From b910b771fde8f1b8c8b4e450ff135d06765a587a Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Thu, 2 Jul 2026 23:29:07 +0200 Subject: [PATCH 01/17] define shared config --- go.mod | 14 + go.sum | 28 ++ internal/pkg/aws/sessions/sessions.go | 10 +- internal/pkg/aws/sessions/sessions_v2.go | 225 ++++++++++++ internal/pkg/aws/sessions/sessions_v2_test.go | 330 ++++++++++++++++++ 5 files changed, 605 insertions(+), 2 deletions(-) create mode 100644 internal/pkg/aws/sessions/sessions_v2.go create mode 100644 internal/pkg/aws/sessions/sessions_v2_test.go diff --git a/go.mod b/go.mod index 8b3b37784fa..4e1399a74ea 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,11 @@ toolchain go1.26.0 require ( github.com/AlecAivazis/survey/v2 v2.3.2 github.com/aws/aws-sdk-go v1.55.5 + github.com/aws/aws-sdk-go-v2 v1.42.1 + github.com/aws/aws-sdk-go-v2/config v1.32.27 + github.com/aws/aws-sdk-go-v2/credentials v1.19.26 + github.com/aws/aws-sdk-go-v2/service/sts v1.43.5 + github.com/aws/smithy-go v1.27.3 github.com/briandowns/spinner v1.23.1 github.com/dustin/go-humanize v1.0.1 github.com/fatih/color v1.17.0 @@ -38,6 +43,15 @@ require ( require ( github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 // indirect github.com/agext/levenshtein v1.2.3 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 // indirect + github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.31.5 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/docker/docker v25.0.6+incompatible // indirect diff --git a/go.sum b/go.sum index 53c6ed194e6..74ed9cafbfc 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,34 @@ github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7l github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= 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-v2 v1.42.1 h1:9eOTgu1z/dVtYpNZ3/8/XbbaX0x/BqE3HUzAzs6K0ek= +github.com/aws/aws-sdk-go-v2 v1.42.1/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM= +github.com/aws/aws-sdk-go-v2/config v1.32.27 h1:SJwJ9Q4kM7v5QVSYYyXj3znRr6lNyZEhSgAXmXXcVbI= +github.com/aws/aws-sdk-go-v2/config v1.32.27/go.mod h1:uBfrzTRedDmB2u+b6+UlaKJy2O6VSH5un2jP24t/KvQ= +github.com/aws/aws-sdk-go-v2/credentials v1.19.26 h1:Si8kk1kyJnuJWCEgiwpBtTdtgSdR7i611596NnC0YIQ= +github.com/aws/aws-sdk-go-v2/credentials v1.19.26/go.mod h1:lBckz+W9SAdNtSDw3pYgQUJDJFcBBWry0GSzw+bK0TY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30 h1:/hi1JADLEW9YYryEz1w4GQu0EtP23pP553Cf9KgsDV4= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30/go.mod h1:/3AOgy4K17Dm4ucMZVC/MJkzy5kmfKUcINRHZyo0koQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 h1:xM/Is9cKMHa8Jj8zkvWhvrFkZsXJV9E+BB4g0HW0duQ= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30/go.mod h1:WueJeNDZvK1fMYEWJIkcivBfEzUkTpBhzlrUKKY8EuA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 h1:jn46zC9LdsVR/ZpMIJqMqb8hHv31BlLx3ulVqNspUOk= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30/go.mod h1:1hTMsAgbdS/AtUi4bw8+gUuh1pceo+eXRLfpSuSQj3M= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 h1:3GUprIsfmGcC5SACIyB0e7E0BM1O1b3Erl5CePYIAeQ= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31/go.mod h1:7PuV1yl5e2xnUbm+RqvVg5i2iBM8EyijZNoI9wsOoOc= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 h1:mbRIur/BiHK6SKPjoBIXSE/hJ6g6JGRLuxQy1jGjlN4= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 h1:/Z5jmNrKsSD7EmDjzAPsm/3L9IuOkzaynklJZ1qX7S4= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30/go.mod h1:lEzEZnOosE7zi8Z6royW1cFJTD9fpab4Ul1SBrllewk= +github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 h1:69JEZSDTQ+UNbTWQJCZMmbpQb5sfc79KUt0O7Pyfjmo= +github.com/aws/aws-sdk-go-v2/service/signin v1.2.2/go.mod h1:mxC0nT/C8wMMS97DemZPzvUZxvIt+2Iq+eS3JdFZGgg= +github.com/aws/aws-sdk-go-v2/service/sso v1.31.5 h1:xlK3Tdc8FO7Tq1k0+hL+otF33glj+dE+qeM5iINiDvU= +github.com/aws/aws-sdk-go-v2/service/sso v1.31.5/go.mod h1:u8af9Nqkmqnr96f7v9nHqzZT9XBwbXEkTiqT4ROuJSE= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8 h1:yX1IbiBfC7SdEgDwIGnRaZyPPDRbQPDOJxl8102PcGk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8/go.mod h1:DMPWJBjYs6+3+f/qhBFEFPPlQ6NlhWjai3dJNvipJ84= +github.com/aws/aws-sdk-go-v2/service/sts v1.43.5 h1:T3ANO8QWDbzQD8f4+UaX+fvJlyGnOFMKLbW+NGBHg04= +github.com/aws/aws-sdk-go-v2/service/sts v1.43.5/go.mod h1:9gdl4RrflIdpDb2TlXshWgR1F9TeCkvqDx77Vpr4Z/Q= +github.com/aws/smithy-go v1.27.3 h1:F3Zb497UhhskkfpJmfkXswyo+t0sh9OTBnIHjogWbVY= +github.com/aws/smithy-go v1.27.3/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/briandowns/spinner v1.23.1 h1:t5fDPmScwUjozhDj4FA46p5acZWIPXYE30qW2Ptu650= github.com/briandowns/spinner v1.23.1/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= diff --git a/internal/pkg/aws/sessions/sessions.go b/internal/pkg/aws/sessions/sessions.go index 8b3dd752fad..b9a4cb184bb 100644 --- a/internal/pkg/aws/sessions/sessions.go +++ b/internal/pkg/aws/sessions/sessions.go @@ -13,6 +13,7 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/version" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws" @@ -38,9 +39,14 @@ const ( type Provider struct { defaultSess *session.Session + defaultConfigV2 awsv2.Config + hasDefaultConfigV2 bool + // Metadata associated with the provider. - userAgentExtras []string - sessionValidator sessionValidator + userAgentExtras []string + sessionValidator sessionValidator + loadV2Config v2ConfigLoader + configV2Validator v2ConfigValidator } type sessionValidator interface { diff --git a/internal/pkg/aws/sessions/sessions_v2.go b/internal/pkg/aws/sessions/sessions_v2.go new file mode 100644 index 00000000000..5257f8a2406 --- /dev/null +++ b/internal/pkg/aws/sessions/sessions_v2.go @@ -0,0 +1,225 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sessions + +import ( + "context" + "errors" + "fmt" + "net/http" + "runtime" + "strings" + + "github.com/aproint/copilot-cli/internal/pkg/version" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/retry" + v2config "github.com/aws/aws-sdk-go-v2/config" + v2credentials "github.com/aws/aws-sdk-go-v2/credentials" + v2stscreds "github.com/aws/aws-sdk-go-v2/credentials/stscreds" + "github.com/aws/aws-sdk-go-v2/service/sts" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" +) + +type v2ConfigLoader func(context.Context, ...func(*v2config.LoadOptions) error) (awsv2.Config, error) + +type v2ConfigValidator interface { + ValidateV2Credentials(context.Context, awsv2.Config) (awsv2.Credentials, error) +} + +// DefaultConfig returns an SDK v2 config configured against the default AWS profile. +// DefaultConfig assumes that a region must be present with the config, otherwise it returns an error. +func (p *Provider) DefaultConfig(ctx context.Context) (awsv2.Config, error) { + cfg, err := p.defaultV2Config(ctx) + if err != nil { + return awsv2.Config{}, err + } + if cfg.Region == "" { + return awsv2.Config{}, &errMissingRegion{} + } + return cfg, nil +} + +// DefaultConfigWithRegion returns an SDK v2 config configured against the default AWS profile and the input region. +func (p *Provider) DefaultConfigWithRegion(ctx context.Context, region string) (awsv2.Config, error) { + return p.v2Loader()(ctx, p.v2LoadOptions(v2config.WithRegion(region))...) +} + +// ConfigFromProfile returns an SDK v2 config configured against the input profile name. +func (p *Provider) ConfigFromProfile(ctx context.Context, name string) (awsv2.Config, error) { + cfg, err := p.v2Loader()(ctx, p.v2LoadOptions(v2config.WithSharedConfigProfile(name))...) + if err != nil { + return awsv2.Config{}, err + } + if cfg.Region == "" { + return awsv2.Config{}, &errMissingRegion{} + } + if _, err := p.v2Validator().ValidateV2Credentials(ctx, cfg); err != nil { + if isCredRetrievalErr(err) { + return awsv2.Config{}, &errCredRetrieval{profile: name, parentErr: err} + } + return awsv2.Config{}, err + } + return cfg, nil +} + +// ConfigFromRole returns an SDK v2 config configured against the input role and region. +func (p *Provider) ConfigFromRole(ctx context.Context, roleARN string, region string) (awsv2.Config, error) { + cfg, err := p.defaultV2Config(ctx) + if err != nil { + return awsv2.Config{}, fmt.Errorf("create default config: %w", err) + } + + cfg.Region = region + cfg.Credentials = awsv2.NewCredentialsCache(v2stscreds.NewAssumeRoleProvider( + sts.NewFromConfig(cfg), + roleARN, + func(o *v2stscreds.AssumeRoleOptions) { + o.TokenProvider = v2stscreds.StdinTokenProvider + }, + )) + return cfg, nil +} + +// ConfigFromStaticCreds returns an SDK v2 config from static credentials. +func (p *Provider) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (awsv2.Config, error) { + return awsv2.Config{ + Credentials: awsv2.NewCredentialsCache(v2credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, sessionToken)), + HTTPClient: newV2HTTPClient(), + Retryer: newV2Retryer, + APIOptions: p.v2APIOptions(), + }, nil +} + +func (p *Provider) defaultV2Config(ctx context.Context) (awsv2.Config, error) { + if p.hasDefaultConfigV2 { + return p.defaultConfigV2, nil + } + + cfg, err := p.v2Loader()(ctx, p.v2LoadOptions()...) + if err != nil { + return awsv2.Config{}, err + } + if _, err = p.v2Validator().ValidateV2Credentials(ctx, cfg); err != nil { + if isCredRetrievalErr(err) { + return awsv2.Config{}, &errCredRetrieval{parentErr: err} + } + return awsv2.Config{}, err + } + + p.defaultConfigV2 = cfg + p.hasDefaultConfigV2 = true + return cfg, nil +} + +func (p *Provider) v2LoadOptions(additional ...func(*v2config.LoadOptions) error) []func(*v2config.LoadOptions) error { + opts := []func(*v2config.LoadOptions) error{ + v2config.WithHTTPClient(newV2HTTPClient()), + v2config.WithRetryer(newV2Retryer), + v2config.WithAssumeRoleCredentialOptions(func(o *v2stscreds.AssumeRoleOptions) { + o.TokenProvider = v2stscreds.StdinTokenProvider + }), + v2config.WithAPIOptions(p.v2APIOptions()), + } + return append(opts, additional...) +} + +func (p *Provider) v2Loader() v2ConfigLoader { + if p.loadV2Config != nil { + return p.loadV2Config + } + return v2config.LoadDefaultConfig +} + +func (p *Provider) v2Validator() v2ConfigValidator { + if p.configV2Validator != nil { + return p.configV2Validator + } + return &v2Validator{} +} + +func newV2HTTPClient() *http.Client { + return &http.Client{ + Timeout: clientTimeout, + } +} + +func newV2Retryer() awsv2.Retryer { + return retry.NewStandard(func(o *retry.StandardOptions) { + o.MaxAttempts = maxRetriesOnRecoverableFailures + }) +} + +func (p *Provider) v2APIOptions() []func(*middleware.Stack) error { + return []func(*middleware.Stack) error{ + addCopilotUserAgent(p), + } +} + +func (p *Provider) userAgentValue() string { + extras := append([]string{runtime.GOOS}, p.userAgentExtras...) + return fmt.Sprintf("%s/%s (%s)", userAgentProductName, version.Version, strings.Join(extras, "; ")) +} + +// AreV2CredsFromEnvVars returns true if the config's credentials provider is environment variables, false otherwise. +// An error is returned if the credentials are invalid or the request times out. +func AreV2CredsFromEnvVars(ctx context.Context, cfg awsv2.Config) (bool, error) { + v, err := V2Creds(ctx, cfg) + if err != nil { + return false, err + } + return v.Source == v2config.CredentialsSourceName, nil +} + +// V2Creds returns the credential values from an SDK v2 config. +func V2Creds(ctx context.Context, cfg awsv2.Config) (awsv2.Credentials, error) { + ctx, cancel := context.WithTimeout(ctx, credsTimeout) + defer cancel() + + if cfg.Credentials == nil { + return awsv2.Credentials{}, errors.New("get credentials of config: missing credentials provider") + } + v, err := cfg.Credentials.Retrieve(ctx) + if err != nil { + return awsv2.Credentials{}, fmt.Errorf("get credentials of config: %w", err) + } + return v, nil +} + +type v2Validator struct{} + +func (v *v2Validator) ValidateV2Credentials(ctx context.Context, cfg awsv2.Config) (awsv2.Credentials, error) { + return V2Creds(ctx, cfg) +} + +type copilotUserAgent struct { + provider *Provider +} + +func addCopilotUserAgent(provider *Provider) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Build.Add(&copilotUserAgent{provider: provider}, middleware.After) + } +} + +func (m *copilotUserAgent) ID() string { + return "CopilotUserAgent" +} + +func (m *copilotUserAgent) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) ( + out middleware.BuildOutput, metadata middleware.Metadata, err error, +) { + req, ok := in.Request.(*smithyhttp.Request) + if !ok { + return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) + } + + value := m.provider.userAgentValue() + if existing := req.Header.Get("User-Agent"); existing != "" { + req.Header.Set("User-Agent", fmt.Sprintf("%s %s", existing, value)) + } else { + req.Header.Set("User-Agent", value) + } + return next.HandleBuild(ctx, in) +} diff --git a/internal/pkg/aws/sessions/sessions_v2_test.go b/internal/pkg/aws/sessions/sessions_v2_test.go new file mode 100644 index 00000000000..40cba08cbcd --- /dev/null +++ b/internal/pkg/aws/sessions/sessions_v2_test.go @@ -0,0 +1,330 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package sessions + +import ( + "context" + "errors" + "net/http" + "testing" + + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + v2config "github.com/aws/aws-sdk-go-v2/config" + v2credentials "github.com/aws/aws-sdk-go-v2/credentials" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" + "github.com/stretchr/testify/require" +) + +type mockV2CredentialsProvider struct { + value awsv2.Credentials + err error +} + +func (m mockV2CredentialsProvider) Retrieve(context.Context) (awsv2.Credentials, error) { + if m.err != nil { + return awsv2.Credentials{}, m.err + } + return m.value, nil +} + +type stubV2Loader struct { + cfg awsv2.Config + err error + calls int + opts v2config.LoadOptions +} + +func (s *stubV2Loader) load(_ context.Context, optFns ...func(*v2config.LoadOptions) error) (awsv2.Config, error) { + s.calls++ + var opts v2config.LoadOptions + for _, fn := range optFns { + if err := fn(&opts); err != nil { + return awsv2.Config{}, err + } + } + s.opts = opts + if s.err != nil { + return awsv2.Config{}, s.err + } + return s.cfg, nil +} + +type stubV2Validator struct { + value awsv2.Credentials + err error + calls int +} + +func (s *stubV2Validator) ValidateV2Credentials(context.Context, awsv2.Config) (awsv2.Credentials, error) { + s.calls++ + if s.err != nil { + return awsv2.Credentials{}, s.err + } + return s.value, nil +} + +func TestProvider_DefaultConfig(t *testing.T) { + t.Run("returns a cached config with v2 defaults applied", func(t *testing.T) { + loader := &stubV2Loader{ + cfg: awsv2.Config{ + Region: "us-west-2", + Credentials: mockV2CredentialsProvider{}, + }, + } + validator := &stubV2Validator{} + provider := &Provider{ + userAgentExtras: []string{"svc deploy"}, + loadV2Config: loader.load, + configV2Validator: validator, + } + + cfg, err := provider.DefaultConfig(context.Background()) + require.NoError(t, err) + require.Equal(t, "us-west-2", cfg.Region) + + cached, err := provider.DefaultConfig(context.Background()) + require.NoError(t, err) + require.Equal(t, cfg, cached) + require.Equal(t, 1, loader.calls) + require.Equal(t, 1, validator.calls) + + httpClient, ok := loader.opts.HTTPClient.(*http.Client) + require.True(t, ok) + require.Equal(t, clientTimeout, httpClient.Timeout) + require.NotNil(t, loader.opts.AssumeRoleCredentialOptions) + require.Len(t, loader.opts.APIOptions, 1) + require.Equal(t, maxRetriesOnRecoverableFailures, loader.opts.Retryer().MaxAttempts()) + }) + + t.Run("returns an error if region is missing", func(t *testing.T) { + loader := &stubV2Loader{ + cfg: awsv2.Config{ + Credentials: mockV2CredentialsProvider{}, + }, + } + provider := &Provider{ + loadV2Config: loader.load, + configV2Validator: &stubV2Validator{}, + } + + cfg, err := provider.DefaultConfig(context.Background()) + require.EqualError(t, err, "missing region configuration") + require.Equal(t, awsv2.Config{}, cfg) + }) + + t.Run("wraps credential retrieval errors", func(t *testing.T) { + loader := &stubV2Loader{ + cfg: awsv2.Config{ + Region: "us-west-2", + Credentials: mockV2CredentialsProvider{}, + }, + } + provider := &Provider{ + loadV2Config: loader.load, + configV2Validator: &stubV2Validator{err: context.DeadlineExceeded}, + } + + cfg, err := provider.DefaultConfig(context.Background()) + require.EqualError(t, err, "context deadline exceeded") + require.Equal(t, awsv2.Config{}, cfg) + var retrievalErr *errCredRetrieval + require.ErrorAs(t, err, &retrievalErr) + }) +} + +func TestProvider_DefaultConfigWithRegion(t *testing.T) { + loader := &stubV2Loader{ + cfg: awsv2.Config{ + Region: "us-west-2", + Credentials: mockV2CredentialsProvider{}, + }, + } + provider := &Provider{loadV2Config: loader.load} + + cfg, err := provider.DefaultConfigWithRegion(context.Background(), "us-west-2") + require.NoError(t, err) + require.Equal(t, "us-west-2", cfg.Region) + require.Equal(t, "us-west-2", loader.opts.Region) +} + +func TestProvider_ConfigFromProfile(t *testing.T) { + t.Run("loads config with profile and validates credentials", func(t *testing.T) { + loader := &stubV2Loader{ + cfg: awsv2.Config{ + Region: "us-west-2", + Credentials: mockV2CredentialsProvider{}, + }, + } + validator := &stubV2Validator{} + provider := &Provider{ + loadV2Config: loader.load, + configV2Validator: validator, + } + + cfg, err := provider.ConfigFromProfile(context.Background(), "prod") + require.NoError(t, err) + require.Equal(t, "us-west-2", cfg.Region) + require.Equal(t, "prod", loader.opts.SharedConfigProfile) + require.Equal(t, 1, validator.calls) + }) + + t.Run("wraps credential retrieval errors with profile context", func(t *testing.T) { + loader := &stubV2Loader{ + cfg: awsv2.Config{ + Region: "us-west-2", + Credentials: mockV2CredentialsProvider{}, + }, + } + provider := &Provider{ + loadV2Config: loader.load, + configV2Validator: &stubV2Validator{err: errors.New("NoCredentialProviders: no valid providers in chain")}, + } + + cfg, err := provider.ConfigFromProfile(context.Background(), "prod") + require.EqualError(t, err, "NoCredentialProviders: no valid providers in chain") + require.Equal(t, awsv2.Config{}, cfg) + var retrievalErr *errCredRetrieval + require.ErrorAs(t, err, &retrievalErr) + require.Equal(t, "prod", retrievalErr.profile) + }) +} + +func TestProvider_ConfigFromStaticCreds(t *testing.T) { + provider := &Provider{} + + cfg, err := provider.ConfigFromStaticCreds("access", "secret", "token") + require.NoError(t, err) + + httpClient, ok := cfg.HTTPClient.(*http.Client) + require.True(t, ok) + require.Equal(t, clientTimeout, httpClient.Timeout) + require.Equal(t, maxRetriesOnRecoverableFailures, cfg.Retryer().MaxAttempts()) + require.Len(t, cfg.APIOptions, 1) + + creds, err := V2Creds(context.Background(), cfg) + require.NoError(t, err) + require.Equal(t, awsv2.Credentials{ + AccessKeyID: "access", + SecretAccessKey: "secret", + SessionToken: "token", + Source: v2credentials.StaticCredentialsName, + }, creds) +} + +func TestV2Creds(t *testing.T) { + t.Run("returns values if provider is valid", func(t *testing.T) { + cfg := awsv2.Config{ + Credentials: mockV2CredentialsProvider{ + value: awsv2.Credentials{ + AccessKeyID: "abc", + SecretAccessKey: "def", + }, + }, + } + + creds, err := V2Creds(context.Background(), cfg) + require.NoError(t, err) + require.Equal(t, awsv2.Credentials{ + AccessKeyID: "abc", + SecretAccessKey: "def", + }, creds) + }) + + t.Run("returns a wrapped error if fetching credentials fails", func(t *testing.T) { + cfg := awsv2.Config{ + Credentials: mockV2CredentialsProvider{err: errors.New("some error")}, + } + + _, err := V2Creds(context.Background(), cfg) + require.EqualError(t, err, "get credentials of config: some error") + }) + + t.Run("returns an error if provider is missing", func(t *testing.T) { + _, err := V2Creds(context.Background(), awsv2.Config{}) + require.EqualError(t, err, "get credentials of config: missing credentials provider") + }) +} + +func TestAreV2CredsFromEnvVars(t *testing.T) { + testCases := map[string]struct { + source string + want bool + }{ + "returns true if credentials come from environment variables": { + source: v2config.CredentialsSourceName, + want: true, + }, + "returns false if credentials do not come from environment variables": { + source: v2credentials.StaticCredentialsName, + want: false, + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + cfg := awsv2.Config{ + Credentials: mockV2CredentialsProvider{ + value: awsv2.Credentials{Source: tc.source}, + }, + } + + ok, err := AreV2CredsFromEnvVars(context.Background(), cfg) + require.NoError(t, err) + require.Equal(t, tc.want, ok) + }) + } +} + +func TestCopilotUserAgent_HandleBuild(t *testing.T) { + provider := &Provider{} + testCases := map[string]struct { + existing string + want string + }{ + "sets the header if missing": { + want: provider.userAgentValue(), + }, + "appends to existing user agent": { + existing: "aws-sdk-go-v2/1.0.0", + want: "aws-sdk-go-v2/1.0.0 " + provider.userAgentValue(), + }, + } + + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + req := &smithyhttp.Request{Request: &http.Request{Header: http.Header{}}} + if tc.existing != "" { + req.Header.Set("User-Agent", tc.existing) + } + ua := &copilotUserAgent{provider: provider} + + _, _, err := ua.HandleBuild(context.Background(), middleware.BuildInput{Request: req}, middleware.BuildHandlerFunc( + func(_ context.Context, in middleware.BuildInput) (middleware.BuildOutput, middleware.Metadata, error) { + return middleware.BuildOutput{Result: in.Request}, middleware.Metadata{}, nil + }, + )) + + require.NoError(t, err) + require.Equal(t, tc.want, req.Header.Get("User-Agent")) + }) + } +} + +func TestCopilotUserAgent_HandleBuildUsesLatestProviderExtras(t *testing.T) { + provider := &Provider{userAgentExtras: []string{"svc deploy"}} + req := &smithyhttp.Request{Request: &http.Request{Header: http.Header{}}} + ua := &copilotUserAgent{provider: provider} + + provider.UserAgentExtras("override cdk") + _, _, err := ua.HandleBuild(context.Background(), middleware.BuildInput{Request: req}, middleware.BuildHandlerFunc( + func(_ context.Context, in middleware.BuildInput) (middleware.BuildOutput, middleware.Metadata, error) { + return middleware.BuildOutput{Result: in.Request}, middleware.Metadata{}, nil + }, + )) + + require.NoError(t, err) + require.Equal(t, provider.userAgentValue(), req.Header.Get("User-Agent")) + require.Contains(t, req.Header.Get("User-Agent"), "svc deploy; override cdk") +} From 559ed3525009945c0562ca4c50af093fd2193f55 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Thu, 2 Jul 2026 23:39:03 +0200 Subject: [PATCH 02/17] chore: regen mocks --- .../pkg/apprunner/mocks/mock_apprunner.go | 12 ++--- internal/pkg/cli/deploy/mocks/mock_env.go | 12 ++--- internal/pkg/cli/mocks/mock_interfaces.go | 46 ++++++++-------- .../mocks/mock_cloudformation.go | 52 +++++++++---------- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/internal/pkg/apprunner/mocks/mock_apprunner.go b/internal/pkg/apprunner/mocks/mock_apprunner.go index 404b9602eb0..fdffaa9e3a4 100644 --- a/internal/pkg/apprunner/mocks/mock_apprunner.go +++ b/internal/pkg/apprunner/mocks/mock_apprunner.go @@ -7,9 +7,9 @@ package mocks import ( reflect "reflect" - apprunner0 "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" + apprunner "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" resourcegroups "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - apprunner "github.com/aws/aws-sdk-go/service/apprunner" + apprunner0 "github.com/aws/aws-sdk-go/service/apprunner" gomock "github.com/golang/mock/gomock" ) @@ -37,10 +37,10 @@ func (m *MockappRunnerClient) EXPECT() *MockappRunnerClientMockRecorder { } // DescribeOperation mocks base method. -func (m *MockappRunnerClient) DescribeOperation(operationId, svcARN string) (*apprunner.OperationSummary, error) { +func (m *MockappRunnerClient) DescribeOperation(operationId, svcARN string) (*apprunner0.OperationSummary, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DescribeOperation", operationId, svcARN) - ret0, _ := ret[0].(*apprunner.OperationSummary) + ret0, _ := ret[0].(*apprunner0.OperationSummary) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -52,10 +52,10 @@ func (mr *MockappRunnerClientMockRecorder) DescribeOperation(operationId, svcARN } // DescribeService mocks base method. -func (m *MockappRunnerClient) DescribeService(svcARN string) (*apprunner0.Service, error) { +func (m *MockappRunnerClient) DescribeService(svcARN string) (*apprunner.Service, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DescribeService", svcARN) - ret0, _ := ret[0].(*apprunner0.Service) + ret0, _ := ret[0].(*apprunner.Service) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/internal/pkg/cli/deploy/mocks/mock_env.go b/internal/pkg/cli/deploy/mocks/mock_env.go index e3f13505b50..f9b6ce710b5 100644 --- a/internal/pkg/cli/deploy/mocks/mock_env.go +++ b/internal/pkg/cli/deploy/mocks/mock_env.go @@ -8,13 +8,13 @@ import ( context "context" reflect "reflect" - cloudformation0 "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" + cloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" elbv2 "github.com/aproint/copilot-cli/internal/pkg/aws/elbv2" config "github.com/aproint/copilot-cli/internal/pkg/config" - cloudformation1 "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" + cloudformation0 "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" stack "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" stack0 "github.com/aproint/copilot-cli/internal/pkg/describe/stack" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation1 "github.com/aws/aws-sdk-go/service/cloudformation" gomock "github.com/golang/mock/gomock" ) @@ -203,10 +203,10 @@ func (m *MockenvironmentDeployer) EXPECT() *MockenvironmentDeployerMockRecorder } // DeployedEnvironmentParameters mocks base method. -func (m *MockenvironmentDeployer) DeployedEnvironmentParameters(app, env string) ([]*cloudformation.Parameter, error) { +func (m *MockenvironmentDeployer) DeployedEnvironmentParameters(app, env string) ([]*cloudformation1.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeployedEnvironmentParameters", app, env) - ret0, _ := ret[0].([]*cloudformation.Parameter) + ret0, _ := ret[0].([]*cloudformation1.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -233,7 +233,7 @@ func (mr *MockenvironmentDeployerMockRecorder) ForceUpdateOutputID(app, env inte } // UpdateAndRenderEnvironment mocks base method. -func (m *MockenvironmentDeployer) UpdateAndRenderEnvironment(conf cloudformation1.StackConfiguration, bucketARN string, detach bool, opts ...cloudformation0.StackOption) error { +func (m *MockenvironmentDeployer) UpdateAndRenderEnvironment(conf cloudformation0.StackConfiguration, bucketARN string, detach bool, opts ...cloudformation.StackOption) error { m.ctrl.T.Helper() varargs := []interface{}{conf, bucketARN, detach} for _, a := range opts { diff --git a/internal/pkg/cli/mocks/mock_interfaces.go b/internal/pkg/cli/mocks/mock_interfaces.go index 89982b481cb..4be119ba842 100644 --- a/internal/pkg/cli/mocks/mock_interfaces.go +++ b/internal/pkg/cli/mocks/mock_interfaces.go @@ -10,7 +10,7 @@ import ( io "io" reflect "reflect" - cloudformation0 "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" + cloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" codepipeline "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" ec2 "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" ecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -19,7 +19,7 @@ import ( deploy "github.com/aproint/copilot-cli/internal/pkg/cli/deploy" config "github.com/aproint/copilot-cli/internal/pkg/config" deploy0 "github.com/aproint/copilot-cli/internal/pkg/deploy" - cloudformation1 "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" + cloudformation0 "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" stack "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" describe "github.com/aproint/copilot-cli/internal/pkg/describe" stack0 "github.com/aproint/copilot-cli/internal/pkg/describe/stack" @@ -36,7 +36,7 @@ import ( selector "github.com/aproint/copilot-cli/internal/pkg/term/selector" workspace "github.com/aproint/copilot-cli/internal/pkg/workspace" session "github.com/aws/aws-sdk-go/aws/session" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation1 "github.com/aws/aws-sdk-go/service/cloudformation" gomock "github.com/golang/mock/gomock" ) @@ -3960,7 +3960,7 @@ func (m *MockenvironmentDeployer) EXPECT() *MockenvironmentDeployerMockRecorder } // CreateAndRenderEnvironment mocks base method. -func (m *MockenvironmentDeployer) CreateAndRenderEnvironment(conf cloudformation1.StackConfiguration, bucketARN string) error { +func (m *MockenvironmentDeployer) CreateAndRenderEnvironment(conf cloudformation0.StackConfiguration, bucketARN string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateAndRenderEnvironment", conf, bucketARN) ret0, _ := ret[0].(error) @@ -4217,7 +4217,7 @@ func (mr *MockpipelineDeployerMockRecorder) AddPipelineResourcesToApp(app, regio } // CreatePipeline mocks base method. -func (m *MockpipelineDeployer) CreatePipeline(bucketName string, stackConfig cloudformation1.StackConfiguration) error { +func (m *MockpipelineDeployer) CreatePipeline(bucketName string, stackConfig cloudformation0.StackConfiguration) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreatePipeline", bucketName, stackConfig) ret0, _ := ret[0].(error) @@ -4275,7 +4275,7 @@ func (mr *MockpipelineDeployerMockRecorder) GetRegionalAppResources(app interfac } // PipelineExists mocks base method. -func (m *MockpipelineDeployer) PipelineExists(stackConfig cloudformation1.StackConfiguration) (bool, error) { +func (m *MockpipelineDeployer) PipelineExists(stackConfig cloudformation0.StackConfiguration) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PipelineExists", stackConfig) ret0, _ := ret[0].(bool) @@ -4305,7 +4305,7 @@ func (mr *MockpipelineDeployerMockRecorder) Template(stackName interface{}) *gom } // UpdatePipeline mocks base method. -func (m *MockpipelineDeployer) UpdatePipeline(bucketName string, stackConfig cloudformation1.StackConfiguration) error { +func (m *MockpipelineDeployer) UpdatePipeline(bucketName string, stackConfig cloudformation0.StackConfiguration) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdatePipeline", bucketName, stackConfig) ret0, _ := ret[0].(error) @@ -4342,7 +4342,7 @@ func (m *MockappDeployer) EXPECT() *MockappDeployerMockRecorder { } // AddEnvToApp mocks base method. -func (m *MockappDeployer) AddEnvToApp(opts *cloudformation1.AddEnvToAppOpts) error { +func (m *MockappDeployer) AddEnvToApp(opts *cloudformation0.AddEnvToAppOpts) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddEnvToApp", opts) ret0, _ := ret[0].(error) @@ -4356,7 +4356,7 @@ func (mr *MockappDeployerMockRecorder) AddEnvToApp(opts interface{}) *gomock.Cal } // AddJobToApp mocks base method. -func (m *MockappDeployer) AddJobToApp(app *config.Application, jobName string, opts ...cloudformation1.AddWorkloadToAppOpt) error { +func (m *MockappDeployer) AddJobToApp(app *config.Application, jobName string, opts ...cloudformation0.AddWorkloadToAppOpt) error { m.ctrl.T.Helper() varargs := []interface{}{app, jobName} for _, a := range opts { @@ -4375,7 +4375,7 @@ func (mr *MockappDeployerMockRecorder) AddJobToApp(app, jobName interface{}, opt } // AddServiceToApp mocks base method. -func (m *MockappDeployer) AddServiceToApp(app *config.Application, svcName string, opts ...cloudformation1.AddWorkloadToAppOpt) error { +func (m *MockappDeployer) AddServiceToApp(app *config.Application, svcName string, opts ...cloudformation0.AddWorkloadToAppOpt) error { m.ctrl.T.Helper() varargs := []interface{}{app, svcName} for _, a := range opts { @@ -4542,7 +4542,7 @@ func (mr *MockenvDeleterFromAppMockRecorder) GetRegionalAppResources(app interfa } // RemoveEnvFromApp mocks base method. -func (m *MockenvDeleterFromApp) RemoveEnvFromApp(opts *cloudformation1.RemoveEnvFromAppOpts) error { +func (m *MockenvDeleterFromApp) RemoveEnvFromApp(opts *cloudformation0.RemoveEnvFromAppOpts) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RemoveEnvFromApp", opts) ret0, _ := ret[0].(error) @@ -4579,7 +4579,7 @@ func (m *MocktaskDeployer) EXPECT() *MocktaskDeployerMockRecorder { } // DeployTask mocks base method. -func (m *MocktaskDeployer) DeployTask(input *deploy0.CreateTaskResourcesInput, opts ...cloudformation0.StackOption) error { +func (m *MocktaskDeployer) DeployTask(input *deploy0.CreateTaskResourcesInput, opts ...cloudformation.StackOption) error { m.ctrl.T.Helper() varargs := []interface{}{input} for _, a := range opts { @@ -4778,7 +4778,7 @@ func (m *Mockdeployer) EXPECT() *MockdeployerMockRecorder { } // AddEnvToApp mocks base method. -func (m *Mockdeployer) AddEnvToApp(opts *cloudformation1.AddEnvToAppOpts) error { +func (m *Mockdeployer) AddEnvToApp(opts *cloudformation0.AddEnvToAppOpts) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "AddEnvToApp", opts) ret0, _ := ret[0].(error) @@ -4792,7 +4792,7 @@ func (mr *MockdeployerMockRecorder) AddEnvToApp(opts interface{}) *gomock.Call { } // AddJobToApp mocks base method. -func (m *Mockdeployer) AddJobToApp(app *config.Application, jobName string, opts ...cloudformation1.AddWorkloadToAppOpt) error { +func (m *Mockdeployer) AddJobToApp(app *config.Application, jobName string, opts ...cloudformation0.AddWorkloadToAppOpt) error { m.ctrl.T.Helper() varargs := []interface{}{app, jobName} for _, a := range opts { @@ -4825,7 +4825,7 @@ func (mr *MockdeployerMockRecorder) AddPipelineResourcesToApp(app, region interf } // AddServiceToApp mocks base method. -func (m *Mockdeployer) AddServiceToApp(app *config.Application, svcName string, opts ...cloudformation1.AddWorkloadToAppOpt) error { +func (m *Mockdeployer) AddServiceToApp(app *config.Application, svcName string, opts ...cloudformation0.AddWorkloadToAppOpt) error { m.ctrl.T.Helper() varargs := []interface{}{app, svcName} for _, a := range opts { @@ -4844,7 +4844,7 @@ func (mr *MockdeployerMockRecorder) AddServiceToApp(app, svcName interface{}, op } // CreateAndRenderEnvironment mocks base method. -func (m *Mockdeployer) CreateAndRenderEnvironment(conf cloudformation1.StackConfiguration, bucketARN string) error { +func (m *Mockdeployer) CreateAndRenderEnvironment(conf cloudformation0.StackConfiguration, bucketARN string) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateAndRenderEnvironment", conf, bucketARN) ret0, _ := ret[0].(error) @@ -4858,7 +4858,7 @@ func (mr *MockdeployerMockRecorder) CreateAndRenderEnvironment(conf, bucketARN i } // CreatePipeline mocks base method. -func (m *Mockdeployer) CreatePipeline(bucketName string, stackConfig cloudformation1.StackConfiguration) error { +func (m *Mockdeployer) CreatePipeline(bucketName string, stackConfig cloudformation0.StackConfiguration) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreatePipeline", bucketName, stackConfig) ret0, _ := ret[0].(error) @@ -5002,7 +5002,7 @@ func (mr *MockdeployerMockRecorder) ListTaskStacks(appName, envName interface{}) } // PipelineExists mocks base method. -func (m *Mockdeployer) PipelineExists(stackConfig cloudformation1.StackConfiguration) (bool, error) { +func (m *Mockdeployer) PipelineExists(stackConfig cloudformation0.StackConfiguration) (bool, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "PipelineExists", stackConfig) ret0, _ := ret[0].(bool) @@ -5046,7 +5046,7 @@ func (mr *MockdeployerMockRecorder) UpdateEnvironmentTemplate(appName, envName, } // UpdatePipeline mocks base method. -func (m *Mockdeployer) UpdatePipeline(bucketName string, stackConfig cloudformation1.StackConfiguration) error { +func (m *Mockdeployer) UpdatePipeline(bucketName string, stackConfig cloudformation0.StackConfiguration) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdatePipeline", bucketName, stackConfig) ret0, _ := ret[0].(error) @@ -8136,10 +8136,10 @@ func (m *MockstackConfiguration) EXPECT() *MockstackConfigurationMockRecorder { } // Parameters mocks base method. -func (m *MockstackConfiguration) Parameters() ([]*cloudformation.Parameter, error) { +func (m *MockstackConfiguration) Parameters() ([]*cloudformation1.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Parameters") - ret0, _ := ret[0].([]*cloudformation.Parameter) + ret0, _ := ret[0].([]*cloudformation1.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -8180,10 +8180,10 @@ func (mr *MockstackConfigurationMockRecorder) StackName() *gomock.Call { } // Tags mocks base method. -func (m *MockstackConfiguration) Tags() []*cloudformation.Tag { +func (m *MockstackConfiguration) Tags() []*cloudformation1.Tag { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Tags") - ret0, _ := ret[0].([]*cloudformation.Tag) + ret0, _ := ret[0].([]*cloudformation1.Tag) return ret0 } diff --git a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go index a3922ae3ed3..7aee7d59b7d 100644 --- a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go +++ b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go @@ -9,11 +9,11 @@ import ( io "io" reflect "reflect" - cloudformation0 "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" + cloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" stackset "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation/stackset" cloudwatch "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" ecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation0 "github.com/aws/aws-sdk-go/service/cloudformation" gomock "github.com/golang/mock/gomock" ) @@ -41,10 +41,10 @@ func (m *MockStackConfiguration) EXPECT() *MockStackConfigurationMockRecorder { } // Parameters mocks base method. -func (m *MockStackConfiguration) Parameters() ([]*cloudformation.Parameter, error) { +func (m *MockStackConfiguration) Parameters() ([]*cloudformation0.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Parameters") - ret0, _ := ret[0].([]*cloudformation.Parameter) + ret0, _ := ret[0].([]*cloudformation0.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -85,10 +85,10 @@ func (mr *MockStackConfigurationMockRecorder) StackName() *gomock.Call { } // Tags mocks base method. -func (m *MockStackConfiguration) Tags() []*cloudformation.Tag { +func (m *MockStackConfiguration) Tags() []*cloudformation0.Tag { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Tags") - ret0, _ := ret[0].([]*cloudformation.Tag) + ret0, _ := ret[0].([]*cloudformation0.Tag) return ret0 } @@ -284,7 +284,7 @@ func (mr *MockcfnClientMockRecorder) CancelUpdateStack(stackName interface{}) *g } // Create mocks base method. -func (m *MockcfnClient) Create(arg0 *cloudformation0.Stack) (string, error) { +func (m *MockcfnClient) Create(arg0 *cloudformation.Stack) (string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Create", arg0) ret0, _ := ret[0].(string) @@ -299,7 +299,7 @@ func (mr *MockcfnClientMockRecorder) Create(arg0 interface{}) *gomock.Call { } // CreateAndWait mocks base method. -func (m *MockcfnClient) CreateAndWait(arg0 *cloudformation0.Stack) error { +func (m *MockcfnClient) CreateAndWait(arg0 *cloudformation.Stack) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "CreateAndWait", arg0) ret0, _ := ret[0].(error) @@ -355,10 +355,10 @@ func (mr *MockcfnClientMockRecorder) DeleteAndWaitWithRoleARN(stackName, roleARN } // Describe mocks base method. -func (m *MockcfnClient) Describe(stackName string) (*cloudformation0.StackDescription, error) { +func (m *MockcfnClient) Describe(stackName string) (*cloudformation.StackDescription, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Describe", stackName) - ret0, _ := ret[0].(*cloudformation0.StackDescription) + ret0, _ := ret[0].(*cloudformation.StackDescription) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -370,10 +370,10 @@ func (mr *MockcfnClientMockRecorder) Describe(stackName interface{}) *gomock.Cal } // DescribeChangeSet mocks base method. -func (m *MockcfnClient) DescribeChangeSet(changeSetID, stackName string) (*cloudformation0.ChangeSetDescription, error) { +func (m *MockcfnClient) DescribeChangeSet(changeSetID, stackName string) (*cloudformation.ChangeSetDescription, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DescribeChangeSet", changeSetID, stackName) - ret0, _ := ret[0].(*cloudformation0.ChangeSetDescription) + ret0, _ := ret[0].(*cloudformation.ChangeSetDescription) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -385,10 +385,10 @@ func (mr *MockcfnClientMockRecorder) DescribeChangeSet(changeSetID, stackName in } // DescribeStackEvents mocks base method. -func (m *MockcfnClient) DescribeStackEvents(arg0 *cloudformation.DescribeStackEventsInput) (*cloudformation.DescribeStackEventsOutput, error) { +func (m *MockcfnClient) DescribeStackEvents(arg0 *cloudformation0.DescribeStackEventsInput) (*cloudformation0.DescribeStackEventsOutput, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DescribeStackEvents", arg0) - ret0, _ := ret[0].(*cloudformation.DescribeStackEventsOutput) + ret0, _ := ret[0].(*cloudformation0.DescribeStackEventsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -400,10 +400,10 @@ func (mr *MockcfnClientMockRecorder) DescribeStackEvents(arg0 interface{}) *gomo } // ErrorEvents mocks base method. -func (m *MockcfnClient) ErrorEvents(stackName string) ([]cloudformation0.StackEvent, error) { +func (m *MockcfnClient) ErrorEvents(stackName string) ([]cloudformation.StackEvent, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ErrorEvents", stackName) - ret0, _ := ret[0].([]cloudformation0.StackEvent) + ret0, _ := ret[0].([]cloudformation.StackEvent) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -415,10 +415,10 @@ func (mr *MockcfnClientMockRecorder) ErrorEvents(stackName interface{}) *gomock. } // Events mocks base method. -func (m *MockcfnClient) Events(stackName string) ([]cloudformation0.StackEvent, error) { +func (m *MockcfnClient) Events(stackName string) ([]cloudformation.StackEvent, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Events", stackName) - ret0, _ := ret[0].([]cloudformation0.StackEvent) + ret0, _ := ret[0].([]cloudformation.StackEvent) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -430,10 +430,10 @@ func (mr *MockcfnClientMockRecorder) Events(stackName interface{}) *gomock.Call } // ListStacksWithTags mocks base method. -func (m *MockcfnClient) ListStacksWithTags(tags map[string]string) ([]cloudformation0.StackDescription, error) { +func (m *MockcfnClient) ListStacksWithTags(tags map[string]string) ([]cloudformation.StackDescription, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ListStacksWithTags", tags) - ret0, _ := ret[0].([]cloudformation0.StackDescription) + ret0, _ := ret[0].([]cloudformation.StackDescription) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -445,7 +445,7 @@ func (mr *MockcfnClientMockRecorder) ListStacksWithTags(tags interface{}) *gomoc } // Metadata mocks base method. -func (m *MockcfnClient) Metadata(opts cloudformation0.MetadataOpts) (string, error) { +func (m *MockcfnClient) Metadata(opts cloudformation.MetadataOpts) (string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Metadata", opts) ret0, _ := ret[0].(string) @@ -460,7 +460,7 @@ func (mr *MockcfnClientMockRecorder) Metadata(opts interface{}) *gomock.Call { } // Outputs mocks base method. -func (m *MockcfnClient) Outputs(stack *cloudformation0.Stack) (map[string]string, error) { +func (m *MockcfnClient) Outputs(stack *cloudformation.Stack) (map[string]string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Outputs", stack) ret0, _ := ret[0].(map[string]string) @@ -475,10 +475,10 @@ func (mr *MockcfnClientMockRecorder) Outputs(stack interface{}) *gomock.Call { } // StackResources mocks base method. -func (m *MockcfnClient) StackResources(name string) ([]*cloudformation0.StackResource, error) { +func (m *MockcfnClient) StackResources(name string) ([]*cloudformation.StackResource, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StackResources", name) - ret0, _ := ret[0].([]*cloudformation0.StackResource) + ret0, _ := ret[0].([]*cloudformation.StackResource) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -520,7 +520,7 @@ func (mr *MockcfnClientMockRecorder) TemplateBodyFromChangeSet(changeSetID, stac } // Update mocks base method. -func (m *MockcfnClient) Update(arg0 *cloudformation0.Stack) (string, error) { +func (m *MockcfnClient) Update(arg0 *cloudformation.Stack) (string, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Update", arg0) ret0, _ := ret[0].(string) @@ -535,7 +535,7 @@ func (mr *MockcfnClientMockRecorder) Update(arg0 interface{}) *gomock.Call { } // UpdateAndWait mocks base method. -func (m *MockcfnClient) UpdateAndWait(arg0 *cloudformation0.Stack) error { +func (m *MockcfnClient) UpdateAndWait(arg0 *cloudformation.Stack) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateAndWait", arg0) ret0, _ := ret[0].(error) From 29c7a36c92099274b98dd46db1dff7e8fffade3a Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Thu, 2 Jul 2026 23:47:41 +0200 Subject: [PATCH 03/17] chore: disable binsize --- .github/workflows/ci_size_computer.yml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/ci_size_computer.yml b/.github/workflows/ci_size_computer.yml index 2ca946892e0..97e0770df0c 100644 --- a/.github/workflows/ci_size_computer.yml +++ b/.github/workflows/ci_size_computer.yml @@ -1,11 +1,7 @@ name: Compute bin sizes on: - pull_request: - types: - - opened - - edited - - synchronize + workflow_dispatch: jobs: binsize: From 656ee89cf987a6fed72bb58c242956adca30254b Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Fri, 3 Jul 2026 09:21:24 +0200 Subject: [PATCH 04/17] migrate first set of wrappers --- go.mod | 5 + go.sum | 10 + internal/pkg/apprunner/apprunner.go | 5 +- internal/pkg/aws/cloudwatch/cloudwatch.go | 7 +- internal/pkg/aws/codepipeline/codepipeline.go | 7 +- internal/pkg/aws/codestar/codestar.go | 26 +- internal/pkg/aws/codestar/codestar_test.go | 69 ++--- .../pkg/aws/codestar/mocks/mock_codestar.go | 29 +- internal/pkg/aws/identity/identity.go | 26 +- internal/pkg/aws/identity/identity_test.go | 29 +- .../pkg/aws/identity/mocks/mock_identity.go | 16 +- .../mocks/mock_resourcegroups.go | 16 +- .../pkg/aws/resourcegroups/resourcegroups.go | 36 +-- .../aws/resourcegroups/resourcegroups_test.go | 55 ++-- .../mocks/mock_secretsmanager.go | 54 ++-- .../pkg/aws/secretsmanager/secretsmanager.go | 84 +++--- .../aws/secretsmanager/secretsmanager_test.go | 90 +++--- internal/pkg/aws/ssm/mocks/mock_ssm.go | 41 +-- internal/pkg/aws/ssm/ssm.go | 74 +++-- internal/pkg/aws/ssm/ssm_test.go | 266 +++++++++--------- .../stepfunctions/mocks/mock_stepfunctions.go | 29 +- .../pkg/aws/stepfunctions/stepfunctions.go | 28 +- .../aws/stepfunctions/stepfunctions_test.go | 24 +- internal/pkg/cli/app_delete.go | 11 +- internal/pkg/cli/app_init.go | 3 +- internal/pkg/cli/app_list.go | 12 +- internal/pkg/cli/app_show.go | 12 +- internal/pkg/cli/app_upgrade.go | 11 +- internal/pkg/cli/config_store.go | 27 ++ internal/pkg/cli/deploy.go | 7 +- internal/pkg/cli/deploy/aws_config.go | 15 + internal/pkg/cli/deploy/backend.go | 2 +- internal/pkg/cli/deploy/lbws.go | 2 +- internal/pkg/cli/deploy/rdws.go | 4 +- internal/pkg/cli/deploy/worker.go | 2 +- internal/pkg/cli/deploy/workload.go | 6 +- internal/pkg/cli/env_delete.go | 11 +- internal/pkg/cli/env_deploy.go | 9 +- internal/pkg/cli/env_init.go | 11 +- internal/pkg/cli/env_list.go | 8 +- internal/pkg/cli/env_override.go | 9 +- internal/pkg/cli/env_package.go | 10 +- internal/pkg/cli/env_show.go | 9 +- internal/pkg/cli/init.go | 8 +- internal/pkg/cli/interfaces.go | 3 + internal/pkg/cli/job_delete.go | 11 +- internal/pkg/cli/job_deploy.go | 9 +- internal/pkg/cli/job_init.go | 8 +- internal/pkg/cli/job_list.go | 7 +- internal/pkg/cli/job_logs.go | 8 +- internal/pkg/cli/job_package.go | 9 +- internal/pkg/cli/job_run.go | 10 +- internal/pkg/cli/mocks/mock_interfaces.go | 61 ++++ internal/pkg/cli/pipeline_delete.go | 15 +- internal/pkg/cli/pipeline_delete_test.go | 6 +- internal/pkg/cli/pipeline_deploy.go | 12 +- internal/pkg/cli/pipeline_init.go | 12 +- internal/pkg/cli/pipeline_list.go | 12 +- internal/pkg/cli/pipeline_override.go | 10 +- internal/pkg/cli/pipeline_package.go | 11 +- internal/pkg/cli/pipeline_show.go | 15 +- internal/pkg/cli/pipeline_status.go | 15 +- internal/pkg/cli/run_local.go | 24 +- internal/pkg/cli/secret_init.go | 17 +- internal/pkg/cli/secret_init_test.go | 16 +- internal/pkg/cli/storage_init.go | 9 +- internal/pkg/cli/svc_delete.go | 10 +- internal/pkg/cli/svc_deploy.go | 9 +- internal/pkg/cli/svc_exec.go | 10 +- internal/pkg/cli/svc_init.go | 7 +- internal/pkg/cli/svc_list.go | 9 +- internal/pkg/cli/svc_logs.go | 15 +- internal/pkg/cli/svc_override.go | 9 +- internal/pkg/cli/svc_package.go | 9 +- internal/pkg/cli/svc_pause.go | 8 +- internal/pkg/cli/svc_resume.go | 9 +- internal/pkg/cli/svc_show.go | 8 +- internal/pkg/cli/svc_status.go | 9 +- internal/pkg/cli/task_delete.go | 11 +- internal/pkg/cli/task_exec.go | 11 +- internal/pkg/cli/task_run.go | 15 +- .../deploy/cloudformation/cloudformation.go | 8 +- internal/pkg/deploy/deploy.go | 17 +- internal/pkg/deploy/mocks/mock_deploy.go | 17 +- internal/pkg/describe/aws_config.go | 15 + internal/pkg/describe/backend_service.go | 2 +- internal/pkg/describe/lb_web_service.go | 2 +- internal/pkg/describe/pipeline_show.go | 2 +- internal/pkg/describe/pipeline_status.go | 2 +- internal/pkg/describe/service.go | 2 +- internal/pkg/describe/static_site.go | 2 +- internal/pkg/describe/status_describe.go | 6 +- internal/pkg/describe/worker_service.go | 2 +- internal/pkg/ecs/ecs.go | 15 +- internal/pkg/s3/s3.go | 5 +- 95 files changed, 991 insertions(+), 770 deletions(-) create mode 100644 internal/pkg/cli/config_store.go create mode 100644 internal/pkg/cli/deploy/aws_config.go create mode 100644 internal/pkg/describe/aws_config.go diff --git a/go.mod b/go.mod index 4e1399a74ea..9719dce0796 100644 --- a/go.mod +++ b/go.mod @@ -47,9 +47,14 @@ require ( github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 // indirect + github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 // indirect + github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5 // indirect + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5 // indirect + github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 // indirect + github.com/aws/aws-sdk-go-v2/service/ssm v1.69.5 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.31.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect diff --git a/go.sum b/go.sum index 74ed9cafbfc..b1782c1e5ea 100644 --- a/go.sum +++ b/go.sum @@ -21,12 +21,22 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 h1:jn46zC9LdsVR/ZpMIJ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30/go.mod h1:1hTMsAgbdS/AtUi4bw8+gUuh1pceo+eXRLfpSuSQj3M= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 h1:3GUprIsfmGcC5SACIyB0e7E0BM1O1b3Erl5CePYIAeQ= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31/go.mod h1:7PuV1yl5e2xnUbm+RqvVg5i2iBM8EyijZNoI9wsOoOc= +github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7 h1:6Z1SAXPMgG3SmbDoDQ2erFygJ7vA2W349Ru3UzNjRWM= +github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7/go.mod h1:tvsbZAxIY9hRwspsZURZ34tYiMGm2gnyAc++5M0G3i0= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 h1:mbRIur/BiHK6SKPjoBIXSE/hJ6g6JGRLuxQy1jGjlN4= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 h1:/Z5jmNrKsSD7EmDjzAPsm/3L9IuOkzaynklJZ1qX7S4= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30/go.mod h1:lEzEZnOosE7zi8Z6royW1cFJTD9fpab4Ul1SBrllewk= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5 h1:cd2vmT/Cc9/ZzmuY0XM2YKA5tgkp2Jyv5Ia35ENsW5I= +github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5/go.mod h1:1N13ke5qTtwOiBPXfPtH+MmG5Jo0UAfKnp+OZ2bQahI= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5 h1:CWn32XhRKVJQlCpU5T1PpspYbgUisB+Ke1w7NR4AHZw= +github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5/go.mod h1:oUyL28WfxY0RqPhFpkrWZx26Cu4JlyrWMMcWq8qqhi0= +github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2 h1:DN64QFK4wW3/Fnzn5Wj1ztuzG2Smv4Oc8TJxVcmQ5E0= +github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2/go.mod h1:rSGTfHDlX6qAZG6eJ5p81Z1vXTnV65ejnIYW6G2/PHo= github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 h1:69JEZSDTQ+UNbTWQJCZMmbpQb5sfc79KUt0O7Pyfjmo= github.com/aws/aws-sdk-go-v2/service/signin v1.2.2/go.mod h1:mxC0nT/C8wMMS97DemZPzvUZxvIt+2Iq+eS3JdFZGgg= +github.com/aws/aws-sdk-go-v2/service/ssm v1.69.5 h1:fCaC9yP7sthItdHF8VBT3qR42jK1R4g+5IoSvePys7o= +github.com/aws/aws-sdk-go-v2/service/ssm v1.69.5/go.mod h1:xabzRvdbMs3FG9kU5M6RUOuCW6wXDkpdIqoXXNzA1nQ= github.com/aws/aws-sdk-go-v2/service/sso v1.31.5 h1:xlK3Tdc8FO7Tq1k0+hL+otF33glj+dE+qeM5iINiDvU= github.com/aws/aws-sdk-go-v2/service/sso v1.31.5/go.mod h1:u8af9Nqkmqnr96f7v9nHqzZT9XBwbXEkTiqT4ROuJSE= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8 h1:yX1IbiBfC7SdEgDwIGnRaZyPPDRbQPDOJxl8102PcGk= diff --git a/internal/pkg/apprunner/apprunner.go b/internal/pkg/apprunner/apprunner.go index 9022ebfde36..a363098934c 100644 --- a/internal/pkg/apprunner/apprunner.go +++ b/internal/pkg/apprunner/apprunner.go @@ -11,6 +11,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/session" awsapprunner "github.com/aws/aws-sdk-go/service/apprunner" ) @@ -37,9 +38,9 @@ type Client struct { } // New inits a new Client. -func New(sess *session.Session) *Client { +func New(sess *session.Session, rgConfig awsv2.Config) *Client { return &Client{ - rgGetter: resourcegroups.New(sess), + rgGetter: resourcegroups.New(rgConfig), appRunnerClient: apprunner.New(sess), } } diff --git a/internal/pkg/aws/cloudwatch/cloudwatch.go b/internal/pkg/aws/cloudwatch/cloudwatch.go index 84bb5e047f8..aa46ff0b94c 100644 --- a/internal/pkg/aws/cloudwatch/cloudwatch.go +++ b/internal/pkg/aws/cloudwatch/cloudwatch.go @@ -11,6 +11,7 @@ import ( rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/session" @@ -59,11 +60,11 @@ type AlarmDescription struct { Environment string `json:"environment"` } -// New returns a CloudWatch struct configured against the input session. -func New(s *session.Session) *CloudWatch { +// New returns a CloudWatch struct configured against the input session and SDK v2 Resource Groups config. +func New(s *session.Session, rgConfig awsv2.Config) *CloudWatch { return &CloudWatch{ client: cloudwatch.New(s), - rgClient: rg.New(s), + rgClient: rg.New(rgConfig), } } diff --git a/internal/pkg/aws/codepipeline/codepipeline.go b/internal/pkg/aws/codepipeline/codepipeline.go index 1fe2ba417db..5f836841080 100644 --- a/internal/pkg/aws/codepipeline/codepipeline.go +++ b/internal/pkg/aws/codepipeline/codepipeline.go @@ -13,6 +13,7 @@ import ( rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/term/color" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/session" @@ -101,11 +102,11 @@ func (ss StageState) AggregateStatus() string { return "" } -// New returns a CodePipeline client configured against the input session. -func New(s *session.Session) *CodePipeline { +// New returns a CodePipeline client configured against the input session and SDK v2 Resource Groups config. +func New(s *session.Session, rgConfig awsv2.Config) *CodePipeline { return &CodePipeline{ client: cp.New(s), - rgClient: rg.New(s), + rgClient: rg.New(rgConfig), } } diff --git a/internal/pkg/aws/codestar/codestar.go b/internal/pkg/aws/codestar/codestar.go index ccad8dd76c5..e80b12e9f47 100644 --- a/internal/pkg/aws/codestar/codestar.go +++ b/internal/pkg/aws/codestar/codestar.go @@ -9,14 +9,14 @@ import ( "fmt" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/codestarconnections" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/codestarconnections" + "github.com/aws/aws-sdk-go-v2/service/codestarconnections/types" ) type api interface { - GetConnection(input *codestarconnections.GetConnectionInput) (*codestarconnections.GetConnectionOutput, error) - ListConnections(input *codestarconnections.ListConnectionsInput) (*codestarconnections.ListConnectionsOutput, error) + GetConnection(ctx context.Context, input *codestarconnections.GetConnectionInput, opts ...func(*codestarconnections.Options)) (*codestarconnections.GetConnectionOutput, error) + ListConnections(ctx context.Context, input *codestarconnections.ListConnectionsInput, opts ...func(*codestarconnections.Options)) (*codestarconnections.ListConnectionsOutput, error) } // CodeStar represents a client to make requests to AWS CodeStarConnections. @@ -25,9 +25,9 @@ type CodeStar struct { } // New creates a new CodeStar client. -func New(s *session.Session) *CodeStar { +func New(cfg awsv2.Config) *CodeStar { return &CodeStar{ - codestarconnections.New(s), + codestarconnections.NewFromConfig(cfg), } } @@ -39,11 +39,11 @@ func (c *CodeStar) WaitUntilConnectionStatusAvailable(ctx context.Context, conne case <-ctx.Done(): return fmt.Errorf("timed out waiting for connection %s status to change from PENDING to AVAILABLE", connectionARN) case <-time.After(interval): - output, err := c.client.GetConnection(&codestarconnections.GetConnectionInput{ConnectionArn: aws.String(connectionARN)}) + output, err := c.client.GetConnection(ctx, &codestarconnections.GetConnectionInput{ConnectionArn: awsv2.String(connectionARN)}) if err != nil { return fmt.Errorf("get connection details for %s: %w", connectionARN, err) } - if aws.StringValue(output.Connection.ConnectionStatus) == codestarconnections.ConnectionStatusAvailable { + if output.Connection.ConnectionStatus == types.ConnectionStatusAvailable { return nil } interval = 5 * time.Second @@ -54,13 +54,13 @@ func (c *CodeStar) WaitUntilConnectionStatusAvailable(ctx context.Context, conne // GetConnectionARN retrieves all of the CSC connections in the current account and returns the ARN correlating to the // connection name passed in. func (c *CodeStar) GetConnectionARN(connectionName string) (connectionARN string, err error) { - output, err := c.client.ListConnections(&codestarconnections.ListConnectionsInput{}) + output, err := c.client.ListConnections(context.Background(), &codestarconnections.ListConnectionsInput{}) if err != nil { return "", fmt.Errorf("get list of connections in AWS account: %w", err) } connections := output.Connections for output.NextToken != nil { - output, err = c.client.ListConnections(&codestarconnections.ListConnectionsInput{ + output, err = c.client.ListConnections(context.Background(), &codestarconnections.ListConnectionsInput{ NextToken: output.NextToken, }) if err != nil { @@ -70,9 +70,9 @@ func (c *CodeStar) GetConnectionARN(connectionName string) (connectionARN string } for _, connection := range connections { - if aws.StringValue(connection.ConnectionName) == connectionName { + if awsv2.ToString(connection.ConnectionName) == connectionName { // Duplicate connection names are supposed to result in replacement, so okay to return first match. - return aws.StringValue(connection.ConnectionArn), nil + return awsv2.ToString(connection.ConnectionArn), nil } } return "", fmt.Errorf("cannot find a connectionARN associated with %s", connectionName) diff --git a/internal/pkg/aws/codestar/codestar_test.go b/internal/pkg/aws/codestar/codestar_test.go index b1f950051dc..6badbad99b1 100644 --- a/internal/pkg/aws/codestar/codestar_test.go +++ b/internal/pkg/aws/codestar/codestar_test.go @@ -9,8 +9,9 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/codestarconnections" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/codestarconnections" + "github.com/aws/aws-sdk-go-v2/service/codestarconnections/types" "github.com/aproint/copilot-cli/internal/pkg/aws/codestar/mocks" @@ -28,9 +29,9 @@ func TestCodestar_WaitUntilStatusAvailable(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := mocks.NewMockapi(ctrl) - m.EXPECT().GetConnection(gomock.Any()).Return( - &codestarconnections.GetConnectionOutput{Connection: &codestarconnections.Connection{ - ConnectionStatus: aws.String(codestarconnections.ConnectionStatusPending), + m.EXPECT().GetConnection(gomock.Any(), gomock.Any()).Return( + &codestarconnections.GetConnectionOutput{Connection: &types.Connection{ + ConnectionStatus: types.ConnectionStatusPending, }, }, nil).AnyTimes() @@ -51,7 +52,7 @@ func TestCodestar_WaitUntilStatusAvailable(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() m := mocks.NewMockapi(ctrl) - m.EXPECT().GetConnection(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().GetConnection(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) connection := &CodeStar{ client: m, @@ -74,11 +75,11 @@ func TestCodestar_WaitUntilStatusAvailable(t *testing.T) { client: m, } connectionARN := "mockConnectionARN" - m.EXPECT().GetConnection(&codestarconnections.GetConnectionInput{ - ConnectionArn: aws.String(connectionARN), + m.EXPECT().GetConnection(gomock.Any(), &codestarconnections.GetConnectionInput{ + ConnectionArn: awsv2.String(connectionARN), }).Return( - &codestarconnections.GetConnectionOutput{Connection: &codestarconnections.Connection{ - ConnectionStatus: aws.String(codestarconnections.ConnectionStatusAvailable), + &codestarconnections.GetConnectionOutput{Connection: &types.Connection{ + ConnectionStatus: types.ConnectionStatusAvailable, }, }, nil) @@ -95,7 +96,7 @@ func TestCodeStar_GetConnectionARN(t *testing.T) { // GIVEN ctrl := gomock.NewController(t) m := mocks.NewMockapi(ctrl) - m.EXPECT().ListConnections(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().ListConnections(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) connection := &CodeStar{ client: m, @@ -114,12 +115,12 @@ func TestCodeStar_GetConnectionARN(t *testing.T) { connectionName := "string cheese" ctrl := gomock.NewController(t) m := mocks.NewMockapi(ctrl) - m.EXPECT().ListConnections(gomock.Any()).Return( + m.EXPECT().ListConnections(gomock.Any(), gomock.Any()).Return( &codestarconnections.ListConnectionsOutput{ - Connections: []*codestarconnections.Connection{ - {ConnectionName: aws.String("gouda")}, - {ConnectionName: aws.String("fontina")}, - {ConnectionName: aws.String("brie")}, + Connections: []types.Connection{ + {ConnectionName: awsv2.String("gouda")}, + {ConnectionName: awsv2.String("fontina")}, + {ConnectionName: awsv2.String("brie")}, }, }, nil) @@ -140,20 +141,20 @@ func TestCodeStar_GetConnectionARN(t *testing.T) { connectionName := "string cheese" ctrl := gomock.NewController(t) m := mocks.NewMockapi(ctrl) - m.EXPECT().ListConnections(gomock.Any()).Return( + m.EXPECT().ListConnections(gomock.Any(), gomock.Any()).Return( &codestarconnections.ListConnectionsOutput{ - Connections: []*codestarconnections.Connection{ + Connections: []types.Connection{ { - ConnectionName: aws.String("gouda"), - ConnectionArn: aws.String("notThisOne"), + ConnectionName: awsv2.String("gouda"), + ConnectionArn: awsv2.String("notThisOne"), }, { - ConnectionName: aws.String("string cheese"), - ConnectionArn: aws.String("thisCheesyFakeARN"), + ConnectionName: awsv2.String("string cheese"), + ConnectionArn: awsv2.String("thisCheesyFakeARN"), }, { - ConnectionName: aws.String("fontina"), - ConnectionArn: aws.String("norThisOne"), + ConnectionName: awsv2.String("fontina"), + ConnectionArn: awsv2.String("norThisOne"), }, }, }, nil) @@ -176,28 +177,28 @@ func TestCodeStar_GetConnectionARN(t *testing.T) { mockNextToken := "next" ctrl := gomock.NewController(t) m := mocks.NewMockapi(ctrl) - m.EXPECT().ListConnections(gomock.Any()).Return( + m.EXPECT().ListConnections(gomock.Any(), gomock.Any()).Return( &codestarconnections.ListConnectionsOutput{ - Connections: []*codestarconnections.Connection{ + Connections: []types.Connection{ { - ConnectionName: aws.String("gouda"), - ConnectionArn: aws.String("notThisOne"), + ConnectionName: awsv2.String("gouda"), + ConnectionArn: awsv2.String("notThisOne"), }, { - ConnectionName: aws.String("fontina"), - ConnectionArn: aws.String("thisCheesyFakeARN"), + ConnectionName: awsv2.String("fontina"), + ConnectionArn: awsv2.String("thisCheesyFakeARN"), }, }, NextToken: &mockNextToken, }, nil) - m.EXPECT().ListConnections(&codestarconnections.ListConnectionsInput{ + m.EXPECT().ListConnections(gomock.Any(), &codestarconnections.ListConnectionsInput{ NextToken: &mockNextToken, }).Return( &codestarconnections.ListConnectionsOutput{ - Connections: []*codestarconnections.Connection{ + Connections: []types.Connection{ { - ConnectionName: aws.String("string cheese"), - ConnectionArn: aws.String("thisOne"), + ConnectionName: awsv2.String("string cheese"), + ConnectionArn: awsv2.String("thisOne"), }, }, }, nil) diff --git a/internal/pkg/aws/codestar/mocks/mock_codestar.go b/internal/pkg/aws/codestar/mocks/mock_codestar.go index 7970d49abcd..7aea790dd55 100644 --- a/internal/pkg/aws/codestar/mocks/mock_codestar.go +++ b/internal/pkg/aws/codestar/mocks/mock_codestar.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - codestarconnections "github.com/aws/aws-sdk-go/service/codestarconnections" + codestarconnections "github.com/aws/aws-sdk-go-v2/service/codestarconnections" gomock "github.com/golang/mock/gomock" ) @@ -35,31 +36,41 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // GetConnection mocks base method. -func (m *Mockapi) GetConnection(input *codestarconnections.GetConnectionInput) (*codestarconnections.GetConnectionOutput, error) { +func (m *Mockapi) GetConnection(ctx context.Context, input *codestarconnections.GetConnectionInput, opts ...func(*codestarconnections.Options)) (*codestarconnections.GetConnectionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetConnection", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetConnection", varargs...) ret0, _ := ret[0].(*codestarconnections.GetConnectionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetConnection indicates an expected call of GetConnection. -func (mr *MockapiMockRecorder) GetConnection(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetConnection(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnection", reflect.TypeOf((*Mockapi)(nil).GetConnection), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetConnection", reflect.TypeOf((*Mockapi)(nil).GetConnection), varargs...) } // ListConnections mocks base method. -func (m *Mockapi) ListConnections(input *codestarconnections.ListConnectionsInput) (*codestarconnections.ListConnectionsOutput, error) { +func (m *Mockapi) ListConnections(ctx context.Context, input *codestarconnections.ListConnectionsInput, opts ...func(*codestarconnections.Options)) (*codestarconnections.ListConnectionsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListConnections", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListConnections", varargs...) ret0, _ := ret[0].(*codestarconnections.ListConnectionsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListConnections indicates an expected call of ListConnections. -func (mr *MockapiMockRecorder) ListConnections(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListConnections(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListConnections", reflect.TypeOf((*Mockapi)(nil).ListConnections), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListConnections", reflect.TypeOf((*Mockapi)(nil).ListConnections), varargs...) } diff --git a/internal/pkg/aws/identity/identity.go b/internal/pkg/aws/identity/identity.go index a5f671c7466..790e84112f4 100644 --- a/internal/pkg/aws/identity/identity.go +++ b/internal/pkg/aws/identity/identity.go @@ -5,16 +5,16 @@ package identity import ( + "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/sts" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/sts" ) type api interface { - GetCallerIdentity(input *sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) + GetCallerIdentity(ctx context.Context, input *sts.GetCallerIdentityInput, opts ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error) } // STS wraps the internal sts client. @@ -22,10 +22,10 @@ type STS struct { client api } -// New returns a STS configured with the input session. -func New(s *session.Session) STS { +// New returns a STS configured with the input SDK v2 config. +func New(cfg awsv2.Config) STS { return STS{ - client: sts.New(s), + client: sts.NewFromConfig(cfg), } } @@ -38,18 +38,18 @@ type Caller struct { // Get returns the Caller associated with the Client's session. func (s STS) Get() (Caller, error) { - out, err := s.client.GetCallerIdentity(&sts.GetCallerIdentityInput{}) + out, err := s.client.GetCallerIdentity(context.Background(), &sts.GetCallerIdentityInput{}) if err != nil { return Caller{}, fmt.Errorf("get caller identity: %w", err) } - parsedARN, err := arn.Parse(aws.StringValue(out.Arn)) + parsedARN, err := arn.Parse(awsv2.ToString(out.Arn)) if err != nil { return Caller{}, fmt.Errorf("parse caller arn: %w", err) } return Caller{ - RootUserARN: fmt.Sprintf("arn:%s:iam::%s:root", parsedARN.Partition, aws.StringValue(out.Account)), - Account: aws.StringValue(out.Account), - UserID: aws.StringValue(out.UserId), + RootUserARN: fmt.Sprintf("arn:%s:iam::%s:root", parsedARN.Partition, awsv2.ToString(out.Account)), + Account: awsv2.ToString(out.Account), + UserID: awsv2.ToString(out.UserId), }, nil } diff --git a/internal/pkg/aws/identity/identity_test.go b/internal/pkg/aws/identity/identity_test.go index e95476e8506..194f6d74644 100644 --- a/internal/pkg/aws/identity/identity_test.go +++ b/internal/pkg/aws/identity/identity_test.go @@ -9,7 +9,8 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/identity/mocks" - "github.com/aws/aws-sdk-go/service/sts" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -30,26 +31,26 @@ func TestIdentity_Get(t *testing.T) { }{ "should return wrapped error given error from STS GetCallerIdentity": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any()).Return(nil, mockError) + m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantErr: fmt.Errorf("get caller identity: %w", mockError), }, "should return wrapped error if cannot parse the account arn": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any()).Return(&sts.GetCallerIdentityOutput{ - Account: &mockAccount, - Arn: &mockBadARN, - UserId: &mockUserID, + m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(&sts.GetCallerIdentityOutput{ + Account: awsv2.String(mockAccount), + Arn: awsv2.String(mockBadARN), + UserId: awsv2.String(mockUserID), }, nil) }, wantErr: fmt.Errorf("parse caller arn: arn: invalid prefix"), }, "should return Identity": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any()).Return(&sts.GetCallerIdentityOutput{ - Account: &mockAccount, - Arn: &mockARN, - UserId: &mockUserID, + m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(&sts.GetCallerIdentityOutput{ + Account: awsv2.String(mockAccount), + Arn: awsv2.String(mockARN), + UserId: awsv2.String(mockUserID), }, nil) }, wantIdentity: Caller{ @@ -60,10 +61,10 @@ func TestIdentity_Get(t *testing.T) { }, "should return Identity in non standard partition": { callMock: func(m *mocks.Mockapi) { - m.EXPECT().GetCallerIdentity(gomock.Any()).Return(&sts.GetCallerIdentityOutput{ - Account: &mockAccount, - Arn: &mockChinaARN, - UserId: &mockUserID, + m.EXPECT().GetCallerIdentity(gomock.Any(), gomock.Any()).Return(&sts.GetCallerIdentityOutput{ + Account: awsv2.String(mockAccount), + Arn: awsv2.String(mockChinaARN), + UserId: awsv2.String(mockUserID), }, nil) }, wantIdentity: Caller{ diff --git a/internal/pkg/aws/identity/mocks/mock_identity.go b/internal/pkg/aws/identity/mocks/mock_identity.go index 17f154a828a..d0d4c74871b 100644 --- a/internal/pkg/aws/identity/mocks/mock_identity.go +++ b/internal/pkg/aws/identity/mocks/mock_identity.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - sts "github.com/aws/aws-sdk-go/service/sts" + sts "github.com/aws/aws-sdk-go-v2/service/sts" gomock "github.com/golang/mock/gomock" ) @@ -35,16 +36,21 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // GetCallerIdentity mocks base method. -func (m *Mockapi) GetCallerIdentity(input *sts.GetCallerIdentityInput) (*sts.GetCallerIdentityOutput, error) { +func (m *Mockapi) GetCallerIdentity(ctx context.Context, input *sts.GetCallerIdentityInput, opts ...func(*sts.Options)) (*sts.GetCallerIdentityOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetCallerIdentity", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetCallerIdentity", varargs...) ret0, _ := ret[0].(*sts.GetCallerIdentityOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetCallerIdentity indicates an expected call of GetCallerIdentity. -func (mr *MockapiMockRecorder) GetCallerIdentity(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetCallerIdentity(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCallerIdentity", reflect.TypeOf((*Mockapi)(nil).GetCallerIdentity), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCallerIdentity", reflect.TypeOf((*Mockapi)(nil).GetCallerIdentity), varargs...) } diff --git a/internal/pkg/aws/resourcegroups/mocks/mock_resourcegroups.go b/internal/pkg/aws/resourcegroups/mocks/mock_resourcegroups.go index 841cce78e31..95d3c0902c5 100644 --- a/internal/pkg/aws/resourcegroups/mocks/mock_resourcegroups.go +++ b/internal/pkg/aws/resourcegroups/mocks/mock_resourcegroups.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - resourcegroupstaggingapi "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + resourcegroupstaggingapi "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi" gomock "github.com/golang/mock/gomock" ) @@ -35,16 +36,21 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // GetResources mocks base method. -func (m *Mockapi) GetResources(input *resourcegroupstaggingapi.GetResourcesInput) (*resourcegroupstaggingapi.GetResourcesOutput, error) { +func (m *Mockapi) GetResources(ctx context.Context, input *resourcegroupstaggingapi.GetResourcesInput, opts ...func(*resourcegroupstaggingapi.Options)) (*resourcegroupstaggingapi.GetResourcesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetResources", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetResources", varargs...) ret0, _ := ret[0].(*resourcegroupstaggingapi.GetResourcesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetResources indicates an expected call of GetResources. -func (mr *MockapiMockRecorder) GetResources(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetResources(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResources", reflect.TypeOf((*Mockapi)(nil).GetResources), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetResources", reflect.TypeOf((*Mockapi)(nil).GetResources), varargs...) } diff --git a/internal/pkg/aws/resourcegroups/resourcegroups.go b/internal/pkg/aws/resourcegroups/resourcegroups.go index 2486d319701..56dc10f9ca7 100644 --- a/internal/pkg/aws/resourcegroups/resourcegroups.go +++ b/internal/pkg/aws/resourcegroups/resourcegroups.go @@ -5,12 +5,12 @@ package resourcegroups 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/resourcegroupstaggingapi" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types" ) const ( @@ -21,7 +21,7 @@ const ( ) type api interface { - GetResources(input *resourcegroupstaggingapi.GetResourcesInput) (*resourcegroupstaggingapi.GetResourcesOutput, error) + GetResources(ctx context.Context, input *resourcegroupstaggingapi.GetResourcesInput, opts ...func(*resourcegroupstaggingapi.Options)) (*resourcegroupstaggingapi.GetResourcesOutput, error) } // ResourceGroups wraps an AWS ResourceGroups client. @@ -35,33 +35,33 @@ type Resource struct { Tags map[string]string } -// New returns a ResourceGroup struct configured against the input session. -func New(s *session.Session) *ResourceGroups { +// New returns a ResourceGroup struct configured against the input SDK v2 config. +func New(cfg awsv2.Config) *ResourceGroups { return &ResourceGroups{ - client: resourcegroupstaggingapi.New(s), + client: resourcegroupstaggingapi.NewFromConfig(cfg), } } // GetResourcesByTags gets tag set and ARN for the resource with input resource type and tags. func (rg *ResourceGroups) GetResourcesByTags(resourceType string, tags map[string]string) ([]*Resource, error) { var resources []*Resource - var tagFilter []*resourcegroupstaggingapi.TagFilter + var tagFilter []types.TagFilter for k, v := range tags { - var values []*string + var values []string if v != "" { - values = aws.StringSlice([]string{v}) + values = []string{v} } - tagFilter = append(tagFilter, &resourcegroupstaggingapi.TagFilter{ - Key: aws.String(k), + tagFilter = append(tagFilter, types.TagFilter{ + Key: awsv2.String(k), Values: values, }) } resourceResp := &resourcegroupstaggingapi.GetResourcesOutput{} for { var err error - resourceResp, err = rg.client.GetResources(&resourcegroupstaggingapi.GetResourcesInput{ + resourceResp, err = rg.client.GetResources(context.Background(), &resourcegroupstaggingapi.GetResourcesInput{ PaginationToken: resourceResp.PaginationToken, - ResourceTypeFilters: aws.StringSlice([]string{resourceType}), + ResourceTypeFilters: []string{resourceType}, TagFilters: tagFilter, }) if err != nil { @@ -73,16 +73,16 @@ func (rg *ResourceGroups) GetResourcesByTags(resourceType string, tags map[strin if tag.Key == nil { continue } - tags[*tag.Key] = aws.StringValue(tag.Value) + tags[*tag.Key] = awsv2.ToString(tag.Value) } resources = append(resources, &Resource{ - ARN: aws.StringValue(resourceTagMapping.ResourceARN), + ARN: awsv2.ToString(resourceTagMapping.ResourceARN), Tags: tags, }) } // usually pagination token is "" when it doesn't have any next page. However, since it // is type *string, it is safer for us to check nil value for it as well. - if token := resourceResp.PaginationToken; aws.StringValue(token) == "" { + if token := resourceResp.PaginationToken; awsv2.ToString(token) == "" { break } } diff --git a/internal/pkg/aws/resourcegroups/resourcegroups_test.go b/internal/pkg/aws/resourcegroups/resourcegroups_test.go index a6ec8d8e3c0..c35fd751dcf 100644 --- a/internal/pkg/aws/resourcegroups/resourcegroups_test.go +++ b/internal/pkg/aws/resourcegroups/resourcegroups_test.go @@ -9,8 +9,9 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups/mocks" - "github.com/aws/aws-sdk-go/aws" - rgapi "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + rgapi "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -30,22 +31,22 @@ const ( func TestResourceGroups_GetResourcesByTags(t *testing.T) { mockRequest := &rgapi.GetResourcesInput{ PaginationToken: nil, - ResourceTypeFilters: aws.StringSlice([]string{testResourceType}), - TagFilters: []*rgapi.TagFilter{ + ResourceTypeFilters: []string{testResourceType}, + TagFilters: []types.TagFilter{ { - Key: aws.String("copilot-environment"), - Values: aws.StringSlice([]string{"test"}), + Key: awsv2.String("copilot-environment"), + Values: []string{"test"}, }, }, } mockResponse := &rgapi.GetResourcesOutput{ - ResourceTagMappingList: []*rgapi.ResourceTagMapping{ + ResourceTagMappingList: []types.ResourceTagMapping{ { - ResourceARN: aws.String(testArn), - Tags: []*rgapi.Tag{ + ResourceARN: awsv2.String(testArn), + Tags: []types.Tag{ { - Key: aws.String("copilot-environment"), - Value: aws.String("test"), + Key: awsv2.String("copilot-environment"), + Value: awsv2.String("test"), }, }, }, @@ -64,7 +65,7 @@ func TestResourceGroups_GetResourcesByTags(t *testing.T) { inTags: testTags, inResourceType: testResourceType, setupMocks: func(m *mocks.Mockapi) { - m.EXPECT().GetResources(mockRequest).Return(mockResponse, nil) + m.EXPECT().GetResources(gomock.Any(), mockRequest).Return(mockResponse, nil) }, expectedOut: []*Resource{ { @@ -78,7 +79,7 @@ func TestResourceGroups_GetResourcesByTags(t *testing.T) { inTags: testTags, inResourceType: testResourceType, setupMocks: func(m *mocks.Mockapi) { - m.EXPECT().GetResources(mockRequest).Return(nil, mockError) + m.EXPECT().GetResources(gomock.Any(), mockRequest).Return(nil, mockError) }, expectedOut: nil, expectedErr: fmt.Errorf("get resource: some error"), @@ -88,30 +89,30 @@ func TestResourceGroups_GetResourcesByTags(t *testing.T) { inResourceType: testResourceType, setupMocks: func(m *mocks.Mockapi) { gomock.InOrder( - m.EXPECT().GetResources(mockRequest).Return(&rgapi.GetResourcesOutput{ - PaginationToken: aws.String("mockNextToken"), - ResourceTagMappingList: []*rgapi.ResourceTagMapping{ + m.EXPECT().GetResources(gomock.Any(), mockRequest).Return(&rgapi.GetResourcesOutput{ + PaginationToken: awsv2.String("mockNextToken"), + ResourceTagMappingList: []types.ResourceTagMapping{ { - ResourceARN: aws.String(mockArn1), - Tags: []*rgapi.Tag{{Key: aws.String("copilot-environment"), Value: aws.String("test")}}, + ResourceARN: awsv2.String(mockArn1), + Tags: []types.Tag{{Key: awsv2.String("copilot-environment"), Value: awsv2.String("test")}}, }, }, }, nil), - m.EXPECT().GetResources(&rgapi.GetResourcesInput{ - PaginationToken: aws.String("mockNextToken"), - ResourceTypeFilters: aws.StringSlice([]string{testResourceType}), - TagFilters: []*rgapi.TagFilter{ + m.EXPECT().GetResources(gomock.Any(), &rgapi.GetResourcesInput{ + PaginationToken: awsv2.String("mockNextToken"), + ResourceTypeFilters: []string{testResourceType}, + TagFilters: []types.TagFilter{ { - Key: aws.String("copilot-environment"), - Values: aws.StringSlice([]string{"test"}), + Key: awsv2.String("copilot-environment"), + Values: []string{"test"}, }, }, }).Return(&rgapi.GetResourcesOutput{ PaginationToken: nil, - ResourceTagMappingList: []*rgapi.ResourceTagMapping{ + ResourceTagMappingList: []types.ResourceTagMapping{ { - ResourceARN: aws.String(mockArn2), - Tags: []*rgapi.Tag{{Key: aws.String("copilot-environment"), Value: aws.String("test")}}, + ResourceARN: awsv2.String(mockArn2), + Tags: []types.Tag{{Key: awsv2.String("copilot-environment"), Value: awsv2.String("test")}}, }, }, }, nil), diff --git a/internal/pkg/aws/secretsmanager/mocks/mock_secretsmanager.go b/internal/pkg/aws/secretsmanager/mocks/mock_secretsmanager.go index 0fb10ffcc25..f53fdbddf50 100644 --- a/internal/pkg/aws/secretsmanager/mocks/mock_secretsmanager.go +++ b/internal/pkg/aws/secretsmanager/mocks/mock_secretsmanager.go @@ -8,8 +8,7 @@ import ( context "context" reflect "reflect" - request "github.com/aws/aws-sdk-go/aws/request" - secretsmanager "github.com/aws/aws-sdk-go/service/secretsmanager" + secretsmanager "github.com/aws/aws-sdk-go-v2/service/secretsmanager" gomock "github.com/golang/mock/gomock" ) @@ -37,66 +36,81 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // CreateSecret mocks base method. -func (m *Mockapi) CreateSecret(arg0 *secretsmanager.CreateSecretInput) (*secretsmanager.CreateSecretOutput, error) { +func (m *Mockapi) CreateSecret(arg0 context.Context, arg1 *secretsmanager.CreateSecretInput, arg2 ...func(*secretsmanager.Options)) (*secretsmanager.CreateSecretOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateSecret", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateSecret", varargs...) ret0, _ := ret[0].(*secretsmanager.CreateSecretOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateSecret indicates an expected call of CreateSecret. -func (mr *MockapiMockRecorder) CreateSecret(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) CreateSecret(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSecret", reflect.TypeOf((*Mockapi)(nil).CreateSecret), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSecret", reflect.TypeOf((*Mockapi)(nil).CreateSecret), varargs...) } // DeleteSecret mocks base method. -func (m *Mockapi) DeleteSecret(arg0 *secretsmanager.DeleteSecretInput) (*secretsmanager.DeleteSecretOutput, error) { +func (m *Mockapi) DeleteSecret(arg0 context.Context, arg1 *secretsmanager.DeleteSecretInput, arg2 ...func(*secretsmanager.Options)) (*secretsmanager.DeleteSecretOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteSecret", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteSecret", varargs...) ret0, _ := ret[0].(*secretsmanager.DeleteSecretOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteSecret indicates an expected call of DeleteSecret. -func (mr *MockapiMockRecorder) DeleteSecret(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DeleteSecret(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecret", reflect.TypeOf((*Mockapi)(nil).DeleteSecret), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteSecret", reflect.TypeOf((*Mockapi)(nil).DeleteSecret), varargs...) } // DescribeSecret mocks base method. -func (m *Mockapi) DescribeSecret(arg0 *secretsmanager.DescribeSecretInput) (*secretsmanager.DescribeSecretOutput, error) { +func (m *Mockapi) DescribeSecret(arg0 context.Context, arg1 *secretsmanager.DescribeSecretInput, arg2 ...func(*secretsmanager.Options)) (*secretsmanager.DescribeSecretOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeSecret", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeSecret", varargs...) ret0, _ := ret[0].(*secretsmanager.DescribeSecretOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeSecret indicates an expected call of DescribeSecret. -func (mr *MockapiMockRecorder) DescribeSecret(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeSecret(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSecret", reflect.TypeOf((*Mockapi)(nil).DescribeSecret), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSecret", reflect.TypeOf((*Mockapi)(nil).DescribeSecret), varargs...) } -// GetSecretValueWithContext mocks base method. -func (m *Mockapi) GetSecretValueWithContext(arg0 context.Context, arg1 *secretsmanager.GetSecretValueInput, arg2 ...request.Option) (*secretsmanager.GetSecretValueOutput, error) { +// GetSecretValue mocks base method. +func (m *Mockapi) GetSecretValue(arg0 context.Context, arg1 *secretsmanager.GetSecretValueInput, arg2 ...func(*secretsmanager.Options)) (*secretsmanager.GetSecretValueOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "GetSecretValueWithContext", varargs...) + ret := m.ctrl.Call(m, "GetSecretValue", varargs...) ret0, _ := ret[0].(*secretsmanager.GetSecretValueOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetSecretValueWithContext indicates an expected call of GetSecretValueWithContext. -func (mr *MockapiMockRecorder) GetSecretValueWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// GetSecretValue indicates an expected call of GetSecretValue. +func (mr *MockapiMockRecorder) GetSecretValue(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, "GetSecretValueWithContext", reflect.TypeOf((*Mockapi)(nil).GetSecretValueWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSecretValue", reflect.TypeOf((*Mockapi)(nil).GetSecretValue), varargs...) } diff --git a/internal/pkg/aws/secretsmanager/secretsmanager.go b/internal/pkg/aws/secretsmanager/secretsmanager.go index 2a07d65c7e3..0fbbcad7255 100644 --- a/internal/pkg/aws/secretsmanager/secretsmanager.go +++ b/internal/pkg/aws/secretsmanager/secretsmanager.go @@ -6,22 +6,20 @@ package secretsmanager import ( "context" + "errors" "fmt" "time" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/secretsmanager" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/secretsmanager" + "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types" ) type api interface { - CreateSecret(*secretsmanager.CreateSecretInput) (*secretsmanager.CreateSecretOutput, error) - DeleteSecret(*secretsmanager.DeleteSecretInput) (*secretsmanager.DeleteSecretOutput, error) - DescribeSecret(*secretsmanager.DescribeSecretInput) (*secretsmanager.DescribeSecretOutput, error) - GetSecretValueWithContext(context.Context, *secretsmanager.GetSecretValueInput, ...request.Option) (*secretsmanager.GetSecretValueOutput, error) + CreateSecret(context.Context, *secretsmanager.CreateSecretInput, ...func(*secretsmanager.Options)) (*secretsmanager.CreateSecretOutput, error) + DeleteSecret(context.Context, *secretsmanager.DeleteSecretInput, ...func(*secretsmanager.Options)) (*secretsmanager.DeleteSecretOutput, error) + DescribeSecret(context.Context, *secretsmanager.DescribeSecretInput, ...func(*secretsmanager.Options)) (*secretsmanager.DescribeSecretOutput, error) + GetSecretValue(context.Context, *secretsmanager.GetSecretValueInput, ...func(*secretsmanager.Options)) (*secretsmanager.GetSecretValueOutput, error) } // SecretsManager wraps the AWS SecretManager client. @@ -30,54 +28,53 @@ type SecretsManager struct { sessionRegion string } -// New returns a SecretsManager configured against the input session. -func New(s *session.Session) *SecretsManager { +// New returns a SecretsManager configured against the input SDK v2 config. +func New(cfg awsv2.Config) *SecretsManager { return &SecretsManager{ - secretsManager: secretsmanager.New(s), - sessionRegion: *s.Config.Region, + secretsManager: secretsmanager.NewFromConfig(cfg), + sessionRegion: cfg.Region, } } -var secretTags = func() []*secretsmanager.Tag { +var secretTags = func() []types.Tag { timestamp := time.Now().UTC().Format(time.UnixDate) - return []*secretsmanager.Tag{ + return []types.Tag{ { - Key: aws.String("copilot-application"), - Value: aws.String(timestamp), + Key: awsv2.String("copilot-application"), + Value: awsv2.String(timestamp), }, } } // CreateSecret creates a secret using the default KMS key "aws/secretmanager" to encrypt the secret and returns its ARN. func (s *SecretsManager) CreateSecret(secretName, secretString string) (string, error) { - resp, err := s.secretsManager.CreateSecret(&secretsmanager.CreateSecretInput{ - Name: aws.String(secretName), - SecretString: aws.String(secretString), + resp, err := s.secretsManager.CreateSecret(context.Background(), &secretsmanager.CreateSecretInput{ + Name: awsv2.String(secretName), + SecretString: awsv2.String(secretString), Tags: secretTags(), }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == secretsmanager.ErrCodeResourceExistsException { - // TODO update secret if value provided? - return "", &ErrSecretAlreadyExists{ - secretName: secretName, - parentErr: err, - } + var errAlreadyExists *types.ResourceExistsException + if errors.As(err, &errAlreadyExists) { + // TODO update secret if value provided? + return "", &ErrSecretAlreadyExists{ + secretName: secretName, + parentErr: err, } } return "", fmt.Errorf("create secret %s: %w", secretName, err) } - return aws.StringValue(resp.ARN), nil + return awsv2.ToString(resp.ARN), nil } // DeleteSecret force removes the secret from SecretsManager. func (s *SecretsManager) DeleteSecret(secretName string) error { - _, err := s.secretsManager.DeleteSecret(&secretsmanager.DeleteSecretInput{ - SecretId: aws.String(secretName), - ForceDeleteWithoutRecovery: aws.Bool(true), // forego the waiting period to delete the secret + _, err := s.secretsManager.DeleteSecret(context.Background(), &secretsmanager.DeleteSecretInput{ + SecretId: awsv2.String(secretName), + ForceDeleteWithoutRecovery: awsv2.Bool(true), // forego the waiting period to delete the secret }) if err != nil { @@ -90,21 +87,20 @@ func (s *SecretsManager) DeleteSecret(secretName string) error { type DescribeSecretOutput struct { Name *string CreatedDate *time.Time - Tags []*secretsmanager.Tag + Tags []types.Tag } // DescribeSecret retrieves the details of a secret. func (s *SecretsManager) DescribeSecret(secretName string) (*DescribeSecretOutput, error) { - resp, err := s.secretsManager.DescribeSecret(&secretsmanager.DescribeSecretInput{ - SecretId: aws.String(secretName), + resp, err := s.secretsManager.DescribeSecret(context.Background(), &secretsmanager.DescribeSecretInput{ + SecretId: awsv2.String(secretName), }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - if aerr.Code() == secretsmanager.ErrCodeResourceNotFoundException { - return nil, &ErrSecretNotFound{ - secretName: secretName, - parentErr: err, - } + var errNotFound *types.ResourceNotFoundException + if errors.As(err, &errNotFound) { + return nil, &ErrSecretNotFound{ + secretName: secretName, + parentErr: err, } } return nil, fmt.Errorf("describe secret %s: %w", secretName, err) @@ -120,13 +116,13 @@ func (s *SecretsManager) DescribeSecret(secretName string) (*DescribeSecretOutpu // GetSecretValue retrieves the value of a secret from AWS Secrets Manager. // It takes the name of the secret as input and returns the corresponding value as a string. func (s *SecretsManager) GetSecretValue(ctx context.Context, name string) (string, error) { - resp, err := s.secretsManager.GetSecretValueWithContext(ctx, &secretsmanager.GetSecretValueInput{ - SecretId: aws.String(name), + resp, err := s.secretsManager.GetSecretValue(ctx, &secretsmanager.GetSecretValueInput{ + SecretId: awsv2.String(name), }) if err != nil { return "", fmt.Errorf("get secret %q from secrets manager: %w", name, err) } - return aws.StringValue(resp.SecretString), nil + return awsv2.ToString(resp.SecretString), nil } // ErrSecretAlreadyExists occurs if a secret with the same name already exists. diff --git a/internal/pkg/aws/secretsmanager/secretsmanager_test.go b/internal/pkg/aws/secretsmanager/secretsmanager_test.go index 1e431279c3a..febd5af833f 100644 --- a/internal/pkg/aws/secretsmanager/secretsmanager_test.go +++ b/internal/pkg/aws/secretsmanager/secretsmanager_test.go @@ -12,9 +12,9 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/aws/secretsmanager/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/secretsmanager" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/secretsmanager" + "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -24,9 +24,9 @@ func TestSecretsManager_CreateSecret(t *testing.T) { mockSecretString := "H0NKH0NKH0NK" mockError := errors.New("mockError") mockOutput := &secretsmanager.CreateSecretOutput{ - ARN: aws.String("arn-goose"), + ARN: awsv2.String("arn-goose"), } - mockAwsErr := awserr.New(secretsmanager.ErrCodeResourceExistsException, "", nil) + mockAwsErr := &types.ResourceExistsException{} tests := map[string]struct { inSecretName string @@ -39,10 +39,10 @@ func TestSecretsManager_CreateSecret(t *testing.T) { inSecretName: mockSecretName, inSecretString: mockSecretString, callMock: func(m *mocks.Mockapi) { - m.EXPECT().CreateSecret(&secretsmanager.CreateSecretInput{ - Name: aws.String(mockSecretName), - SecretString: aws.String(mockSecretString), - Tags: []*secretsmanager.Tag{}, + m.EXPECT().CreateSecret(gomock.Any(), &secretsmanager.CreateSecretInput{ + Name: awsv2.String(mockSecretName), + SecretString: awsv2.String(mockSecretString), + Tags: []types.Tag{}, }).Return(nil, mockError) }, expectedError: fmt.Errorf("create secret %s: %w", mockSecretName, mockError), @@ -52,10 +52,10 @@ func TestSecretsManager_CreateSecret(t *testing.T) { inSecretName: mockSecretName, inSecretString: mockSecretString, callMock: func(m *mocks.Mockapi) { - m.EXPECT().CreateSecret(&secretsmanager.CreateSecretInput{ - Name: aws.String(mockSecretName), - SecretString: aws.String(mockSecretString), - Tags: []*secretsmanager.Tag{}, + m.EXPECT().CreateSecret(gomock.Any(), &secretsmanager.CreateSecretInput{ + Name: awsv2.String(mockSecretName), + SecretString: awsv2.String(mockSecretString), + Tags: []types.Tag{}, }).Return(nil, mockAwsErr) }, expectedError: &ErrSecretAlreadyExists{ @@ -68,10 +68,10 @@ func TestSecretsManager_CreateSecret(t *testing.T) { inSecretName: mockSecretName, inSecretString: mockSecretString, callMock: func(m *mocks.Mockapi) { - m.EXPECT().CreateSecret(&secretsmanager.CreateSecretInput{ - Name: aws.String(mockSecretName), - SecretString: aws.String(mockSecretString), - Tags: []*secretsmanager.Tag{}, + m.EXPECT().CreateSecret(gomock.Any(), &secretsmanager.CreateSecretInput{ + Name: awsv2.String(mockSecretName), + SecretString: awsv2.String(mockSecretString), + Tags: []types.Tag{}, }).Return(mockOutput, nil) }, expectedError: nil, @@ -95,8 +95,8 @@ func TestSecretsManager_CreateSecret(t *testing.T) { // WHEN oldSecretTags := secretTags defer func() { secretTags = oldSecretTags }() - secretTags = func() []*secretsmanager.Tag { - return []*secretsmanager.Tag{} + secretTags = func() []types.Tag { + return []types.Tag{} } _, err := sm.CreateSecret(tc.inSecretName, tc.inSecretString) @@ -120,9 +120,9 @@ func TestSecretsManager_DeleteSecret(t *testing.T) { "should wrap error returned by DeleteSecret": { inSecretName: mockSecretName, callMock: func(m *mocks.Mockapi) { - m.EXPECT().DeleteSecret(&secretsmanager.DeleteSecretInput{ - SecretId: aws.String(mockSecretName), - ForceDeleteWithoutRecovery: aws.Bool(true), + m.EXPECT().DeleteSecret(gomock.Any(), &secretsmanager.DeleteSecretInput{ + SecretId: awsv2.String(mockSecretName), + ForceDeleteWithoutRecovery: awsv2.Bool(true), }).Return(nil, mockError) }, expectedError: fmt.Errorf("delete secret %s from secrets manager: %w", mockSecretName, mockError), @@ -130,9 +130,9 @@ func TestSecretsManager_DeleteSecret(t *testing.T) { "should return no error if successful": { inSecretName: mockSecretName, callMock: func(m *mocks.Mockapi) { - m.EXPECT().DeleteSecret(&secretsmanager.DeleteSecretInput{ - SecretId: aws.String(mockSecretName), - ForceDeleteWithoutRecovery: aws.Bool(true), + m.EXPECT().DeleteSecret(gomock.Any(), &secretsmanager.DeleteSecretInput{ + SecretId: awsv2.String(mockSecretName), + ForceDeleteWithoutRecovery: awsv2.Bool(true), }).Return(nil, nil) }, expectedError: nil, @@ -165,16 +165,16 @@ func TestSecretsManager_DescribeSecret(t *testing.T) { mockSecretName := "github-token-backend-badgoose" mockError := errors.New("mockError") mockAPIOutput := &secretsmanager.DescribeSecretOutput{ - CreatedDate: aws.Time(mockTime), - Name: aws.String(mockSecretName), - Tags: []*secretsmanager.Tag{}, + CreatedDate: awsv2.Time(mockTime), + Name: awsv2.String(mockSecretName), + Tags: []types.Tag{}, } mockOutput := &DescribeSecretOutput{ - CreatedDate: aws.Time(mockTime), - Name: aws.String(mockSecretName), - Tags: []*secretsmanager.Tag{}, + CreatedDate: awsv2.Time(mockTime), + Name: awsv2.String(mockSecretName), + Tags: []types.Tag{}, } - mockAwsErr := awserr.New(secretsmanager.ErrCodeResourceNotFoundException, "", nil) + mockAwsErr := &types.ResourceNotFoundException{} tests := map[string]struct { inSecretName string @@ -186,8 +186,8 @@ func TestSecretsManager_DescribeSecret(t *testing.T) { "should wrap error returned by DescribeSecret": { inSecretName: mockSecretName, callMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSecret(&secretsmanager.DescribeSecretInput{ - SecretId: aws.String(mockSecretName), + m.EXPECT().DescribeSecret(gomock.Any(), &secretsmanager.DescribeSecretInput{ + SecretId: awsv2.String(mockSecretName), }).Return(nil, mockError) }, expectedError: fmt.Errorf("describe secret %s: %w", mockSecretName, mockError), @@ -196,8 +196,8 @@ func TestSecretsManager_DescribeSecret(t *testing.T) { "should return no error if secret is not found": { inSecretName: mockSecretName, callMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSecret(&secretsmanager.DescribeSecretInput{ - SecretId: aws.String(mockSecretName), + m.EXPECT().DescribeSecret(gomock.Any(), &secretsmanager.DescribeSecretInput{ + SecretId: awsv2.String(mockSecretName), }).Return(nil, mockAwsErr) }, expectedError: &ErrSecretNotFound{ @@ -209,8 +209,8 @@ func TestSecretsManager_DescribeSecret(t *testing.T) { "should return no error if successful": { inSecretName: mockSecretName, callMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSecret(&secretsmanager.DescribeSecretInput{ - SecretId: aws.String(mockSecretName), + m.EXPECT().DescribeSecret(gomock.Any(), &secretsmanager.DescribeSecretInput{ + SecretId: awsv2.String(mockSecretName), }).Return(mockAPIOutput, nil) }, expectedResp: mockOutput, @@ -235,8 +235,8 @@ func TestSecretsManager_DescribeSecret(t *testing.T) { // WHEN oldSecretTags := secretTags defer func() { secretTags = oldSecretTags }() - secretTags = func() []*secretsmanager.Tag { - return []*secretsmanager.Tag{} + secretTags = func() []types.Tag { + return []types.Tag{} } resp, err := sm.DescribeSecret(tc.inSecretName) @@ -263,8 +263,8 @@ func TestSecretsManager_GetSecretValue(t *testing.T) { "error": { secretName: "asdf", setupMock: func(m *mocks.Mockapi) { - m.EXPECT().GetSecretValueWithContext(gomock.Any(), &secretsmanager.GetSecretValueInput{ - SecretId: aws.String("asdf"), + m.EXPECT().GetSecretValue(gomock.Any(), &secretsmanager.GetSecretValueInput{ + SecretId: awsv2.String("asdf"), }).Return(nil, errors.New("some error")) }, wantError: `get secret "asdf" from secrets manager: some error`, @@ -272,10 +272,10 @@ func TestSecretsManager_GetSecretValue(t *testing.T) { "success": { secretName: "asdf", setupMock: func(m *mocks.Mockapi) { - m.EXPECT().GetSecretValueWithContext(gomock.Any(), &secretsmanager.GetSecretValueInput{ - SecretId: aws.String("asdf"), + m.EXPECT().GetSecretValue(gomock.Any(), &secretsmanager.GetSecretValueInput{ + SecretId: awsv2.String("asdf"), }).Return(&secretsmanager.GetSecretValueOutput{ - SecretString: aws.String("hi"), + SecretString: awsv2.String("hi"), }, nil) }, want: "hi", diff --git a/internal/pkg/aws/ssm/mocks/mock_ssm.go b/internal/pkg/aws/ssm/mocks/mock_ssm.go index 3a4ab861e30..b7ab7c9d609 100644 --- a/internal/pkg/aws/ssm/mocks/mock_ssm.go +++ b/internal/pkg/aws/ssm/mocks/mock_ssm.go @@ -8,8 +8,7 @@ import ( context "context" reflect "reflect" - request "github.com/aws/aws-sdk-go/aws/request" - ssm "github.com/aws/aws-sdk-go/service/ssm" + ssm "github.com/aws/aws-sdk-go-v2/service/ssm" gomock "github.com/golang/mock/gomock" ) @@ -37,51 +36,61 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // AddTagsToResource mocks base method. -func (m *Mockapi) AddTagsToResource(arg0 *ssm.AddTagsToResourceInput) (*ssm.AddTagsToResourceOutput, error) { +func (m *Mockapi) AddTagsToResource(arg0 context.Context, arg1 *ssm.AddTagsToResourceInput, arg2 ...func(*ssm.Options)) (*ssm.AddTagsToResourceOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddTagsToResource", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "AddTagsToResource", varargs...) ret0, _ := ret[0].(*ssm.AddTagsToResourceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // AddTagsToResource indicates an expected call of AddTagsToResource. -func (mr *MockapiMockRecorder) AddTagsToResource(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) AddTagsToResource(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTagsToResource", reflect.TypeOf((*Mockapi)(nil).AddTagsToResource), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTagsToResource", reflect.TypeOf((*Mockapi)(nil).AddTagsToResource), varargs...) } -// GetParameterWithContext mocks base method. -func (m *Mockapi) GetParameterWithContext(arg0 context.Context, arg1 *ssm.GetParameterInput, arg2 ...request.Option) (*ssm.GetParameterOutput, error) { +// GetParameter mocks base method. +func (m *Mockapi) GetParameter(arg0 context.Context, arg1 *ssm.GetParameterInput, arg2 ...func(*ssm.Options)) (*ssm.GetParameterOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "GetParameterWithContext", varargs...) + ret := m.ctrl.Call(m, "GetParameter", varargs...) ret0, _ := ret[0].(*ssm.GetParameterOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetParameterWithContext indicates an expected call of GetParameterWithContext. -func (mr *MockapiMockRecorder) GetParameterWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// GetParameter indicates an expected call of GetParameter. +func (mr *MockapiMockRecorder) GetParameter(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, "GetParameterWithContext", reflect.TypeOf((*Mockapi)(nil).GetParameterWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetParameter", reflect.TypeOf((*Mockapi)(nil).GetParameter), varargs...) } // PutParameter mocks base method. -func (m *Mockapi) PutParameter(arg0 *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { +func (m *Mockapi) PutParameter(arg0 context.Context, arg1 *ssm.PutParameterInput, arg2 ...func(*ssm.Options)) (*ssm.PutParameterOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PutParameter", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PutParameter", varargs...) ret0, _ := ret[0].(*ssm.PutParameterOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // PutParameter indicates an expected call of PutParameter. -func (mr *MockapiMockRecorder) PutParameter(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) PutParameter(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutParameter", reflect.TypeOf((*Mockapi)(nil).PutParameter), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PutParameter", reflect.TypeOf((*Mockapi)(nil).PutParameter), varargs...) } diff --git a/internal/pkg/aws/ssm/ssm.go b/internal/pkg/aws/ssm/ssm.go index ddc00996c62..b1625b1c480 100644 --- a/internal/pkg/aws/ssm/ssm.go +++ b/internal/pkg/aws/ssm/ssm.go @@ -10,18 +10,15 @@ import ( "fmt" "sort" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" ) type api interface { - PutParameter(*ssm.PutParameterInput) (*ssm.PutParameterOutput, error) - AddTagsToResource(*ssm.AddTagsToResourceInput) (*ssm.AddTagsToResourceOutput, error) - GetParameterWithContext(context.Context, *ssm.GetParameterInput, ...request.Option) (*ssm.GetParameterOutput, error) + PutParameter(context.Context, *ssm.PutParameterInput, ...func(*ssm.Options)) (*ssm.PutParameterOutput, error) + AddTagsToResource(context.Context, *ssm.AddTagsToResourceInput, ...func(*ssm.Options)) (*ssm.AddTagsToResourceOutput, error) + GetParameter(context.Context, *ssm.GetParameterInput, ...func(*ssm.Options)) (*ssm.GetParameterOutput, error) } // SSM wraps an AWS SSM client. @@ -29,10 +26,10 @@ type SSM struct { client api } -// New returns a SSM service configured against the input session. -func New(s *session.Session) *SSM { +// New returns a SSM service configured against the input SDK v2 config. +func New(cfg awsv2.Config) *SSM { return &SSM{ - client: ssm.New(s), + client: ssm.NewFromConfig(cfg), } } @@ -67,14 +64,14 @@ func (s *SSM) PutSecret(in PutSecretInput) (*PutSecretOutput, error) { // GetSecretValue retrieves the value of a parameter from AWS Systems Manager Parameter Store. // It takes the name of the parameter as input and returns the corresponding value as a string. func (s *SSM) GetSecretValue(ctx context.Context, name string) (string, error) { - resp, err := s.client.GetParameterWithContext(ctx, &ssm.GetParameterInput{ - Name: aws.String(name), - WithDecryption: aws.Bool(true), + resp, err := s.client.GetParameter(ctx, &ssm.GetParameterInput{ + Name: awsv2.String(name), + WithDecryption: awsv2.Bool(true), }) if err != nil { return "", fmt.Errorf("get parameter %q from SSM: %w", name, err) } - return aws.StringValue(resp.Parameter.Value), nil + return awsv2.ToString(resp.Parameter.Value), nil } func (s *SSM) createSecret(in PutSecretInput) (*PutSecretOutput, error) { @@ -84,21 +81,20 @@ func (s *SSM) createSecret(in PutSecretInput) (*PutSecretOutput, error) { tags := convertTags(in.Tags) input := &ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(in.Name), - Value: aws.String(in.Value), + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(in.Name), + Value: awsv2.String(in.Value), Tags: tags, } - output, err := s.client.PutParameter(input) + output, err := s.client.PutParameter(context.Background(), input) if err == nil { return (*PutSecretOutput)(output), nil } - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == ssm.ErrCodeParameterAlreadyExists { - return nil, &ErrParameterAlreadyExists{in.Name} - } + var errAlreadyExists *types.ParameterAlreadyExists + if errors.As(err, &errAlreadyExists) { + return nil, &ErrParameterAlreadyExists{in.Name} } return nil, fmt.Errorf("create parameter %s: %w", in.Name, err) } @@ -108,21 +104,21 @@ func (s *SSM) overwriteSecret(in PutSecretInput) (*PutSecretOutput, error) { // add the tags in two separate calls. input := &ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(in.Name), - Value: aws.String(in.Value), - Overwrite: aws.Bool(in.Overwrite), + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(in.Name), + Value: awsv2.String(in.Value), + Overwrite: awsv2.Bool(in.Overwrite), } - output, err := s.client.PutParameter(input) + output, err := s.client.PutParameter(context.Background(), input) if err != nil { return nil, fmt.Errorf("update parameter %s: %w", in.Name, err) } tags := convertTags(in.Tags) - _, err = s.client.AddTagsToResource(&ssm.AddTagsToResourceInput{ - ResourceType: aws.String(ssm.ResourceTypeForTaggingParameter), - ResourceId: aws.String(in.Name), + _, err = s.client.AddTagsToResource(context.Background(), &ssm.AddTagsToResourceInput{ + ResourceType: types.ResourceTypeForTaggingParameter, + ResourceId: awsv2.String(in.Name), Tags: tags, }) if err != nil { @@ -131,7 +127,7 @@ func (s *SSM) overwriteSecret(in PutSecretInput) (*PutSecretOutput, error) { return (*PutSecretOutput)(output), nil } -func convertTags(inTags map[string]string) []*ssm.Tag { +func convertTags(inTags map[string]string) []types.Tag { // Sort the map so that the unit test won't be flaky. keys := make([]string, 0, len(inTags)) for k := range inTags { @@ -139,11 +135,11 @@ func convertTags(inTags map[string]string) []*ssm.Tag { } sort.Strings(keys) - var tags []*ssm.Tag + var tags []types.Tag for _, key := range keys { - tags = append(tags, &ssm.Tag{ - Key: aws.String(key), - Value: aws.String(inTags[key]), + tags = append(tags, types.Tag{ + Key: awsv2.String(key), + Value: awsv2.String(inTags[key]), }) } return tags diff --git a/internal/pkg/aws/ssm/ssm_test.go b/internal/pkg/aws/ssm/ssm_test.go index 19700108902..90921337534 100644 --- a/internal/pkg/aws/ssm/ssm_test.go +++ b/internal/pkg/aws/ssm/ssm_test.go @@ -11,9 +11,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ssm/mocks" "github.com/aproint/copilot-cli/internal/pkg/deploy" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -42,29 +42,29 @@ func TestSSM_PutSecret(t *testing.T) { }, }, mockClient: func(m *mocks.Mockapi) { - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, }).Return(&ssm.PutParameterOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(1), + Tier: types.ParameterTierStandard, + Version: int64(1), }, nil) }, wantedOut: &PutSecretOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(1), + Tier: types.ParameterTierStandard, + Version: int64(1), }, }, "attempt to create a new secret even if overwrite is true": { @@ -78,29 +78,29 @@ func TestSSM_PutSecret(t *testing.T) { Overwrite: true, }, mockClient: func(m *mocks.Mockapi) { - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, }).Return(&ssm.PutParameterOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(1), + Tier: types.ParameterTierStandard, + Version: int64(1), }, nil) }, wantedOut: &PutSecretOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(1), + Tier: types.ParameterTierStandard, + Version: int64(1), }, }, "no overwrite attempt when overwrite is false and creation fails because the secret exists": { @@ -113,22 +113,22 @@ func TestSSM_PutSecret(t *testing.T) { }, }, mockClient: func(m *mocks.Mockapi) { - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, - }).Return(nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "parameter already exists", fmt.Errorf("parameter already exists"))) + }).Return(nil, &types.ParameterAlreadyExists{Message: awsv2.String("parameter already exists")}) }, wantedError: &ErrParameterAlreadyExists{"/copilot/myapp/myenv/secrets/db-password"}, }, @@ -142,19 +142,19 @@ func TestSSM_PutSecret(t *testing.T) { }, }, mockClient: func(m *mocks.Mockapi) { - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, }).Return(nil, errors.New("some error")) @@ -172,19 +172,19 @@ func TestSSM_PutSecret(t *testing.T) { Overwrite: true, }, mockClient: func(m *mocks.Mockapi) { - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, }).Return(nil, errors.New("some error")) @@ -203,35 +203,35 @@ func TestSSM_PutSecret(t *testing.T) { }, mockClient: func(m *mocks.Mockapi) { gomock.InOrder( - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, - }).Return(nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "parameter already exists", fmt.Errorf("parameter already exists"))), - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Overwrite: aws.Bool(true), + }).Return(nil, &types.ParameterAlreadyExists{Message: awsv2.String("parameter already exists")}), + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Overwrite: awsv2.Bool(true), }).Return(&ssm.PutParameterOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(3), + Tier: types.ParameterTierStandard, + Version: int64(3), }, nil), - m.EXPECT().AddTagsToResource(&ssm.AddTagsToResourceInput{ - ResourceType: aws.String(ssm.ResourceTypeForTaggingParameter), - ResourceId: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + m.EXPECT().AddTagsToResource(gomock.Any(), &ssm.AddTagsToResourceInput{ + ResourceType: types.ResourceTypeForTaggingParameter, + ResourceId: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), Tags: convertTags(map[string]string{ deploy.AppTagKey: mockApp, deploy.EnvTagKey: mockEnv, @@ -240,8 +240,8 @@ func TestSSM_PutSecret(t *testing.T) { ) }, wantedOut: &PutSecretOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(3), + Tier: types.ParameterTierStandard, + Version: int64(3), }, }, "failed to add tags during an overwrite operation": { @@ -256,35 +256,35 @@ func TestSSM_PutSecret(t *testing.T) { }, mockClient: func(m *mocks.Mockapi) { gomock.InOrder( - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, - }).Return(nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "parameter already exists", fmt.Errorf("parameter already exists"))), - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Overwrite: aws.Bool(true), + }).Return(nil, &types.ParameterAlreadyExists{Message: awsv2.String("parameter already exists")}), + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Overwrite: awsv2.Bool(true), }).Return(&ssm.PutParameterOutput{ - Tier: aws.String("Standard"), - Version: aws.Int64(3), + Tier: types.ParameterTierStandard, + Version: int64(3), }, nil), - m.EXPECT().AddTagsToResource(&ssm.AddTagsToResourceInput{ - ResourceType: aws.String(ssm.ResourceTypeForTaggingParameter), - ResourceId: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + m.EXPECT().AddTagsToResource(gomock.Any(), &ssm.AddTagsToResourceInput{ + ResourceType: types.ResourceTypeForTaggingParameter, + ResourceId: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), Tags: convertTags(map[string]string{ deploy.AppTagKey: mockApp, deploy.EnvTagKey: mockEnv, @@ -306,28 +306,28 @@ func TestSSM_PutSecret(t *testing.T) { }, mockClient: func(m *mocks.Mockapi) { gomock.InOrder( - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Tags: []*ssm.Tag{ + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Tags: []types.Tag{ { - Key: aws.String(deploy.AppTagKey), - Value: aws.String(mockApp), + Key: awsv2.String(deploy.AppTagKey), + Value: awsv2.String(mockApp), }, { - Key: aws.String(deploy.EnvTagKey), - Value: aws.String(mockEnv), + Key: awsv2.String(deploy.EnvTagKey), + Value: awsv2.String(mockEnv), }, }, - }).Return(nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "parameter already exists", fmt.Errorf("parameter already exists"))), - m.EXPECT().PutParameter(&ssm.PutParameterInput{ - DataType: aws.String("text"), - Type: aws.String("SecureString"), - Name: aws.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), - Value: aws.String("super secure password"), - Overwrite: aws.Bool(true), + }).Return(nil, &types.ParameterAlreadyExists{Message: awsv2.String("parameter already exists")}), + m.EXPECT().PutParameter(gomock.Any(), &ssm.PutParameterInput{ + DataType: awsv2.String("text"), + Type: types.ParameterTypeSecureString, + Name: awsv2.String(fmt.Sprintf("/copilot/%s/%s/secrets/db-password", mockApp, mockEnv)), + Value: awsv2.String("super secure password"), + Overwrite: awsv2.Bool(true), }).Return(nil, errors.New("some error")), ) }, @@ -370,9 +370,9 @@ func TestSSM_GetSecretValue(t *testing.T) { "error": { secretName: "asdf", setupMock: func(m *mocks.Mockapi) { - m.EXPECT().GetParameterWithContext(gomock.Any(), &ssm.GetParameterInput{ - Name: aws.String("asdf"), - WithDecryption: aws.Bool(true), + m.EXPECT().GetParameter(gomock.Any(), &ssm.GetParameterInput{ + Name: awsv2.String("asdf"), + WithDecryption: awsv2.Bool(true), }).Return(nil, errors.New("some error")) }, wantError: `get parameter "asdf" from SSM: some error`, @@ -380,12 +380,12 @@ func TestSSM_GetSecretValue(t *testing.T) { "success": { secretName: "asdf", setupMock: func(m *mocks.Mockapi) { - m.EXPECT().GetParameterWithContext(gomock.Any(), &ssm.GetParameterInput{ - Name: aws.String("asdf"), - WithDecryption: aws.Bool(true), + m.EXPECT().GetParameter(gomock.Any(), &ssm.GetParameterInput{ + Name: awsv2.String("asdf"), + WithDecryption: awsv2.Bool(true), }).Return(&ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ - Value: aws.String("hi"), + Parameter: &types.Parameter{ + Value: awsv2.String("hi"), }, }, nil) }, diff --git a/internal/pkg/aws/stepfunctions/mocks/mock_stepfunctions.go b/internal/pkg/aws/stepfunctions/mocks/mock_stepfunctions.go index 5a240e2da67..bb975aecf64 100644 --- a/internal/pkg/aws/stepfunctions/mocks/mock_stepfunctions.go +++ b/internal/pkg/aws/stepfunctions/mocks/mock_stepfunctions.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - sfn "github.com/aws/aws-sdk-go/service/sfn" + sfn "github.com/aws/aws-sdk-go-v2/service/sfn" gomock "github.com/golang/mock/gomock" ) @@ -35,31 +36,41 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeStateMachine mocks base method. -func (m *Mockapi) DescribeStateMachine(input *sfn.DescribeStateMachineInput) (*sfn.DescribeStateMachineOutput, error) { +func (m *Mockapi) DescribeStateMachine(ctx context.Context, input *sfn.DescribeStateMachineInput, opts ...func(*sfn.Options)) (*sfn.DescribeStateMachineOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeStateMachine", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStateMachine", varargs...) ret0, _ := ret[0].(*sfn.DescribeStateMachineOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeStateMachine indicates an expected call of DescribeStateMachine. -func (mr *MockapiMockRecorder) DescribeStateMachine(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeStateMachine(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStateMachine", reflect.TypeOf((*Mockapi)(nil).DescribeStateMachine), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStateMachine", reflect.TypeOf((*Mockapi)(nil).DescribeStateMachine), varargs...) } // StartExecution mocks base method. -func (m *Mockapi) StartExecution(input *sfn.StartExecutionInput) (*sfn.StartExecutionOutput, error) { +func (m *Mockapi) StartExecution(ctx context.Context, input *sfn.StartExecutionInput, opts ...func(*sfn.Options)) (*sfn.StartExecutionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartExecution", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "StartExecution", varargs...) ret0, _ := ret[0].(*sfn.StartExecutionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // StartExecution indicates an expected call of StartExecution. -func (mr *MockapiMockRecorder) StartExecution(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) StartExecution(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartExecution", reflect.TypeOf((*Mockapi)(nil).StartExecution), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartExecution", reflect.TypeOf((*Mockapi)(nil).StartExecution), varargs...) } diff --git a/internal/pkg/aws/stepfunctions/stepfunctions.go b/internal/pkg/aws/stepfunctions/stepfunctions.go index 2fdc79cee2d..d7607d35362 100644 --- a/internal/pkg/aws/stepfunctions/stepfunctions.go +++ b/internal/pkg/aws/stepfunctions/stepfunctions.go @@ -5,16 +5,16 @@ package stepfunctions 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/sfn" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/sfn" ) type api interface { - DescribeStateMachine(input *sfn.DescribeStateMachineInput) (*sfn.DescribeStateMachineOutput, error) - StartExecution(input *sfn.StartExecutionInput) (*sfn.StartExecutionOutput, error) + DescribeStateMachine(ctx context.Context, input *sfn.DescribeStateMachineInput, opts ...func(*sfn.Options)) (*sfn.DescribeStateMachineOutput, error) + StartExecution(ctx context.Context, input *sfn.StartExecutionInput, opts ...func(*sfn.Options)) (*sfn.StartExecutionOutput, error) } // StepFunctions wraps an AWS StepFunctions client. @@ -22,29 +22,29 @@ type StepFunctions struct { client api } -// New returns StepFunctions configured against the input session. -func New(s *session.Session) *StepFunctions { +// New returns StepFunctions configured against the input SDK v2 config. +func New(cfg awsv2.Config) *StepFunctions { return &StepFunctions{ - client: sfn.New(s), + client: sfn.NewFromConfig(cfg), } } // StateMachineDefinition returns the JSON-based state machine definition. func (s *StepFunctions) StateMachineDefinition(stateMachineARN string) (string, error) { - out, err := s.client.DescribeStateMachine(&sfn.DescribeStateMachineInput{ - StateMachineArn: aws.String(stateMachineARN), + out, err := s.client.DescribeStateMachine(context.Background(), &sfn.DescribeStateMachineInput{ + StateMachineArn: awsv2.String(stateMachineARN), }) if err != nil { return "", fmt.Errorf("describe state machine: %w", err) } - return aws.StringValue(out.Definition), nil + return awsv2.ToString(out.Definition), nil } -//Execute starts a state machine execution. +// Execute starts a state machine execution. func (s *StepFunctions) Execute(arn string) error { - _, err := s.client.StartExecution(&sfn.StartExecutionInput{ - StateMachineArn: aws.String(arn), + _, err := s.client.StartExecution(context.Background(), &sfn.StartExecutionInput{ + StateMachineArn: awsv2.String(arn), }) if err != nil { return fmt.Errorf("execute state machine %s: %w", arn, err) diff --git a/internal/pkg/aws/stepfunctions/stepfunctions_test.go b/internal/pkg/aws/stepfunctions/stepfunctions_test.go index bd6a5585df0..9422c4ed482 100644 --- a/internal/pkg/aws/stepfunctions/stepfunctions_test.go +++ b/internal/pkg/aws/stepfunctions/stepfunctions_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/sfn" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/sfn" "github.com/stretchr/testify/require" @@ -30,8 +30,8 @@ func TestStepFunctions_StateMachineDefinition(t *testing.T) { "fail to describe state machine": { inStateMachineARN: "ninth inning", mockStepFunctionsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeStateMachine(&sfn.DescribeStateMachineInput{ - StateMachineArn: aws.String("ninth inning"), + m.EXPECT().DescribeStateMachine(gomock.Any(), &sfn.DescribeStateMachineInput{ + StateMachineArn: awsv2.String("ninth inning"), }).Return(nil, errors.New("some error")) }, wantedError: errors.New("describe state machine: some error"), @@ -39,10 +39,10 @@ func TestStepFunctions_StateMachineDefinition(t *testing.T) { "success": { inStateMachineARN: "ninth inning", mockStepFunctionsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeStateMachine(&sfn.DescribeStateMachineInput{ - StateMachineArn: aws.String("ninth inning"), + m.EXPECT().DescribeStateMachine(gomock.Any(), &sfn.DescribeStateMachineInput{ + StateMachineArn: awsv2.String("ninth inning"), }).Return(&sfn.DescribeStateMachineOutput{ - Definition: aws.String("{\n \"Version\": \"42\",\n \"Comment\": \"very important comment\"\n}"), + Definition: awsv2.String("{\n \"Version\": \"42\",\n \"Comment\": \"very important comment\"\n}"), }, nil) }, wantedDefinition: "{\n \"Version\": \"42\",\n \"Comment\": \"very important comment\"\n}", @@ -82,8 +82,8 @@ func TestStepFunctions_Execute(t *testing.T) { "fail to execute state machine": { inStateMachineARN: "forca barca", mockStepFunctionsClient: func(m *mocks.Mockapi) { - m.EXPECT().StartExecution(&sfn.StartExecutionInput{ - StateMachineArn: aws.String("forca barca"), + m.EXPECT().StartExecution(gomock.Any(), &sfn.StartExecutionInput{ + StateMachineArn: awsv2.String("forca barca"), }).Return(nil, errors.New("some error")) }, wantedError: errors.New("execute state machine forca barca: some error"), @@ -91,10 +91,10 @@ func TestStepFunctions_Execute(t *testing.T) { "success": { inStateMachineARN: "forca barca", mockStepFunctionsClient: func(m *mocks.Mockapi) { - m.EXPECT().StartExecution(&sfn.StartExecutionInput{ - StateMachineArn: aws.String("forca barca"), + m.EXPECT().StartExecution(gomock.Any(), &sfn.StartExecutionInput{ + StateMachineArn: awsv2.String("forca barca"), }).Return(&sfn.StartExecutionOutput{ - ExecutionArn: aws.String("forca barca"), + ExecutionArn: awsv2.String("forca barca"), StartDate: func() *time.Time { t := time.Now(); return &t }(), }, nil) }, diff --git a/internal/pkg/cli/app_delete.go b/internal/pkg/cli/app_delete.go index b12047f0de2..936c9875cff 100644 --- a/internal/pkg/cli/app_delete.go +++ b/internal/pkg/cli/app_delete.go @@ -8,9 +8,7 @@ import ( "fmt" "os" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/aws/s3" @@ -21,9 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -80,7 +76,10 @@ func newDeleteAppOpts(vars deleteAppVars) (*deleteAppOpts, error) { return nil, fmt.Errorf("default session: %w", err) } prompter := prompt.New() - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } return &deleteAppOpts{ deleteAppVars: vars, spinner: termprogress.NewSpinner(log.DiagnosticWriter), @@ -91,7 +90,7 @@ func newDeleteAppOpts(vars deleteAppVars) (*deleteAppOpts, error) { s3: func(session *session.Session) bucketEmptier { return s3.New(session) }, - pipelineLister: deploy.NewPipelineStore(rg.New(defaultSession)), + pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), sel: selector.NewAppEnvSelector(prompter, store), svcDeleteExecutor: func(appName, svcName string) (executor, error) { opts, err := newDeleteSvcOpts(deleteSvcVars{ diff --git a/internal/pkg/cli/app_init.go b/internal/pkg/cli/app_init.go index cb084c06add..eb7d153b3dc 100644 --- a/internal/pkg/cli/app_init.go +++ b/internal/pkg/cli/app_init.go @@ -72,7 +72,8 @@ func newInitAppOpts(vars initAppVars) (*initAppOpts, error) { return nil, fmt.Errorf("default session: %w", err) } fs := afero.NewOsFs() - identity := identity.New(sess) + cfg := v2ConfigFromSessionRegion(sess) + identity := identity.New(cfg) iamClient := iam.New(sess) return &initAppOpts{ initAppVars: vars, diff --git a/internal/pkg/cli/app_list.go b/internal/pkg/cli/app_list.go index ed782c63f49..1eb223f8550 100644 --- a/internal/pkg/cli/app_list.go +++ b/internal/pkg/cli/app_list.go @@ -8,13 +8,7 @@ import ( "io" "os" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/spf13/cobra" ) @@ -53,7 +47,11 @@ func buildAppListCommand() *cobra.Command { if err != nil { return fmt.Errorf("default session: %v", err) } - opts.store = config.NewSSMStore(identity.New(sess), ssm.New(sess), aws.StringValue(sess.Config.Region)) + store, err := newSSMConfigStore(sess) + if err != nil { + return err + } + opts.store = store return opts.Execute() }), } diff --git a/internal/pkg/cli/app_show.go b/internal/pkg/cli/app_show.go index 3538eb6b070..1db93d23fcc 100644 --- a/internal/pkg/cli/app_show.go +++ b/internal/pkg/cli/app_show.go @@ -7,10 +7,7 @@ import ( "context" "fmt" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "io" "sort" @@ -59,7 +56,10 @@ func newShowAppOpts(vars showAppVars) (*showAppOpts, error) { if err != nil { return nil, fmt.Errorf("default session: %w", err) } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) @@ -70,8 +70,8 @@ func newShowAppOpts(vars showAppVars) (*showAppOpts, error) { w: log.OutputWriter, sel: selector.NewAppEnvSelector(prompt.New(), store), deployStore: deployStore, - codepipeline: codepipeline.New(defaultSession), - pipelineLister: deploy.NewPipelineStore(rg.New(defaultSession)), + codepipeline: codepipeline.New(defaultSession, v2ConfigFromSessionRegion(defaultSession)), + pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), newVersionGetter: func(s string) (versionGetter, error) { d, err := describe.NewAppDescriber(s) if err != nil { diff --git a/internal/pkg/cli/app_upgrade.go b/internal/pkg/cli/app_upgrade.go index 857398b356c..81c8002b80e 100644 --- a/internal/pkg/cli/app_upgrade.go +++ b/internal/pkg/cli/app_upgrade.go @@ -7,9 +7,6 @@ import ( "fmt" "os" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/route53" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" @@ -61,11 +58,15 @@ func newAppUpgradeOpts(vars appUpgradeVars) (*appUpgradeOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(sess), ssm.New(sess), aws.StringValue(sess.Config.Region)) + store, err := newSSMConfigStore(sess) + if err != nil { + return nil, err + } + cfg := v2ConfigFromSessionRegion(sess) return &appUpgradeOpts{ appUpgradeVars: vars, store: store, - identity: identity.New(sess), + identity: identity.New(cfg), route53: route53.New(sess), sel: selector.NewAppEnvSelector(prompt.New(), store), upgrader: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), diff --git a/internal/pkg/cli/config_store.go b/internal/pkg/cli/config_store.go new file mode 100644 index 00000000000..2e8af899c92 --- /dev/null +++ b/internal/pkg/cli/config_store.go @@ -0,0 +1,27 @@ +package cli + +import ( + "context" + "fmt" + + "github.com/aproint/copilot-cli/internal/pkg/aws/identity" + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" + "github.com/aproint/copilot-cli/internal/pkg/config" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ssm" +) + +func newSSMConfigStore(sess *session.Session) (*config.Store, error) { + cfg, err := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) + if err != nil { + return nil, fmt.Errorf("create default config: %w", err) + } + return config.NewSSMStore(identity.New(cfg), ssm.New(sess), aws.StringValue(sess.Config.Region)), nil +} + +func v2ConfigFromSessionRegion(sess *session.Session) awsv2.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) + return cfg +} diff --git a/internal/pkg/cli/deploy.go b/internal/pkg/cli/deploy.go index c154b7553c8..a08997f8c90 100644 --- a/internal/pkg/cli/deploy.go +++ b/internal/pkg/cli/deploy.go @@ -15,13 +15,11 @@ import ( "github.com/dustin/go-humanize" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/dustin/go-humanize/english" "github.com/spf13/afero" "github.com/spf13/cobra" "github.com/aproint/copilot-cli/cmd/copilot/template" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/cli/group" "github.com/aproint/copilot-cli/internal/pkg/config" @@ -120,7 +118,10 @@ func newDeployOpts(vars deployVars) (*deployOpts, error) { if err != nil { return nil, fmt.Errorf("default session: %v", err) } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err diff --git a/internal/pkg/cli/deploy/aws_config.go b/internal/pkg/cli/deploy/aws_config.go new file mode 100644 index 00000000000..0a06a56e74b --- /dev/null +++ b/internal/pkg/cli/deploy/aws_config.go @@ -0,0 +1,15 @@ +package deploy + +import ( + "context" + + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" + "github.com/aws/aws-sdk-go-v2/aws" + awsv1 "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" +) + +func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), awsv1.StringValue(sess.Config.Region)) + return cfg +} diff --git a/internal/pkg/cli/deploy/backend.go b/internal/pkg/cli/deploy/backend.go index 5f1d0717657..a95e9c9942d 100644 --- a/internal/pkg/cli/deploy/backend.go +++ b/internal/pkg/cli/deploy/backend.go @@ -130,7 +130,7 @@ func (d *backendSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) ( return &svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return ecs.New(s) + return ecs.New(s, v2ConfigFromSessionRegion(s)) }), }, nil } diff --git a/internal/pkg/cli/deploy/lbws.go b/internal/pkg/cli/deploy/lbws.go index 469467a1982..8e5a7d7727a 100644 --- a/internal/pkg/cli/deploy/lbws.go +++ b/internal/pkg/cli/deploy/lbws.go @@ -175,7 +175,7 @@ func (d *lbWebSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) (*s return &svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return ecs.New(s) + return ecs.New(s, v2ConfigFromSessionRegion(s)) }), }, nil } diff --git a/internal/pkg/cli/deploy/rdws.go b/internal/pkg/cli/deploy/rdws.go index 31688970662..8f29a80ed16 100644 --- a/internal/pkg/cli/deploy/rdws.go +++ b/internal/pkg/cli/deploy/rdws.go @@ -166,7 +166,7 @@ func (d *rdwsDeployer) stackConfiguration(in *StackRuntimeConfiguration) (*rdwsS svcStackConfigurationOutput: svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return apprunner.New(s) + return apprunner.New(s, v2ConfigFromSessionRegion(s)) }), }, }, nil @@ -180,7 +180,7 @@ func (d *rdwsDeployer) stackConfiguration(in *StackRuntimeConfiguration) (*rdwsS svcStackConfigurationOutput: svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return apprunner.New(s) + return apprunner.New(s, v2ConfigFromSessionRegion(s)) }), }, rdSvcAlias: aws.StringValue(d.rdwsMft.Alias), diff --git a/internal/pkg/cli/deploy/worker.go b/internal/pkg/cli/deploy/worker.go index af074d0a715..b856dd5c3fa 100644 --- a/internal/pkg/cli/deploy/worker.go +++ b/internal/pkg/cli/deploy/worker.go @@ -199,7 +199,7 @@ func (d *workerSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) (* svcStackConfigurationOutput: svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return ecs.New(s) + return ecs.New(s, v2ConfigFromSessionRegion(s)) }), }, subscriptions: subs, diff --git a/internal/pkg/cli/deploy/workload.go b/internal/pkg/cli/deploy/workload.go index 4af70217d2c..02e908ebb8a 100644 --- a/internal/pkg/cli/deploy/workload.go +++ b/internal/pkg/cli/deploy/workload.go @@ -258,6 +258,10 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { if err != nil { return nil, fmt.Errorf("create default: %w", err) } + defaultConfig, err := in.SessionProvider.DefaultConfig(context.Background()) + if err != nil { + return nil, fmt.Errorf("create default config: %w", err) + } envSession, err := in.SessionProvider.FromRole(in.Env.ManagerRoleARN, in.Env.Region) if err != nil { return nil, fmt.Errorf("create env session with region %s: %w", in.Env.Region, err) @@ -284,7 +288,7 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { repoName := RepoName(in.App.Name, in.Name) repository := repository.NewWithURI( ecr.New(defaultSessEnvRegion), repoName, resources.RepositoryURLs[in.Name]) - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store := config.NewSSMStore(identity.New(defaultConfig), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ App: in.App.Name, Env: in.Env.Name, diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index addcd911670..ca4c3749dfb 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -11,11 +11,9 @@ import ( "strings" "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/ssm" awscfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/iam" @@ -102,7 +100,10 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { if err != nil { return nil, fmt.Errorf("default session: %v", err) } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompter := prompt.New() return &deleteEnvOpts{ @@ -128,8 +129,8 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), sess) o.deployer = cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) o.envDeleterFromApp = cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) - o.pipelineGetter = codepipeline.New(defaultSess) - o.deployedPipelineLister = deploy.NewPipelineStore(rg.New(defaultSess)) + o.pipelineGetter = codepipeline.New(defaultSess, v2ConfigFromSessionRegion(defaultSess)) + o.deployedPipelineLister = deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSess))) return nil }, }, nil diff --git a/internal/pkg/cli/env_deploy.go b/internal/pkg/cli/env_deploy.go index 9e7ec82aef2..fa01791b027 100644 --- a/internal/pkg/cli/env_deploy.go +++ b/internal/pkg/cli/env_deploy.go @@ -24,8 +24,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" "golang.org/x/mod/semver" @@ -77,7 +75,10 @@ func newEnvDeployOpts(vars deployEnvVars) (*deployEnvOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } fs := afero.NewOsFs() ws, err := workspace.Use(fs) if err != nil { @@ -101,7 +102,7 @@ func newEnvDeployOpts(vars deployEnvVars) (*deployEnvOpts, error) { fs: fs, ws: ws, - identity: identity.New(defaultSess), + identity: identity.New(v2ConfigFromSessionRegion(defaultSess)), templateVersion: version.LatestTemplateVersion(), newInterpolator: newManifestInterpolator, } diff --git a/internal/pkg/cli/env_init.go b/internal/pkg/cli/env_init.go index 08196e22b78..be526963cf6 100644 --- a/internal/pkg/cli/env_init.go +++ b/internal/pkg/cli/env_init.go @@ -21,8 +21,6 @@ import ( "github.com/spf13/afero" "golang.org/x/mod/semver" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" "github.com/aproint/copilot-cli/internal/pkg/aws/iam" @@ -195,7 +193,10 @@ func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } prompter := prompt.New() ws, err := workspace.Use(afero.NewOsFs()) if err != nil { @@ -206,7 +207,7 @@ func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { sessProvider: sessProvider, store: store, appDeployer: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), - identity: identity.New(defaultSession), + identity: identity.New(v2ConfigFromSessionRegion(defaultSession)), prog: termprogress.NewSpinner(log.DiagnosticWriter), prompt: prompter, selCreds: func() (credsSelector, error) { @@ -353,7 +354,7 @@ func (o *initEnvOpts) RecommendActions() error { func (o *initEnvOpts) initRuntimeClients() error { // Initialize environment clients if not set. if o.envIdentity == nil { - o.envIdentity = identity.New(o.sess) + o.envIdentity = identity.New(v2ConfigFromSessionRegion(o.sess)) } if o.envDeployer == nil { o.envDeployer = deploycfn.New(o.sess, deploycfn.WithProgressTracker(os.Stderr)) diff --git a/internal/pkg/cli/env_list.go b/internal/pkg/cli/env_list.go index 422b534f363..34bd01b607c 100644 --- a/internal/pkg/cli/env_list.go +++ b/internal/pkg/cli/env_list.go @@ -10,10 +10,7 @@ import ( "os" "strings" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" @@ -46,7 +43,10 @@ func newListEnvOpts(vars listEnvVars) (*listEnvOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompter := prompt.New() return &listEnvOpts{ listEnvVars: vars, diff --git a/internal/pkg/cli/env_override.go b/internal/pkg/cli/env_override.go index bd3f40317e6..bfb6be73ed4 100644 --- a/internal/pkg/cli/env_override.go +++ b/internal/pkg/cli/env_override.go @@ -8,16 +8,12 @@ import ( "fmt" "slices" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -41,7 +37,10 @@ func newOverrideEnvOpts(vars overrideVars) (*overrideEnvOpts, error) { if err != nil { return nil, fmt.Errorf("default session: %v", err) } - cfgStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + cfgStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } vars.requiresEnv = true prompt := prompt.New() cmd := &overrideEnvOpts{ diff --git a/internal/pkg/cli/env_package.go b/internal/pkg/cli/env_package.go index e1ade5a0fcd..b1581bf19fa 100644 --- a/internal/pkg/cli/env_package.go +++ b/internal/pkg/cli/env_package.go @@ -27,8 +27,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/cobra" ) @@ -96,7 +94,11 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { if err != nil { return nil, err } - cfgStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + cfgStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } + cfg := v2ConfigFromSessionRegion(defaultSess) opts := &packageEnvOpts{ packageEnvVars: vars, @@ -104,7 +106,7 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { cfgStore: cfgStore, ws: ws, sel: selector.NewLocalEnvironmentSelector(prompt.New(), cfgStore, ws), - caller: identity.New(defaultSess), + caller: identity.New(cfg), fs: fs, tplWriter: os.Stdout, paramsWriter: discardFile{}, diff --git a/internal/pkg/cli/env_show.go b/internal/pkg/cli/env_show.go index d50c26b096b..5015b2a01ff 100644 --- a/internal/pkg/cli/env_show.go +++ b/internal/pkg/cli/env_show.go @@ -7,12 +7,8 @@ import ( "fmt" "io" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/term/color" @@ -53,7 +49,10 @@ func newShowEnvOpts(vars showEnvVars) (*showEnvOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { diff --git a/internal/pkg/cli/init.go b/internal/pkg/cli/init.go index 6409889c77e..788ac3f34cf 100644 --- a/internal/pkg/cli/init.go +++ b/internal/pkg/cli/init.go @@ -35,7 +35,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -108,7 +107,10 @@ func newInitOpts(vars initVars) (*initOpts, error) { if err != nil { return nil, err } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompt := prompt.New() sel := selector.NewConfigSelector(prompt, configStore) deployStore, err := deploy.NewStore(sessProvider, configStore) @@ -117,7 +119,7 @@ func newInitOpts(vars initVars) (*initOpts, error) { } snsSel := selector.NewDeploySelect(prompt, configStore, deployStore) spin := termprogress.NewSpinner(log.DiagnosticWriter) - id := identity.New(defaultSess) + id := identity.New(v2ConfigFromSessionRegion(defaultSess)) deployer := cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) iamClient := iam.New(defaultSess) initAppCmd := &initAppOpts{ diff --git a/internal/pkg/cli/interfaces.go b/internal/pkg/cli/interfaces.go index 40b4255d408..bd9b9cbf8b0 100644 --- a/internal/pkg/cli/interfaces.go +++ b/internal/pkg/cli/interfaces.go @@ -35,6 +35,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/session" ) @@ -207,10 +208,12 @@ type defaultSessionProvider interface { type regionalSessionProvider interface { DefaultWithRegion(region string) (*session.Session, error) + DefaultConfigWithRegion(ctx context.Context, region string) (awsv2.Config, error) } type sessionFromRoleProvider interface { FromRole(roleARN string, region string) (*session.Session, error) + ConfigFromRole(ctx context.Context, roleARN string, region string) (awsv2.Config, error) } type sessionFromStaticProvider interface { diff --git a/internal/pkg/cli/job_delete.go b/internal/pkg/cli/job_delete.go index f10511f5393..6c4a5d7bafc 100644 --- a/internal/pkg/cli/job_delete.go +++ b/internal/pkg/cli/job_delete.go @@ -9,10 +9,6 @@ import ( "os" "slices" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -79,7 +75,10 @@ func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } prompter := prompt.New() return &deleteJobOpts{ deleteJobVars: vars, @@ -97,7 +96,7 @@ func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { return ecr.New(session) }, newTaskStopper: func(session *session.Session) taskStopper { - return ecs.New(session) + return ecs.New(session, v2ConfigFromSessionRegion(session)) }, }, nil } diff --git a/internal/pkg/cli/job_deploy.go b/internal/pkg/cli/job_deploy.go index 6366151c793..6c2abcdb216 100644 --- a/internal/pkg/cli/job_deploy.go +++ b/internal/pkg/cli/job_deploy.go @@ -11,9 +11,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" deploycfn "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" @@ -71,7 +69,10 @@ func newJobDeployOpts(vars deployWkldVars) (*deployJobOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err @@ -307,7 +308,7 @@ func (o *deployJobOpts) configureClients() error { o.envSess = envSess // client to retrieve caller identity. - caller, err := identity.New(defaultSess).Get() + caller, err := identity.New(v2ConfigFromSessionRegion(defaultSess)).Get() if err != nil { return fmt.Errorf("get identity: %w", err) } diff --git a/internal/pkg/cli/job_init.go b/internal/pkg/cli/job_init.go index 5d26f08a023..5b06591f598 100644 --- a/internal/pkg/cli/job_init.go +++ b/internal/pkg/cli/job_init.go @@ -8,12 +8,9 @@ import ( "fmt" "os" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerfile" @@ -103,7 +100,10 @@ func newInitJobOpts(vars initJobVars) (*initJobOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(sess), ssm.New(sess), aws.StringValue(sess.Config.Region)) + store, err := newSSMConfigStore(sess) + if err != nil { + return nil, err + } jobInitter := &initialize.WorkloadInitializer{ Store: store, Ws: ws, diff --git a/internal/pkg/cli/job_list.go b/internal/pkg/cli/job_list.go index bb1bb2cbf80..a98b223d9c4 100644 --- a/internal/pkg/cli/job_list.go +++ b/internal/pkg/cli/job_list.go @@ -7,14 +7,10 @@ import ( "fmt" "os" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/aproint/copilot-cli/internal/pkg/cli/list" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" @@ -38,8 +34,7 @@ func newListJobOpts(vars listWkldVars) (*listJobOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) - + store, err := newSSMConfigStore(defaultSession) if err != nil { return nil, err } diff --git a/internal/pkg/cli/job_logs.go b/internal/pkg/cli/job_logs.go index 828d21b3345..1444876b5ec 100644 --- a/internal/pkg/cli/job_logs.go +++ b/internal/pkg/cli/job_logs.go @@ -7,9 +7,6 @@ import ( "errors" "fmt" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -51,7 +48,10 @@ func newJobLogOpts(vars jobLogsVars) (*jobLogsOpts, error) { if err != nil { return nil, err } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { diff --git a/internal/pkg/cli/job_package.go b/internal/pkg/cli/job_package.go index 1ae530b8483..a115bc02cbc 100644 --- a/internal/pkg/cli/job_package.go +++ b/internal/pkg/cli/job_package.go @@ -8,13 +8,9 @@ import ( "os" "slices" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/exec" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" @@ -61,7 +57,10 @@ func newPackageJobOpts(vars packageJobVars) (*packageJobOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } fs := afero.NewOsFs() ws, err := workspace.Use(fs) if err != nil { diff --git a/internal/pkg/cli/job_run.go b/internal/pkg/cli/job_run.go index 7b03af168f4..a0bb23711db 100644 --- a/internal/pkg/cli/job_run.go +++ b/internal/pkg/cli/job_run.go @@ -7,7 +7,6 @@ import ( "fmt" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/aws/stepfunctions" "github.com/aproint/copilot-cli/internal/pkg/config" @@ -18,9 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -53,7 +50,10 @@ func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { if err != nil { return nil, err } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err @@ -81,7 +81,7 @@ func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { Job: opts.jobName, CFN: cloudformation.New(sess), - StateMachine: stepfunctions.New(sess), + StateMachine: stepfunctions.New(v2ConfigFromSessionRegion(sess)), }), nil } opts.newEnvCompatibilityChecker = func() (versionCompatibilityChecker, error) { diff --git a/internal/pkg/cli/mocks/mock_interfaces.go b/internal/pkg/cli/mocks/mock_interfaces.go index 4be119ba842..9ac0805d1e2 100644 --- a/internal/pkg/cli/mocks/mock_interfaces.go +++ b/internal/pkg/cli/mocks/mock_interfaces.go @@ -35,6 +35,7 @@ import ( prompt "github.com/aproint/copilot-cli/internal/pkg/term/prompt" selector "github.com/aproint/copilot-cli/internal/pkg/term/selector" workspace "github.com/aproint/copilot-cli/internal/pkg/workspace" + aws "github.com/aws/aws-sdk-go-v2/aws" session "github.com/aws/aws-sdk-go/aws/session" cloudformation1 "github.com/aws/aws-sdk-go/service/cloudformation" gomock "github.com/golang/mock/gomock" @@ -1960,6 +1961,21 @@ func (m *MockregionalSessionProvider) EXPECT() *MockregionalSessionProviderMockR return m.recorder } +// DefaultConfigWithRegion mocks base method. +func (m *MockregionalSessionProvider) DefaultConfigWithRegion(ctx context.Context, region string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultConfigWithRegion", ctx, region) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DefaultConfigWithRegion indicates an expected call of DefaultConfigWithRegion. +func (mr *MockregionalSessionProviderMockRecorder) DefaultConfigWithRegion(ctx, region interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfigWithRegion", reflect.TypeOf((*MockregionalSessionProvider)(nil).DefaultConfigWithRegion), ctx, region) +} + // DefaultWithRegion mocks base method. func (m *MockregionalSessionProvider) DefaultWithRegion(region string) (*session.Session, error) { m.ctrl.T.Helper() @@ -1998,6 +2014,21 @@ func (m *MocksessionFromRoleProvider) EXPECT() *MocksessionFromRoleProviderMockR return m.recorder } +// ConfigFromRole mocks base method. +func (m *MocksessionFromRoleProvider) ConfigFromRole(ctx context.Context, roleARN, region string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFromRole", ctx, roleARN, region) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConfigFromRole indicates an expected call of ConfigFromRole. +func (mr *MocksessionFromRoleProviderMockRecorder) ConfigFromRole(ctx, roleARN, region interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MocksessionFromRoleProvider)(nil).ConfigFromRole), ctx, roleARN, region) +} + // FromRole mocks base method. func (m *MocksessionFromRoleProvider) FromRole(roleARN, region string) (*session.Session, error) { m.ctrl.T.Helper() @@ -2112,6 +2143,21 @@ func (m *MocksessionProvider) EXPECT() *MocksessionProviderMockRecorder { return m.recorder } +// ConfigFromRole mocks base method. +func (m *MocksessionProvider) ConfigFromRole(ctx context.Context, roleARN, region string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFromRole", ctx, roleARN, region) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConfigFromRole indicates an expected call of ConfigFromRole. +func (mr *MocksessionProviderMockRecorder) ConfigFromRole(ctx, roleARN, region interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromRole), ctx, roleARN, region) +} + // Default mocks base method. func (m *MocksessionProvider) Default() (*session.Session, error) { m.ctrl.T.Helper() @@ -2127,6 +2173,21 @@ func (mr *MocksessionProviderMockRecorder) Default() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Default", reflect.TypeOf((*MocksessionProvider)(nil).Default)) } +// DefaultConfigWithRegion mocks base method. +func (m *MocksessionProvider) DefaultConfigWithRegion(ctx context.Context, region string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultConfigWithRegion", ctx, region) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DefaultConfigWithRegion indicates an expected call of DefaultConfigWithRegion. +func (mr *MocksessionProviderMockRecorder) DefaultConfigWithRegion(ctx, region interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfigWithRegion", reflect.TypeOf((*MocksessionProvider)(nil).DefaultConfigWithRegion), ctx, region) +} + // DefaultWithRegion mocks base method. func (m *MocksessionProvider) DefaultWithRegion(region string) (*session.Session, error) { m.ctrl.T.Helper() diff --git a/internal/pkg/cli/pipeline_delete.go b/internal/pkg/cli/pipeline_delete.go index bf5c6cec26b..e92146f6754 100644 --- a/internal/pkg/cli/pipeline_delete.go +++ b/internal/pkg/cli/pipeline_delete.go @@ -11,11 +11,9 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/secretsmanager" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/term/color" @@ -25,7 +23,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -86,17 +83,21 @@ func newDeletePipelineOpts(vars deletePipelineVars) (*deletePipelineOpts, error) if err != nil { return nil, fmt.Errorf("default session: %w", err) } - ssmStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + ssmStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompter := prompt.New() - codepipeline := codepipeline.New(defaultSess) - pipelineLister := deploy.NewPipelineStore(rg.New(defaultSess)) + v2Config := v2ConfigFromSessionRegion(defaultSess) + codepipeline := codepipeline.New(defaultSess, v2Config) + pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) opts := &deletePipelineOpts{ deletePipelineVars: vars, codepipeline: codepipeline, prog: termprogress.NewSpinner(log.DiagnosticWriter), prompt: prompter, - secretsmanager: secretsmanager.New(defaultSess), + secretsmanager: secretsmanager.New(v2Config), pipelineDeployer: cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)), deployedPipelineLister: pipelineLister, ws: ws, diff --git a/internal/pkg/cli/pipeline_delete_test.go b/internal/pkg/cli/pipeline_delete_test.go index 75f4ef5b2d9..5dfbeb7457e 100644 --- a/internal/pkg/cli/pipeline_delete_test.go +++ b/internal/pkg/cli/pipeline_delete_test.go @@ -11,8 +11,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/secretsmanager" "github.com/aproint/copilot-cli/internal/pkg/deploy" + secretsmanagertypes "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types" "github.com/aws/aws-sdk-go/aws" - sdkSecretsmanager "github.com/aws/aws-sdk-go/service/secretsmanager" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/term/log" @@ -223,7 +223,7 @@ func TestDeletePipelineOpts_Execute(t *testing.T) { mockResp := &secretsmanager.DescribeSecretOutput{ CreatedDate: aws.Time(mockTime), Name: aws.String(testPipelineSecret), - Tags: []*sdkSecretsmanager.Tag{ + Tags: []secretsmanagertypes.Tag{ { Key: aws.String(deploy.AppTagKey), Value: aws.String(mockTime.UTC().Format(time.UnixDate)), @@ -233,7 +233,7 @@ func TestDeletePipelineOpts_Execute(t *testing.T) { mockBadResp := &secretsmanager.DescribeSecretOutput{ CreatedDate: aws.Time(mockTime), Name: aws.String(testPipelineSecret), - Tags: []*sdkSecretsmanager.Tag{ + Tags: []secretsmanagertypes.Tag{ { Key: aws.String("someOtherKey"), Value: aws.String(mockTime.UTC().Format(time.UnixDate)), diff --git a/internal/pkg/cli/pipeline_deploy.go b/internal/pkg/cli/pipeline_deploy.go index 5ab084b380b..0322212cea6 100644 --- a/internal/pkg/cli/pipeline_deploy.go +++ b/internal/pkg/cli/pipeline_deploy.go @@ -13,14 +13,12 @@ import ( "path/filepath" "strings" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "golang.org/x/mod/semver" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" awscloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" cs "github.com/aproint/copilot-cli/internal/pkg/aws/codestar" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" clideploy "github.com/aproint/copilot-cli/internal/pkg/cli/deploy" @@ -122,7 +120,11 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) if err != nil { return nil, fmt.Errorf("default session: %w", err) } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } + v2Config := v2ConfigFromSessionRegion(defaultSession) prompter := prompt.New() ws, err := workspace.Use(afero.NewOsFs()) @@ -146,7 +148,7 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) diffWriter: os.Stdout, sessProvider: sessProvider, sel: selector.NewWsPipelineSelector(prompter, ws), - codestar: cs.New(defaultSession), + codestar: cs.New(v2Config), templateVersion: version.LatestTemplateVersion(), pipelineStackConfig: func(in *deploy.CreatePipelineInput) stackConfiguration { return stack.NewPipelineStackConfig(in) @@ -189,7 +191,7 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) } opts.configureDeployedPipelineLister = func() deployedPipelineLister { // Initialize the client only after the appName is asked. - return deploy.NewPipelineStore(rg.New(defaultSession)) + return deploy.NewPipelineStore(rg.New(v2Config)) } opts.pipelineVersionGetter = func(appName, name string, isLegacy bool) (versionGetter, error) { return describe.NewPipelineStackDescriber(appName, name, isLegacy) diff --git a/internal/pkg/cli/pipeline_init.go b/internal/pkg/cli/pipeline_init.go index b453b2e575d..480c66f1794 100644 --- a/internal/pkg/cli/pipeline_init.go +++ b/internal/pkg/cli/pipeline_init.go @@ -16,9 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/dustin/go-humanize/english" "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -229,7 +227,11 @@ func newInitPipelineOpts(vars initPipelineVars) (*initPipelineOpts, error) { return nil, err } - ssmStore := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + ssmStore, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } + v2Config := v2ConfigFromSessionRegion(defaultSession) prompter := prompt.New() wsAppName := tryReadingAppName() @@ -240,7 +242,7 @@ func newInitPipelineOpts(vars initPipelineVars) (*initPipelineOpts, error) { return &initPipelineOpts{ initPipelineVars: vars, workspace: ws, - secretsmanager: secretsmanager.New(defaultSession), + secretsmanager: secretsmanager.New(v2Config), parser: template.New(), sessProvider: p, cfnClient: cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)), @@ -249,7 +251,7 @@ func newInitPipelineOpts(vars initPipelineVars) (*initPipelineOpts, error) { sel: selector.NewAppEnvSelector(prompter, ssmStore), runner: exec.NewCmd(), wsAppName: wsAppName, - pipelineLister: deploy.NewPipelineStore(rg.New(defaultSession)), + pipelineLister: deploy.NewPipelineStore(rg.New(v2Config)), }, nil } diff --git a/internal/pkg/cli/pipeline_list.go b/internal/pkg/cli/pipeline_list.go index f5809ccf619..157915bf4f1 100644 --- a/internal/pkg/cli/pipeline_list.go +++ b/internal/pkg/cli/pipeline_list.go @@ -13,18 +13,14 @@ import ( "sync" "time" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "golang.org/x/sync/errgroup" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/spf13/cobra" @@ -75,11 +71,15 @@ func newListPipelinesOpts(vars listPipelineVars) (*listPipelineOpts, error) { wsAppName = tryReadingAppName() } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } + v2Config := v2ConfigFromSessionRegion(defaultSession) prompter := prompt.New() return &listPipelineOpts{ listPipelineVars: vars, - pipelineLister: deploy.NewPipelineStore(rg.New(defaultSession)), + pipelineLister: deploy.NewPipelineStore(rg.New(v2Config)), prompt: prompter, sel: selector.NewConfigSelector(prompter, store), store: store, diff --git a/internal/pkg/cli/pipeline_override.go b/internal/pkg/cli/pipeline_override.go index 6c9705ba3e2..d7f718a23d1 100644 --- a/internal/pkg/cli/pipeline_override.go +++ b/internal/pkg/cli/pipeline_override.go @@ -7,16 +7,12 @@ import ( "fmt" "slices" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -43,12 +39,16 @@ func newOverridePipelineOpts(vars overrideVars) (*overridePipelineOpts, error) { } prompt := prompt.New() + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } cmd := &overridePipelineOpts{ overrideOpts: &overrideOpts{ overrideVars: vars, fs: fs, - cfgStore: config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)), + cfgStore: store, prompt: prompt, cfnPrompt: selector.NewCFNSelector(prompt), spinner: termprogress.NewSpinner(log.DiagnosticWriter), diff --git a/internal/pkg/cli/pipeline_package.go b/internal/pkg/cli/pipeline_package.go index ad36061ecf5..de5821543c4 100644 --- a/internal/pkg/cli/pipeline_package.go +++ b/internal/pkg/cli/pipeline_package.go @@ -11,7 +11,6 @@ import ( "os" "path/filepath" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" clideploy "github.com/aproint/copilot-cli/internal/pkg/cli/deploy" @@ -25,8 +24,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" ) @@ -62,7 +59,11 @@ func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, err if err != nil { return nil, fmt.Errorf("default session: %w", err) } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } + v2Config := v2ConfigFromSessionRegion(defaultSession) ws, err := workspace.Use(afero.NewOsFs()) if err != nil { @@ -113,7 +114,7 @@ func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, err svcBuffer: &bytes.Buffer{}, jobBuffer: &bytes.Buffer{}, configureDeployedPipelineLister: func() deployedPipelineLister { - return deploy.NewPipelineStore(rg.New(defaultSession)) + return deploy.NewPipelineStore(rg.New(v2Config)) }, } return opts, nil diff --git a/internal/pkg/cli/pipeline_show.go b/internal/pkg/cli/pipeline_show.go index 6bcc3524681..92c9fff4f49 100644 --- a/internal/pkg/cli/pipeline_show.go +++ b/internal/pkg/cli/pipeline_show.go @@ -11,14 +11,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/spf13/afero" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" @@ -69,9 +64,13 @@ func newShowPipelineOpts(vars showPipelineVars) (*showPipelineOpts, error) { if err != nil { return nil, fmt.Errorf("default session: %w", err) } - codepipeline := codepipeline.New(defaultSession) - pipelineLister := deploy.NewPipelineStore(rg.New(defaultSession)) - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } + v2Config := v2ConfigFromSessionRegion(defaultSession) + codepipeline := codepipeline.New(defaultSession, v2Config) + pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) prompter := prompt.New() opts := &showPipelineOpts{ showPipelineVars: vars, diff --git a/internal/pkg/cli/pipeline_status.go b/internal/pkg/cli/pipeline_status.go index facc719df0f..eb52e1f0cb2 100644 --- a/internal/pkg/cli/pipeline_status.go +++ b/internal/pkg/cli/pipeline_status.go @@ -11,14 +11,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/spf13/afero" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" @@ -68,9 +63,13 @@ func newPipelineStatusOpts(vars pipelineStatusVars) (*pipelineStatusOpts, error) if err != nil { return nil, fmt.Errorf("session: %w", err) } - codepipeline := codepipeline.New(session) - pipelineLister := deploy.NewPipelineStore(rg.New(session)) - store := config.NewSSMStore(identity.New(session), ssm.New(session), aws.StringValue(session.Config.Region)) + store, err := newSSMConfigStore(session) + if err != nil { + return nil, err + } + v2Config := v2ConfigFromSessionRegion(session) + codepipeline := codepipeline.New(session, v2Config) + pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) prompter := prompt.New() return &pipelineStatusOpts{ w: log.OutputWriter, diff --git a/internal/pkg/cli/run_local.go b/internal/pkg/cli/run_local.go index e1706f2b41d..2d50411afb7 100644 --- a/internal/pkg/cli/run_local.go +++ b/internal/pkg/cli/run_local.go @@ -24,7 +24,6 @@ import ( cmdtemplate "github.com/aproint/copilot-cli/cmd/copilot/template" "github.com/aproint/copilot-cli/internal/pkg/aws/ecr" awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/secretsmanager" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" @@ -157,7 +156,10 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { return nil, err } - store := config.NewSSMStore(identity.New(defaultSess), sdkssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { return nil, err @@ -189,18 +191,26 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { if err != nil { return fmt.Errorf("create default session with region %s: %w", o.targetEnv.Region, err) } + defaultConfigEnvRegion, err := o.sessProvider.DefaultConfigWithRegion(context.Background(), o.targetEnv.Region) + if err != nil { + return fmt.Errorf("create default config with region %s: %w", o.targetEnv.Region, err) + } o.envManagerSess, err = o.sessProvider.FromRole(o.targetEnv.ManagerRoleARN, o.targetEnv.Region) if err != nil { return fmt.Errorf("create env manager session %s: %w", o.targetEnv.Region, err) } + envManagerConfig, err := o.sessProvider.ConfigFromRole(context.Background(), o.targetEnv.ManagerRoleARN, o.targetEnv.Region) + if err != nil { + return fmt.Errorf("create env manager config %s: %w", o.targetEnv.Region, err) + } // EnvManagerRole has permissions to get task def and get SSM values. // However, it doesn't have permissions to get secrets from secrets manager, // so use the default sess and *hope* they have permissions. - o.ecsClient = ecs.New(o.envManagerSess) - o.ssm = ssm.New(o.envManagerSess) + o.ecsClient = ecs.New(o.envManagerSess, envManagerConfig) + o.ssm = ssm.New(envManagerConfig) o.ecsExecutor = awsecs.New(o.envManagerSess) - o.secretsManager = secretsmanager.New(defaultSessEnvRegion) + o.secretsManager = secretsmanager.New(defaultConfigEnvRegion) resources, err := cloudformation.New(o.sess, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(o.targetApp, o.targetEnv.Region) if err != nil { @@ -223,8 +233,8 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { app: o.appName, env: o.envName, wkld: o.wkldName, - ecs: ecs.New(o.envManagerSess), - rg: resourcegroups.New(o.envManagerSess), + ecs: ecs.New(o.envManagerSess, envManagerConfig), + rg: resourcegroups.New(envManagerConfig), rds: rds.New(o.envManagerSess), } envDesc, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ diff --git a/internal/pkg/cli/secret_init.go b/internal/pkg/cli/secret_init.go index c9a04c7227d..822b0444e35 100644 --- a/internal/pkg/cli/secret_init.go +++ b/internal/pkg/cli/secret_init.go @@ -4,12 +4,12 @@ package cli import ( + "context" "errors" "fmt" "sort" "strings" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/aws/ssm" "github.com/aproint/copilot-cli/internal/pkg/config" @@ -21,8 +21,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - awsssm "github.com/aws/aws-sdk-go/service/ssm" "github.com/dustin/go-humanize/english" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -85,7 +83,10 @@ func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), awsssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } prompter := prompt.New() opts := secretInitOpts{ secretInitVars: vars, @@ -115,11 +116,11 @@ func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { if err != nil { return err } - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return fmt.Errorf("create session from environment manager role %s in region %s: %w", env.ManagerRoleARN, env.Region, err) + return fmt.Errorf("create config from environment manager role %s in region %s: %w", env.ManagerRoleARN, env.Region, err) } - opts.secretPutters[envName] = ssm.New(sess) + opts.secretPutters[envName] = ssm.New(cfg) return nil } @@ -316,7 +317,7 @@ func (o *secretInitOpts) putSecretInEnv(secretName, envName, value string) error return err } - version := aws.Int64Value(out.Version) + version := out.Version if version != 1 { log.Successln(fmt.Sprintf("Secret %s already exists in environment %s. Overwritten.", name, color.HighlightUserInput(envName))) return nil diff --git a/internal/pkg/cli/secret_init_test.go b/internal/pkg/cli/secret_init_test.go index dce797ad337..793d5b9c73d 100644 --- a/internal/pkg/cli/secret_init_test.go +++ b/internal/pkg/cli/secret_init_test.go @@ -9,8 +9,6 @@ import ( "path/filepath" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/config" @@ -386,7 +384,7 @@ func TestSecretInitOpts_Execute(t *testing.T) { deploy.EnvTagKey: "test", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockSecretPutter.EXPECT().PutSecret(ssm.PutSecretInput{ Name: "/copilot/test-app/prod/secrets/db-password", @@ -397,7 +395,7 @@ func TestSecretInitOpts_Execute(t *testing.T) { deploy.EnvTagKey: "prod", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockEnvCompatibilityChecker.EXPECT().Version().Return("v1.10.0", nil).Times(2) }, @@ -418,7 +416,7 @@ func TestSecretInitOpts_Execute(t *testing.T) { deploy.EnvTagKey: "test", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockSecretPutter.EXPECT().PutSecret(ssm.PutSecretInput{ Name: "/copilot/test-app/prod/secrets/db-password", @@ -429,7 +427,7 @@ func TestSecretInitOpts_Execute(t *testing.T) { deploy.EnvTagKey: "prod", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockEnvCompatibilityChecker.EXPECT().Version().Return("v1.10.0", nil).Times(2) }, @@ -458,7 +456,7 @@ func TestSecretInitOpts_Execute(t *testing.T) { deploy.EnvTagKey: "prod", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockEnvCompatibilityChecker.EXPECT().Version().Return("v1.10.0", nil).Times(2) }, @@ -487,7 +485,7 @@ func TestSecretInitOpts_Execute(t *testing.T) { deploy.EnvTagKey: "prod", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockEnvCompatibilityChecker.EXPECT().Version().Return("v1.10.0", nil).Times(2) }, @@ -527,7 +525,7 @@ db-host: deploy.EnvTagKey: "prod", }, }).Return(&ssm.PutSecretOutput{ - Version: aws.Int64(1), + Version: 1, }, nil) m.mockSecretPutter.EXPECT().PutSecret(ssm.PutSecretInput{ Name: "/copilot/test-app/test/secrets/db-host", diff --git a/internal/pkg/cli/storage_init.go b/internal/pkg/cli/storage_init.go index 7b33fc7296d..56946dc182a 100644 --- a/internal/pkg/cli/storage_init.go +++ b/internal/pkg/cli/storage_init.go @@ -9,15 +9,11 @@ import ( "fmt" "strconv" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/dustin/go-humanize/english" "github.com/aproint/copilot-cli/internal/pkg/addon" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" @@ -202,7 +198,10 @@ func newStorageInitOpts(vars initStorageVars) (*initStorageOpts, error) { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } prompter := prompt.New() return &initStorageOpts{ initStorageVars: vars, diff --git a/internal/pkg/cli/svc_delete.go b/internal/pkg/cli/svc_delete.go index 34cd3535020..abb51b551ea 100644 --- a/internal/pkg/cli/svc_delete.go +++ b/internal/pkg/cli/svc_delete.go @@ -13,13 +13,10 @@ import ( clideploy "github.com/aproint/copilot-cli/internal/pkg/cli/deploy" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" awss3 "github.com/aproint/copilot-cli/internal/pkg/aws/s3" "github.com/aproint/copilot-cli/internal/pkg/cli/clean" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/s3" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/term/selector" @@ -81,7 +78,10 @@ func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } prompter := prompt.New() opts := &deleteSvcOpts{ deleteSvcVars: vars, @@ -101,7 +101,7 @@ func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { } opts.newSvcCleaner = func(sess *awssession.Session, env *config.Environment, manifestType string) cleaner { if manifestType == manifestinfo.StaticSiteType { - return clean.StaticSite(opts.appName, env.Name, opts.name, s3.New(sess), awss3.New(sess)) + return clean.StaticSite(opts.appName, env.Name, opts.name, s3.New(sess, v2ConfigFromSessionRegion(sess)), awss3.New(sess)) } return &clean.NoOp{} } diff --git a/internal/pkg/cli/svc_deploy.go b/internal/pkg/cli/svc_deploy.go index 2bf0a373c5c..cdbb9c5bdc1 100644 --- a/internal/pkg/cli/svc_deploy.go +++ b/internal/pkg/cli/svc_deploy.go @@ -20,9 +20,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "golang.org/x/mod/semver" @@ -105,7 +103,10 @@ func newSvcDeployOpts(vars deployWkldVars) (*deploySvcOpts, error) { return nil, err } - store := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + store, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } prompter := prompt.New() opts := &deploySvcOpts{ @@ -453,7 +454,7 @@ func (o *deploySvcOpts) configureClients() error { o.envSess = envSess // client to retrieve caller identity. - caller, err := identity.New(defaultSess).Get() + caller, err := identity.New(v2ConfigFromSessionRegion(defaultSess)).Get() if err != nil { return fmt.Errorf("get identity: %w", err) } diff --git a/internal/pkg/cli/svc_exec.go b/internal/pkg/cli/svc_exec.go index 8125da841f2..20aaaf1e559 100644 --- a/internal/pkg/cli/svc_exec.go +++ b/internal/pkg/cli/svc_exec.go @@ -9,14 +9,11 @@ import ( "math/rand" "strings" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/cmd/copilot/template" awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/exec" @@ -65,7 +62,10 @@ func newSvcExecOpts(vars execVars) (*svcExecOpts, error) { if err != nil { return nil, err } - ssmStore := config.NewSSMStore(identity.New(defaultSession), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + ssmStore, err := newSSMConfigStore(defaultSession) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, ssmStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) @@ -75,7 +75,7 @@ func newSvcExecOpts(vars execVars) (*svcExecOpts, error) { store: ssmStore, sel: selector.NewDeploySelect(prompt.New(), ssmStore, deployStore), newSvcDescriber: func(s *session.Session) serviceDescriber { - return ecs.New(s) + return ecs.New(s, v2ConfigFromSessionRegion(s)) }, newCommandExecutor: func(s *session.Session) ecsCommandExecutor { return awsecs.New(s) diff --git a/internal/pkg/cli/svc_init.go b/internal/pkg/cli/svc_init.go index 05756d4f0e4..3b762fba645 100644 --- a/internal/pkg/cli/svc_init.go +++ b/internal/pkg/cli/svc_init.go @@ -12,11 +12,9 @@ import ( "strconv" "strings" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/dustin/go-humanize/english" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerfile" @@ -194,7 +192,10 @@ func newInitSvcOpts(vars initSvcVars) (*initSvcOpts, error) { if err != nil { return nil, err } - store := config.NewSSMStore(identity.New(sess), ssm.New(sess), aws.StringValue(sess.Config.Region)) + store, err := newSSMConfigStore(sess) + if err != nil { + return nil, err + } prompter := prompt.New() deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { diff --git a/internal/pkg/cli/svc_list.go b/internal/pkg/cli/svc_list.go index 161d0229842..8f1cf6e2be5 100644 --- a/internal/pkg/cli/svc_list.go +++ b/internal/pkg/cli/svc_list.go @@ -7,14 +7,10 @@ import ( "fmt" "os" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/aproint/copilot-cli/internal/pkg/cli/list" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" @@ -46,7 +42,10 @@ func newListSvcOpts(vars listWkldVars) (*listSvcOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - store := config.NewSSMStore(identity.New(sess), ssm.New(sess), aws.StringValue(sess.Config.Region)) + store, err := newSSMConfigStore(sess) + if err != nil { + return nil, err + } svcLister := &list.SvcListWriter{ Ws: ws, Store: store, diff --git a/internal/pkg/cli/svc_logs.go b/internal/pkg/cli/svc_logs.go index 0c992a51614..63ce8b94941 100644 --- a/internal/pkg/cli/svc_logs.go +++ b/internal/pkg/cli/svc_logs.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -13,9 +14,6 @@ import ( awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -95,7 +93,10 @@ func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) @@ -118,7 +119,11 @@ func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { if err != nil { return err } - opts.ecs = ecs.New(sess) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) + if err != nil { + return err + } + opts.ecs = ecs.New(sess, cfg) newWorkloadLoggerOpts := &logging.NewWorkloadLoggerOpts{ App: opts.appName, diff --git a/internal/pkg/cli/svc_override.go b/internal/pkg/cli/svc_override.go index f9d5ec278d4..efb9ecf8eeb 100644 --- a/internal/pkg/cli/svc_override.go +++ b/internal/pkg/cli/svc_override.go @@ -7,16 +7,12 @@ import ( "fmt" "slices" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -48,7 +44,10 @@ func newOverrideWorkloadOpts(vars overrideWorkloadVars) (*overrideWorkloadOpts, if err != nil { return nil, fmt.Errorf("default session: %v", err) } - cfgStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + cfgStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } vars.requiresEnv = true prompt := prompt.New() cmd := &overrideWorkloadOpts{ diff --git a/internal/pkg/cli/svc_package.go b/internal/pkg/cli/svc_package.go index c7c0a530f5b..d30ca4e395e 100644 --- a/internal/pkg/cli/svc_package.go +++ b/internal/pkg/cli/svc_package.go @@ -17,9 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/exec" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -96,7 +94,10 @@ func newPackageSvcOpts(vars packageSvcVars) (*packageSvcOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompter := prompt.New() opts := &packageSvcOpts{ packageSvcVars: vars, @@ -308,7 +309,7 @@ func (o *packageSvcOpts) configureClients() error { } o.envSess = envSess // client to retrieve caller identity. - caller, err := identity.New(defaultSess).Get() + caller, err := identity.New(v2ConfigFromSessionRegion(defaultSess)).Get() if err != nil { return fmt.Errorf("get identity: %w", err) } diff --git a/internal/pkg/cli/svc_pause.go b/internal/pkg/cli/svc_pause.go index 14f53f34766..0fda761d9ef 100644 --- a/internal/pkg/cli/svc_pause.go +++ b/internal/pkg/cli/svc_pause.go @@ -7,10 +7,7 @@ import ( "errors" "fmt" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" @@ -64,7 +61,10 @@ func newSvcPauseOpts(vars svcPauseVars) (*svcPauseOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/svc_resume.go b/internal/pkg/cli/svc_resume.go index 00684498e43..76969ed549d 100644 --- a/internal/pkg/cli/svc_resume.go +++ b/internal/pkg/cli/svc_resume.go @@ -6,14 +6,10 @@ package cli import ( "fmt" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/term/color" @@ -137,7 +133,10 @@ func newResumeSvcOpts(vars resumeSvcVars) (*resumeSvcOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/svc_show.go b/internal/pkg/cli/svc_show.go index 0eda4a84751..aef8188c16b 100644 --- a/internal/pkg/cli/svc_show.go +++ b/internal/pkg/cli/svc_show.go @@ -10,11 +10,8 @@ import ( "strings" "unicode" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -59,7 +56,10 @@ func newShowSvcOpts(vars showSvcVars) (*showSvcOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - ssmStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + ssmStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, ssmStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/svc_status.go b/internal/pkg/cli/svc_status.go index 59a391bd7a7..a94fb4bef41 100644 --- a/internal/pkg/cli/svc_status.go +++ b/internal/pkg/cli/svc_status.go @@ -7,13 +7,9 @@ import ( "fmt" "io" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/term/log" @@ -51,7 +47,10 @@ func newSvcStatusOpts(vars svcStatusVars) (*svcStatusOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - configStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + configStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/task_delete.go b/internal/pkg/cli/task_delete.go index a661fc46115..3ee49ae39f8 100644 --- a/internal/pkg/cli/task_delete.go +++ b/internal/pkg/cli/task_delete.go @@ -11,13 +11,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/s3" "github.com/spf13/afero" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/service/ssm" - awscfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/ecr" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/ecs" @@ -87,7 +83,10 @@ func newDeleteTaskOpts(vars deleteTaskVars) (*deleteTaskOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompter := prompt.New() return &deleteTaskOpts{ deleteTaskVars: vars, @@ -103,7 +102,7 @@ func newDeleteTaskOpts(vars deleteTaskVars) (*deleteTaskOpts, error) { return selector.NewCFTaskSelect(prompter, store, cfn) }, newTaskStopper: func(session *session.Session) taskStopper { - return ecs.New(session) + return ecs.New(session, v2ConfigFromSessionRegion(session)) }, newStackManager: func(session *session.Session) taskStackManager { return cloudformation.New(session, cloudformation.WithProgressTracker(os.Stderr)) diff --git a/internal/pkg/cli/task_exec.go b/internal/pkg/cli/task_exec.go index ed0e29fb09e..e40dab3ddb7 100644 --- a/internal/pkg/cli/task_exec.go +++ b/internal/pkg/cli/task_exec.go @@ -6,13 +6,9 @@ package cli import ( "fmt" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aproint/copilot-cli/cmd/copilot/template" awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/exec" "github.com/aproint/copilot-cli/internal/pkg/term/color" @@ -64,7 +60,10 @@ func newTaskExecOpts(vars taskExecVars) (*taskExecOpts, error) { return nil, fmt.Errorf("default session: %v", err) } - ssmStore := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + ssmStore, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } prompter := prompt.New() return &taskExecOpts{ taskExecVars: vars, @@ -72,7 +71,7 @@ func newTaskExecOpts(vars taskExecVars) (*taskExecOpts, error) { ssmPluginManager: exec.NewSSMPluginCommand(nil), prompter: prompter, newTaskSel: func(sess *session.Session) runningTaskSelector { - return selector.NewTaskSelector(prompter, ecs.New(sess)) + return selector.NewTaskSelector(prompter, ecs.New(sess, v2ConfigFromSessionRegion(sess))) }, configSel: selector.NewConfigSelector(prompter, ssmStore), newCommandExecutor: func(s *session.Session) ecsCommandExecutor { diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index 788a03a3140..789274c0a39 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -18,9 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template/artifactpath" "golang.org/x/mod/semver" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" "github.com/spf13/pflag" @@ -197,7 +195,10 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { } prompter := prompt.New() - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store, err := newSSMConfigStore(defaultSess) + if err != nil { + return nil, err + } opts := runTaskOpts{ runTaskVars: vars, @@ -236,10 +237,10 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { return awsecs.New(session) } opts.configureServiceDescriber = func(session *session.Session) ecs.ServiceDescriber { - return ecs.New(session) + return ecs.New(session, v2ConfigFromSessionRegion(session)) } opts.configureJobDescriber = func(session *session.Session) ecs.JobDescriber { - return ecs.New(session) + return ecs.New(session, v2ConfigFromSessionRegion(session)) } opts.configureUploader = func(session *session.Session) uploader { return s3.New(session) @@ -283,7 +284,7 @@ func (o *runTaskOpts) configureRunner() (taskRunner, error) { return nil, fmt.Errorf("create describer for environment %s in application %s: %w", o.env, o.appName, err) } - ecsClient := ecs.New(o.sess) + ecsClient := ecs.New(o.sess, v2ConfigFromSessionRegion(o.sess)) return &task.EnvRunner{ Count: o.count, GroupName: o.groupName, @@ -314,7 +315,7 @@ func (o *runTaskOpts) configureRunner() (taskRunner, error) { VPCGetter: vpcGetter, ClusterGetter: ecsService, Starter: ecsService, - NonZeroExitCodeGetter: ecs.New(o.sess), + NonZeroExitCodeGetter: ecs.New(o.sess, v2ConfigFromSessionRegion(o.sess)), }, nil } diff --git a/internal/pkg/deploy/cloudformation/cloudformation.go b/internal/pkg/deploy/cloudformation/cloudformation.go index 188a06a1dea..eeaf8657f67 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation.go +++ b/internal/pkg/deploy/cloudformation/cloudformation.go @@ -25,6 +25,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/codestar" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/aws/s3" + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/stream" "github.com/aproint/copilot-cli/internal/pkg/term/color" @@ -208,12 +209,13 @@ type CloudFormation struct { // New returns a configured CloudFormation client. func New(sess *session.Session, opts ...OptFn) CloudFormation { + v2Config, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) client := CloudFormation{ cfnClient: cloudformation.New(sess), - codeStarClient: codestar.New(sess), - cpClient: codepipeline.New(sess), + codeStarClient: codestar.New(v2Config), + cpClient: codepipeline.New(sess, v2Config), ecsClient: ecs.New(sess), - cwClient: cloudwatch.New(sess), + cwClient: cloudwatch.New(sess, v2Config), regionalClient: func(region string) cfnClient { return cloudformation.New(sess.Copy(&aws.Config{ Region: aws.String(region), diff --git a/internal/pkg/deploy/deploy.go b/internal/pkg/deploy/deploy.go index 3996422644d..a688fffce46 100644 --- a/internal/pkg/deploy/deploy.go +++ b/internal/pkg/deploy/deploy.go @@ -5,12 +5,13 @@ package deploy import ( + "context" "fmt" "slices" "sort" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" @@ -57,7 +58,7 @@ type ConfigStoreClient interface { // SessionProvider is the interface to provide configuration for the AWS SDK's service clients. type SessionProvider interface { - FromRole(roleARN, region string) (*session.Session, error) + ConfigFromRole(ctx context.Context, roleARN string, region string) (awsv2.Config, error) } // Store fetches information on deployed services. @@ -77,18 +78,18 @@ func NewStore(sessProvider SessionProvider, store ConfigStoreClient) (*Store, er if err != nil { return nil, fmt.Errorf("get environment config %s: %w", envName, err) } - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return nil, fmt.Errorf("create new session from env role: %w", err) + return nil, fmt.Errorf("create new config from env role: %w", err) } - return rg.New(sess), nil + return rg.New(cfg), nil } s.newRgClientFromRole = func(roleARN, region string) (ResourceGetter, error) { - sess, err := sessProvider.FromRole(roleARN, region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), roleARN, region) if err != nil { - return nil, fmt.Errorf("create new session from env role: %w", err) + return nil, fmt.Errorf("create new config from env role: %w", err) } - return rg.New(sess), nil + return rg.New(cfg), nil } return s, nil } diff --git a/internal/pkg/deploy/mocks/mock_deploy.go b/internal/pkg/deploy/mocks/mock_deploy.go index 83c6f005dd8..a7b9ae6aa8f 100644 --- a/internal/pkg/deploy/mocks/mock_deploy.go +++ b/internal/pkg/deploy/mocks/mock_deploy.go @@ -5,11 +5,12 @@ package mocks import ( + context "context" reflect "reflect" resourcegroups "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" config "github.com/aproint/copilot-cli/internal/pkg/config" - session "github.com/aws/aws-sdk-go/aws/session" + aws "github.com/aws/aws-sdk-go-v2/aws" gomock "github.com/golang/mock/gomock" ) @@ -172,17 +173,17 @@ func (m *MockSessionProvider) EXPECT() *MockSessionProviderMockRecorder { return m.recorder } -// FromRole mocks base method. -func (m *MockSessionProvider) FromRole(roleARN, region string) (*session.Session, error) { +// ConfigFromRole mocks base method. +func (m *MockSessionProvider) ConfigFromRole(ctx context.Context, roleARN, region string) (aws.Config, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromRole", roleARN, region) - ret0, _ := ret[0].(*session.Session) + ret := m.ctrl.Call(m, "ConfigFromRole", ctx, roleARN, region) + ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } -// FromRole indicates an expected call of FromRole. -func (mr *MockSessionProviderMockRecorder) FromRole(roleARN, region interface{}) *gomock.Call { +// ConfigFromRole indicates an expected call of ConfigFromRole. +func (mr *MockSessionProviderMockRecorder) ConfigFromRole(ctx, roleARN, region interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromRole", reflect.TypeOf((*MockSessionProvider)(nil).FromRole), roleARN, region) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MockSessionProvider)(nil).ConfigFromRole), ctx, roleARN, region) } diff --git a/internal/pkg/describe/aws_config.go b/internal/pkg/describe/aws_config.go new file mode 100644 index 00000000000..e3f550f775b --- /dev/null +++ b/internal/pkg/describe/aws_config.go @@ -0,0 +1,15 @@ +package describe + +import ( + "context" + + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" + "github.com/aws/aws-sdk-go-v2/aws" + awsv1 "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" +) + +func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), awsv1.StringValue(sess.Config.Region)) + return cfg +} diff --git a/internal/pkg/describe/backend_service.go b/internal/pkg/describe/backend_service.go index 2bc921d674f..4b64910a1af 100644 --- a/internal/pkg/describe/backend_service.go +++ b/internal/pkg/describe/backend_service.go @@ -94,7 +94,7 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if err != nil { return nil, err } - return cloudwatch.New(sess), nil + return cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), nil } describer.initEnvDescribers = func(env string) (envDescriber, error) { if describer, ok := describer.envStackDescriber[env]; ok { diff --git a/internal/pkg/describe/lb_web_service.go b/internal/pkg/describe/lb_web_service.go index a0cf0233f8d..39f0ef76745 100644 --- a/internal/pkg/describe/lb_web_service.go +++ b/internal/pkg/describe/lb_web_service.go @@ -132,7 +132,7 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if err != nil { return nil, err } - return cloudwatch.New(sess), nil + return cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), nil } return describer, nil } diff --git a/internal/pkg/describe/pipeline_show.go b/internal/pkg/describe/pipeline_show.go index 95af1d01903..933a3d34d2c 100644 --- a/internal/pkg/describe/pipeline_show.go +++ b/internal/pkg/describe/pipeline_show.go @@ -49,7 +49,7 @@ func NewPipelineDescriber(pipeline deploy.Pipeline, showResources bool) (*Pipeli return nil, err } - pipelineSvc := codepipeline.New(sess) + pipelineSvc := codepipeline.New(sess, v2ConfigFromSessionRegion(sess)) return &PipelineDescriber{ pipeline: pipeline, diff --git a/internal/pkg/describe/pipeline_status.go b/internal/pkg/describe/pipeline_status.go index 76fd3e65954..f6024f832b9 100644 --- a/internal/pkg/describe/pipeline_status.go +++ b/internal/pkg/describe/pipeline_status.go @@ -39,7 +39,7 @@ func NewPipelineStatusDescriber(pipeline deploy.Pipeline) (*PipelineStatusDescri return nil, err } - pipelineSvc := codepipeline.New(sess) + pipelineSvc := codepipeline.New(sess, v2ConfigFromSessionRegion(sess)) return &PipelineStatusDescriber{ pipeline: pipeline, pipelineSvc: pipelineSvc, diff --git a/internal/pkg/describe/service.go b/internal/pkg/describe/service.go index 41c15136f22..1a4faa1a2de 100644 --- a/internal/pkg/describe/service.go +++ b/internal/pkg/describe/service.go @@ -152,7 +152,7 @@ func newECSServiceDescriber(opt NewServiceConfig) (*ecsServiceDescriber, error) } return &ecsServiceDescriber{ WorkloadStackDescriber: stackDescriber, - ecsClient: ecs.New(stackDescriber.sess), + ecsClient: ecs.New(stackDescriber.sess, v2ConfigFromSessionRegion(stackDescriber.sess)), }, nil } diff --git a/internal/pkg/describe/static_site.go b/internal/pkg/describe/static_site.go index a7c275c872f..a61048bb480 100644 --- a/internal/pkg/describe/static_site.go +++ b/internal/pkg/describe/static_site.go @@ -71,7 +71,7 @@ func NewStaticSiteDescriber(opt NewServiceConfig) (*StaticSiteDescriber, error) if err != nil { return nil, nil, err } - return awsS3.New(sess), s3.New(sess), nil + return awsS3.New(sess), s3.New(sess, v2ConfigFromSessionRegion(sess)), nil } return describer, nil } diff --git a/internal/pkg/describe/status_describe.go b/internal/pkg/describe/status_describe.go index 9f648fc73de..be9c5521c15 100644 --- a/internal/pkg/describe/status_describe.go +++ b/internal/pkg/describe/status_describe.go @@ -104,8 +104,8 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er app: opt.App, env: opt.Env, svc: opt.Svc, - svcDescriber: ecs.New(sess), - cwSvcGetter: cloudwatch.New(sess), + svcDescriber: ecs.New(sess, v2ConfigFromSessionRegion(sess)), + cwSvcGetter: cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), ecsSvcGetter: awsecs.New(sess), aasSvcGetter: aas.New(sess), targetHealthGetter: elbv2.New(sess), @@ -149,7 +149,7 @@ func NewStaticSiteStatusDescriber(opt *NewServiceStatusConfig) (*staticSiteStatu if err != nil { return nil, nil, err } - return awsS3.New(sess), s3.New(sess), nil + return awsS3.New(sess), s3.New(sess, v2ConfigFromSessionRegion(sess)), nil } return describer, nil } diff --git a/internal/pkg/describe/worker_service.go b/internal/pkg/describe/worker_service.go index 04a4d6f117e..e4ee9b023f8 100644 --- a/internal/pkg/describe/worker_service.go +++ b/internal/pkg/describe/worker_service.go @@ -70,7 +70,7 @@ func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, e if err != nil { return nil, err } - return cloudwatch.New(sess), nil + return cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), nil } return describer, nil } diff --git a/internal/pkg/ecs/ecs.go b/internal/pkg/ecs/ecs.go index df347b968de..76f60535b6b 100644 --- a/internal/pkg/ecs/ecs.go +++ b/internal/pkg/ecs/ecs.go @@ -16,6 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/stepfunctions" "github.com/aproint/copilot-cli/internal/pkg/deploy" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/session" @@ -78,14 +79,20 @@ type Client struct { } // New creates a new Client. -func New(sess *session.Session) *Client { +func New(sess *session.Session, rgConfig awsv2.Config) *Client { return &Client{ - rgGetter: resourcegroups.New(sess), - ecsClient: ecs.New(sess), - StepFuncClient: stepfunctions.New(sess), + rgGetter: resourcegroups.New(rgConfig), + ecsClient: ecs.New(sess), } } +// NewWithStepFunctionsConfig creates a new Client with a Step Functions client configured from SDK v2 config. +func NewWithStepFunctionsConfig(sess *session.Session, cfg awsv2.Config) *Client { + client := New(sess, cfg) + client.StepFuncClient = stepfunctions.New(cfg) + return client +} + // ClusterARN returns the ARN of the cluster in an environment. func (c Client) ClusterARN(app, env string) (string, error) { return c.clusterARN(app, env) diff --git a/internal/pkg/s3/s3.go b/internal/pkg/s3/s3.go index 63a2d246ab7..612e4fa10ae 100644 --- a/internal/pkg/s3/s3.go +++ b/internal/pkg/s3/s3.go @@ -12,6 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/s3" "github.com/aproint/copilot-cli/internal/pkg/deploy" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/session" ) @@ -29,9 +30,9 @@ type Client struct { } // New inits a new Client. -func New(sess *session.Session) *Client { +func New(sess *session.Session, rgConfig awsv2.Config) *Client { return &Client{ - rgGetter: resourcegroups.New(sess), + rgGetter: resourcegroups.New(rgConfig), } } From 198e9db267e4e927053ee20b1c5255baaa3519d0 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Mon, 6 Jul 2026 15:39:28 +0200 Subject: [PATCH 05/17] migrate another set --- go.mod | 19 +++ go.sum | 38 +++++ internal/pkg/aws/aas/aas.go | 24 +-- internal/pkg/aws/aas/aas_test.go | 34 ++-- internal/pkg/aws/aas/mocks/mock_aas.go | 16 +- internal/pkg/aws/acm/acm.go | 23 ++- internal/pkg/aws/acm/acm_test.go | 25 +-- internal/pkg/aws/acm/mocks/mock_acm.go | 17 +- .../pkg/aws/cloudwatchlogs/cloudwatchlogs.go | 55 ++++--- .../aws/cloudwatchlogs/cloudwatchlogs_test.go | 88 +++++------ .../mocks/mock_cloudwatchlogs.go | 29 ++-- internal/pkg/aws/iam/iam.go | 87 +++++------ internal/pkg/aws/iam/iam_test.go | 57 +++---- internal/pkg/aws/iam/mocks/mock_iam.go | 81 +++++++--- .../pkg/aws/route53/mocks/mock_route53.go | 28 ++-- internal/pkg/aws/route53/route53.go | 56 +++---- internal/pkg/aws/route53/route53_test.go | 146 +++++++++--------- internal/pkg/cli/app_init.go | 4 +- internal/pkg/cli/app_upgrade.go | 2 +- internal/pkg/cli/deploy/backend.go | 2 +- internal/pkg/cli/deploy/lbws.go | 2 +- internal/pkg/cli/env_delete.go | 2 +- internal/pkg/cli/env_init.go | 2 +- internal/pkg/cli/init.go | 2 +- internal/pkg/describe/status_describe.go | 4 +- internal/pkg/logging/aws_config.go | 15 ++ internal/pkg/logging/task.go | 2 +- internal/pkg/logging/workload.go | 2 +- 28 files changed, 500 insertions(+), 362 deletions(-) create mode 100644 internal/pkg/logging/aws_config.go diff --git a/go.mod b/go.mod index 9719dce0796..f41385672ce 100644 --- a/go.mod +++ b/go.mod @@ -43,14 +43,33 @@ require ( require ( github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 // indirect github.com/agext/levenshtein v1.2.3 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.30 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 // indirect + github.com/aws/aws-sdk-go-v2/service/acm v1.41.1 // indirect + github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.43.2 // indirect + github.com/aws/aws-sdk-go-v2/service/apprunner v1.40.8 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.73.1 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.61.1 // indirect + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.78.2 // indirect + github.com/aws/aws-sdk-go-v2/service/codepipeline v1.47.7 // indirect github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7 // indirect + github.com/aws/aws-sdk-go-v2/service/ec2 v1.311.0 // indirect + github.com/aws/aws-sdk-go-v2/service/ecr v1.58.6 // indirect + github.com/aws/aws-sdk-go-v2/service/ecs v1.86.2 // indirect + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.55.6 // indirect + github.com/aws/aws-sdk-go-v2/service/iam v1.54.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31 // indirect + github.com/aws/aws-sdk-go-v2/service/rds v1.119.5 // indirect github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5 // indirect + github.com/aws/aws-sdk-go-v2/service/route53 v1.63.5 // indirect + github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2 // indirect github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5 // indirect github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 // indirect diff --git a/go.sum b/go.sum index b1782c1e5ea..b1b4b469d61 100644 --- a/go.sum +++ b/go.sum @@ -9,26 +9,64 @@ 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-v2 v1.42.1 h1:9eOTgu1z/dVtYpNZ3/8/XbbaX0x/BqE3HUzAzs6K0ek= github.com/aws/aws-sdk-go-v2 v1.42.1/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14 h1:3IZY0XAJquT3aHzbkHfPzy4ACPcEjVG0x87KOwtpqGY= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14/go.mod h1:zwM6veDkhGgQFqkBy+uT28AAYpLu+uFMlPl+rCg/73E= github.com/aws/aws-sdk-go-v2/config v1.32.27 h1:SJwJ9Q4kM7v5QVSYYyXj3znRr6lNyZEhSgAXmXXcVbI= github.com/aws/aws-sdk-go-v2/config v1.32.27/go.mod h1:uBfrzTRedDmB2u+b6+UlaKJy2O6VSH5un2jP24t/KvQ= github.com/aws/aws-sdk-go-v2/credentials v1.19.26 h1:Si8kk1kyJnuJWCEgiwpBtTdtgSdR7i611596NnC0YIQ= github.com/aws/aws-sdk-go-v2/credentials v1.19.26/go.mod h1:lBckz+W9SAdNtSDw3pYgQUJDJFcBBWry0GSzw+bK0TY= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30 h1:/hi1JADLEW9YYryEz1w4GQu0EtP23pP553Cf9KgsDV4= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30/go.mod h1:/3AOgy4K17Dm4ucMZVC/MJkzy5kmfKUcINRHZyo0koQ= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.30 h1:qzaF2qXmjqBcLbtcpIxOddoDH5eKIRdmOiKt7BatgDc= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.30/go.mod h1:5LlJNctj1Y7l59FPonG4LNjK5DvorTKIS+pAVuWAh3s= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 h1:xM/Is9cKMHa8Jj8zkvWhvrFkZsXJV9E+BB4g0HW0duQ= github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30/go.mod h1:WueJeNDZvK1fMYEWJIkcivBfEzUkTpBhzlrUKKY8EuA= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 h1:jn46zC9LdsVR/ZpMIJqMqb8hHv31BlLx3ulVqNspUOk= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30/go.mod h1:1hTMsAgbdS/AtUi4bw8+gUuh1pceo+eXRLfpSuSQj3M= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 h1:3GUprIsfmGcC5SACIyB0e7E0BM1O1b3Erl5CePYIAeQ= github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31/go.mod h1:7PuV1yl5e2xnUbm+RqvVg5i2iBM8EyijZNoI9wsOoOc= +github.com/aws/aws-sdk-go-v2/service/acm v1.41.1 h1:IDASGmtxjGFAZxaAZewQ4VKD3H77U1mBczRFYM66ov8= +github.com/aws/aws-sdk-go-v2/service/acm v1.41.1/go.mod h1:0HVmvx7Fvvqg+fXgDm66ye6/IF0NKccKS+UkuJyRjpI= +github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.43.2 h1:IYkm3geAn8UsbalXfMPMV5BYxuP+nqylyB62KFnUnrc= +github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.43.2/go.mod h1:cxrDXIBVKdyjWMZdK4L90+UuT43Dkgt7uWDISRhh5SY= +github.com/aws/aws-sdk-go-v2/service/apprunner v1.40.8 h1:8zUhx0x9cCHZwT/wT1gWIaIEHatAUDtClw/4p9oWo5o= +github.com/aws/aws-sdk-go-v2/service/apprunner v1.40.8/go.mod h1:UehvT8KFucM18V9+wDq5AeZDj9qlxn8IFjZtz1aphiE= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.73.1 h1:F9Ys3vVDHRpzZBP2KAC67u95z+DTf0pBrGs9wduYMdM= +github.com/aws/aws-sdk-go-v2/service/cloudformation v1.73.1/go.mod h1:CbJ+8eU/zw2k8QilzLNmJvqn5ExnhtcdV1yPr4HmMYA= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.61.1 h1:wH+mF4NPzBMl9pqDofKz3sqolmvNkqvoS+aG7M6H5P4= +github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.61.1/go.mod h1:lipiF9DI3EmTTkEn2sgLug3iEO1dXM50FDFooey6vYU= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.78.2 h1:ZjXtLXEc6i34HW44ktr26b7HfkMZGSHa45URCfnYQt4= +github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.78.2/go.mod h1:h1Iw2nkdpmAUJaa89RvX3cg/HGLgdSkCWpMNgKvBSHA= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.47.7 h1:T5zrFQsfnBGHKxfymxBv4sde8L5LZB9NpGHAwftCvDk= +github.com/aws/aws-sdk-go-v2/service/codepipeline v1.47.7/go.mod h1:TauWDdo/zCElLORUQcUb8JkIxoNrctD03ECepck6/oc= github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7 h1:6Z1SAXPMgG3SmbDoDQ2erFygJ7vA2W349Ru3UzNjRWM= github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7/go.mod h1:tvsbZAxIY9hRwspsZURZ34tYiMGm2gnyAc++5M0G3i0= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.311.0 h1:hdDMnMXw/6HpLiHEpdQ71AKycRFWOuBYi84Nzj8pl+8= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.311.0/go.mod h1:eoF0SIRbTgKWnTcTPYckiURPba/7ilfEkvwL4V1iHK4= +github.com/aws/aws-sdk-go-v2/service/ecr v1.58.6 h1:EHQUIj2cTRnKlrIJZp+vn2jZPd6yukdxKyCPmHv3hCc= +github.com/aws/aws-sdk-go-v2/service/ecr v1.58.6/go.mod h1:UzfjIuiQOpusteIHBCLIikQpxh8ctmdQCvSWWzbcYYI= +github.com/aws/aws-sdk-go-v2/service/ecs v1.86.2 h1:t3eGwX8zYsFSEvWiRNG4KN+pMgYyFOc+wQEZPxWMTKk= +github.com/aws/aws-sdk-go-v2/service/ecs v1.86.2/go.mod h1:FZTiizNr2CG5myXP2I8pyCWM0/k4uwAnZXMkmjxgE3o= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.55.6 h1:5obpUisAJuLjJBLHVfIWi8uEzyaeArb4MDBYYjoJ/xw= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.55.6/go.mod h1:qNnJkZTDHDL2sO8hyVH2yILcfSEkjP/pIns2JsF1g1o= +github.com/aws/aws-sdk-go-v2/service/iam v1.54.7 h1:undHpuVUg25wS2CpeXNqVjIcJComV2RE5AZ7mJGth2U= +github.com/aws/aws-sdk-go-v2/service/iam v1.54.7/go.mod h1:5H/UUroHvcKm6l2qaqh3CMM6R9K91ls8Y8rVX6cG3ts= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 h1:mbRIur/BiHK6SKPjoBIXSE/hJ6g6JGRLuxQy1jGjlN4= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13/go.mod h1:ITg9em2KbJx1s0y4aqRX5OYWG6HBZ5TVR//OdpEZ2CQ= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23 h1:9Fjh6fi/U5JEStVZijmaMpUwE/gvBJj7x2B/PjbO9To= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23/go.mod h1:iMoT2f1tClxrWAAnKCXjZQ6LOmfLrMG14wmnWpM+F14= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 h1:/Z5jmNrKsSD7EmDjzAPsm/3L9IuOkzaynklJZ1qX7S4= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30/go.mod h1:lEzEZnOosE7zi8Z6royW1cFJTD9fpab4Ul1SBrllewk= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31 h1:uao4A3QZ5UmB326V6KF+qRpv9Tjz7IlnlnTbbANntlU= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31/go.mod h1:I/1+z0VwL1GhQyLgkoHDlygpUZ+iTAwOQ/NsftiUL2I= +github.com/aws/aws-sdk-go-v2/service/rds v1.119.5 h1:1/qGMaWmjbeOTaufLLqjLnrjhemH1eM74iVWVWWg+Zc= +github.com/aws/aws-sdk-go-v2/service/rds v1.119.5/go.mod h1:Ve7qHa8jBmStKNz/oaxs2yBuFnwyvN0k/8PpPZVxkEY= github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5 h1:cd2vmT/Cc9/ZzmuY0XM2YKA5tgkp2Jyv5Ia35ENsW5I= github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5/go.mod h1:1N13ke5qTtwOiBPXfPtH+MmG5Jo0UAfKnp+OZ2bQahI= +github.com/aws/aws-sdk-go-v2/service/route53 v1.63.5 h1:xyfm4EsGFdZ6OyXhGJya6dD+O3cqHqe4NHJ8PJ2Q+iE= +github.com/aws/aws-sdk-go-v2/service/route53 v1.63.5/go.mod h1:0hIRXFez1bZsDFMGkLZvNJbByTSVZ4sFZWpxZ39NPuM= +github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2 h1:bAY6O/TDv1HQnvylh9E247IyIKsUWUt2G965S7qX110= +github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2/go.mod h1:zdmCoFO/dSI7GlrwsPqFJI+WlFnSU4Tc8TJnlXrM1Do= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5 h1:CWn32XhRKVJQlCpU5T1PpspYbgUisB+Ke1w7NR4AHZw= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5/go.mod h1:oUyL28WfxY0RqPhFpkrWZx26Cu4JlyrWMMcWq8qqhi0= github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2 h1:DN64QFK4wW3/Fnzn5Wj1ztuzG2Smv4Oc8TJxVcmQ5E0= diff --git a/internal/pkg/aws/aas/aas.go b/internal/pkg/aws/aas/aas.go index 01b43143700..8f2622bfa3a 100644 --- a/internal/pkg/aws/aas/aas.go +++ b/internal/pkg/aws/aas/aas.go @@ -5,12 +5,12 @@ package aas import ( + "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - aas "github.com/aws/aws-sdk-go/service/applicationautoscaling" - - "github.com/aws/aws-sdk-go/aws/session" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + aas "github.com/aws/aws-sdk-go-v2/service/applicationautoscaling" + "github.com/aws/aws-sdk-go-v2/service/applicationautoscaling/types" ) const ( @@ -20,7 +20,7 @@ const ( ) type api interface { - DescribeScalingPolicies(input *aas.DescribeScalingPoliciesInput) (*aas.DescribeScalingPoliciesOutput, error) + DescribeScalingPolicies(ctx context.Context, input *aas.DescribeScalingPoliciesInput, opts ...func(*aas.Options)) (*aas.DescribeScalingPoliciesOutput, error) } // ApplicationAutoscaling wraps an Amazon Application Auto Scaling client. @@ -28,10 +28,10 @@ type ApplicationAutoscaling struct { client api } -// New returns a ApplicationAutoscaling struct configured against the input session. -func New(s *session.Session) *ApplicationAutoscaling { +// New returns a ApplicationAutoscaling struct configured against the input SDK v2 config. +func New(cfg awsv2.Config) *ApplicationAutoscaling { return &ApplicationAutoscaling{ - client: aas.New(s), + client: aas.NewFromConfig(cfg), } } @@ -43,9 +43,9 @@ func (a *ApplicationAutoscaling) ECSServiceAlarmNames(cluster, service string) ( var err error resp := &aas.DescribeScalingPoliciesOutput{} for { - resp, err = a.client.DescribeScalingPolicies(&aas.DescribeScalingPoliciesInput{ - ResourceId: aws.String(resourceID), - ServiceNamespace: aws.String(ecsServiceNamespace), + resp, err = a.client.DescribeScalingPolicies(context.Background(), &aas.DescribeScalingPoliciesInput{ + ResourceId: awsv2.String(resourceID), + ServiceNamespace: types.ServiceNamespaceEcs, NextToken: resp.NextToken, }) if err != nil { @@ -53,7 +53,7 @@ func (a *ApplicationAutoscaling) ECSServiceAlarmNames(cluster, service string) ( } for _, policy := range resp.ScalingPolicies { for _, alarm := range policy.Alarms { - alarms = append(alarms, aws.StringValue(alarm.AlarmName)) + alarms = append(alarms, awsv2.ToString(alarm.AlarmName)) } } if resp.NextToken == nil { diff --git a/internal/pkg/aws/aas/aas_test.go b/internal/pkg/aws/aas/aas_test.go index b37e212653e..b0ca35aae74 100644 --- a/internal/pkg/aws/aas/aas_test.go +++ b/internal/pkg/aws/aas/aas_test.go @@ -4,13 +4,15 @@ package aas import ( + "context" "errors" "fmt" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/aas/mocks" - "github.com/aws/aws-sdk-go/aws" - aas "github.com/aws/aws-sdk-go/service/applicationautoscaling" + "github.com/aws/aws-sdk-go-v2/aws" + aas "github.com/aws/aws-sdk-go-v2/service/applicationautoscaling" + "github.com/aws/aws-sdk-go-v2/service/applicationautoscaling/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -36,20 +38,20 @@ func TestCloudWatch_ECSServiceAutoscalingAlarms(t *testing.T) { }{ "errors if failed to retrieve auto scaling alarm names": { setupMocks: func(m aasMocks) { - m.client.EXPECT().DescribeScalingPolicies(gomock.Any()).Return(nil, mockError) + m.client.EXPECT().DescribeScalingPolicies(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantErr: fmt.Errorf("describe scaling policies for ECS service mockCluster/mockService: some error"), }, "success": { setupMocks: func(m aasMocks) { - m.client.EXPECT().DescribeScalingPolicies(&aas.DescribeScalingPoliciesInput{ + m.client.EXPECT().DescribeScalingPolicies(context.Background(), &aas.DescribeScalingPoliciesInput{ ResourceId: aws.String(mockResourceID), - ServiceNamespace: aws.String(ecsServiceNamespace), + ServiceNamespace: types.ServiceNamespaceEcs, }).Return(&aas.DescribeScalingPoliciesOutput{ - ScalingPolicies: []*aas.ScalingPolicy{ + ScalingPolicies: []types.ScalingPolicy{ { - Alarms: []*aas.Alarm{ + Alarms: []types.Alarm{ { AlarmName: aws.String("mockAlarm1"), }, @@ -59,7 +61,7 @@ func TestCloudWatch_ECSServiceAutoscalingAlarms(t *testing.T) { }, }, { - Alarms: []*aas.Alarm{ + Alarms: []types.Alarm{ { AlarmName: aws.String("mockAlarm3"), }, @@ -74,13 +76,13 @@ func TestCloudWatch_ECSServiceAutoscalingAlarms(t *testing.T) { "success with pagination": { setupMocks: func(m aasMocks) { gomock.InOrder( - m.client.EXPECT().DescribeScalingPolicies(&aas.DescribeScalingPoliciesInput{ + m.client.EXPECT().DescribeScalingPolicies(context.Background(), &aas.DescribeScalingPoliciesInput{ ResourceId: aws.String(mockResourceID), - ServiceNamespace: aws.String(ecsServiceNamespace), + ServiceNamespace: types.ServiceNamespaceEcs, }).Return(&aas.DescribeScalingPoliciesOutput{ - ScalingPolicies: []*aas.ScalingPolicy{ + ScalingPolicies: []types.ScalingPolicy{ { - Alarms: []*aas.Alarm{ + Alarms: []types.Alarm{ { AlarmName: aws.String("mockAlarm1"), }, @@ -89,14 +91,14 @@ func TestCloudWatch_ECSServiceAutoscalingAlarms(t *testing.T) { }, NextToken: aws.String(mockNextToken), }, nil), - m.client.EXPECT().DescribeScalingPolicies(&aas.DescribeScalingPoliciesInput{ + m.client.EXPECT().DescribeScalingPolicies(context.Background(), &aas.DescribeScalingPoliciesInput{ ResourceId: aws.String(mockResourceID), - ServiceNamespace: aws.String(ecsServiceNamespace), + ServiceNamespace: types.ServiceNamespaceEcs, NextToken: aws.String(mockNextToken), }).Return(&aas.DescribeScalingPoliciesOutput{ - ScalingPolicies: []*aas.ScalingPolicy{ + ScalingPolicies: []types.ScalingPolicy{ { - Alarms: []*aas.Alarm{ + Alarms: []types.Alarm{ { AlarmName: aws.String("mockAlarm2"), }, diff --git a/internal/pkg/aws/aas/mocks/mock_aas.go b/internal/pkg/aws/aas/mocks/mock_aas.go index eedc3109f55..91bacd64db0 100644 --- a/internal/pkg/aws/aas/mocks/mock_aas.go +++ b/internal/pkg/aws/aas/mocks/mock_aas.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - applicationautoscaling "github.com/aws/aws-sdk-go/service/applicationautoscaling" + applicationautoscaling "github.com/aws/aws-sdk-go-v2/service/applicationautoscaling" gomock "github.com/golang/mock/gomock" ) @@ -35,16 +36,21 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeScalingPolicies mocks base method. -func (m *Mockapi) DescribeScalingPolicies(input *applicationautoscaling.DescribeScalingPoliciesInput) (*applicationautoscaling.DescribeScalingPoliciesOutput, error) { +func (m *Mockapi) DescribeScalingPolicies(ctx context.Context, input *applicationautoscaling.DescribeScalingPoliciesInput, opts ...func(*applicationautoscaling.Options)) (*applicationautoscaling.DescribeScalingPoliciesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeScalingPolicies", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeScalingPolicies", varargs...) ret0, _ := ret[0].(*applicationautoscaling.DescribeScalingPoliciesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeScalingPolicies indicates an expected call of DescribeScalingPolicies. -func (mr *MockapiMockRecorder) DescribeScalingPolicies(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeScalingPolicies(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeScalingPolicies", reflect.TypeOf((*Mockapi)(nil).DescribeScalingPolicies), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeScalingPolicies", reflect.TypeOf((*Mockapi)(nil).DescribeScalingPolicies), varargs...) } diff --git a/internal/pkg/aws/acm/acm.go b/internal/pkg/aws/acm/acm.go index a12cee9289e..2c95807ef51 100644 --- a/internal/pkg/aws/acm/acm.go +++ b/internal/pkg/aws/acm/acm.go @@ -11,13 +11,10 @@ import ( "sync" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/acm" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/acm" "github.com/dustin/go-humanize/english" "golang.org/x/sync/errgroup" - - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" ) const ( @@ -25,7 +22,7 @@ const ( ) type api interface { - DescribeCertificateWithContext(ctx aws.Context, input *acm.DescribeCertificateInput, opts ...request.Option) (*acm.DescribeCertificateOutput, error) + DescribeCertificate(ctx context.Context, input *acm.DescribeCertificateInput, opts ...func(*acm.Options)) (*acm.DescribeCertificateOutput, error) } // ACM wraps an AWS Certificate Manager client. @@ -33,10 +30,10 @@ type ACM struct { client api } -// New returns an ACM struct configured against the input session. -func New(s *session.Session) *ACM { +// New returns an ACM struct configured against the input SDK v2 config. +func New(cfg awsv2.Config) *ACM { return &ACM{ - client: acm.New(s), + client: acm.NewFromConfig(cfg), } } @@ -81,15 +78,13 @@ func (a *ACM) ValidateCertAliases(aliases []string, certs []string) error { } func (a *ACM) validDomainsOfCert(ctx context.Context, cert string) ([]string, error) { - resp, err := a.client.DescribeCertificateWithContext(ctx, &acm.DescribeCertificateInput{ - CertificateArn: aws.String(cert), + resp, err := a.client.DescribeCertificate(ctx, &acm.DescribeCertificateInput{ + CertificateArn: awsv2.String(cert), }) if err != nil { return nil, fmt.Errorf("describe certificate %s: %w", cert, err) } - var domainsOfCert []*string - domainsOfCert = append(domainsOfCert, resp.Certificate.SubjectAlternativeNames...) - return aws.StringValueSlice(domainsOfCert), err + return append([]string(nil), resp.Certificate.SubjectAlternativeNames...), err } func filterValidAliases(domains []string, aliases []string) []string { diff --git a/internal/pkg/aws/acm/acm_test.go b/internal/pkg/aws/acm/acm_test.go index fff5eda19ea..ed361c1cd3c 100644 --- a/internal/pkg/aws/acm/acm_test.go +++ b/internal/pkg/aws/acm/acm_test.go @@ -9,8 +9,9 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/acm/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/acm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/acm" + "github.com/aws/aws-sdk-go-v2/service/acm/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -35,7 +36,7 @@ func TestACM_ValidateCertAliases(t *testing.T) { inAliases: []string{"copilot.com"}, inCerts: []string{"mockCertARN"}, setupMocks: func(m acmMocks) { - m.client.EXPECT().DescribeCertificateWithContext(gomock.Any(), &acm.DescribeCertificateInput{ + m.client.EXPECT().DescribeCertificate(gomock.Any(), &acm.DescribeCertificateInput{ CertificateArn: aws.String("mockCertARN"), }).Return(nil, mockError) }, @@ -46,11 +47,11 @@ func TestACM_ValidateCertAliases(t *testing.T) { inAliases: []string{"v1.copilot.com", "myapp.v1.copilot.com"}, inCerts: []string{"mockCertARN"}, setupMocks: func(m acmMocks) { - m.client.EXPECT().DescribeCertificateWithContext(gomock.Any(), &acm.DescribeCertificateInput{ + m.client.EXPECT().DescribeCertificate(gomock.Any(), &acm.DescribeCertificateInput{ CertificateArn: aws.String("mockCertARN"), }).Return(&acm.DescribeCertificateOutput{ - Certificate: &acm.CertificateDetail{ - SubjectAlternativeNames: aws.StringSlice([]string{"example.com", "*.copilot.com"}), + Certificate: &types.CertificateDetail{ + SubjectAlternativeNames: []string{"example.com", "*.copilot.com"}, }, }, nil) }, @@ -61,18 +62,18 @@ func TestACM_ValidateCertAliases(t *testing.T) { inAliases: []string{"v1.copilot.com", "example.com"}, inCerts: []string{"mockCertARN1", "mockCertARN2"}, setupMocks: func(m acmMocks) { - m.client.EXPECT().DescribeCertificateWithContext(gomock.Any(), &acm.DescribeCertificateInput{ + m.client.EXPECT().DescribeCertificate(gomock.Any(), &acm.DescribeCertificateInput{ CertificateArn: aws.String("mockCertARN1"), }).Return(&acm.DescribeCertificateOutput{ - Certificate: &acm.CertificateDetail{ - SubjectAlternativeNames: aws.StringSlice([]string{"copilot.com", "*.copilot.com"}), + Certificate: &types.CertificateDetail{ + SubjectAlternativeNames: []string{"copilot.com", "*.copilot.com"}, }, }, nil) - m.client.EXPECT().DescribeCertificateWithContext(gomock.Any(), &acm.DescribeCertificateInput{ + m.client.EXPECT().DescribeCertificate(gomock.Any(), &acm.DescribeCertificateInput{ CertificateArn: aws.String("mockCertARN2"), }).Return(&acm.DescribeCertificateOutput{ - Certificate: &acm.CertificateDetail{ - SubjectAlternativeNames: aws.StringSlice([]string{"example.com"}), + Certificate: &types.CertificateDetail{ + SubjectAlternativeNames: []string{"example.com"}, }, }, nil) }, diff --git a/internal/pkg/aws/acm/mocks/mock_acm.go b/internal/pkg/aws/acm/mocks/mock_acm.go index a9fd29ebf88..a01dc68f1f1 100644 --- a/internal/pkg/aws/acm/mocks/mock_acm.go +++ b/internal/pkg/aws/acm/mocks/mock_acm.go @@ -5,11 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - aws "github.com/aws/aws-sdk-go/aws" - request "github.com/aws/aws-sdk-go/aws/request" - acm "github.com/aws/aws-sdk-go/service/acm" + acm "github.com/aws/aws-sdk-go-v2/service/acm" gomock "github.com/golang/mock/gomock" ) @@ -36,22 +35,22 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { return m.recorder } -// DescribeCertificateWithContext mocks base method. -func (m *Mockapi) DescribeCertificateWithContext(ctx aws.Context, input *acm.DescribeCertificateInput, opts ...request.Option) (*acm.DescribeCertificateOutput, error) { +// DescribeCertificate mocks base method. +func (m *Mockapi) DescribeCertificate(ctx context.Context, input *acm.DescribeCertificateInput, opts ...func(*acm.Options)) (*acm.DescribeCertificateOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{ctx, input} for _, a := range opts { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DescribeCertificateWithContext", varargs...) + ret := m.ctrl.Call(m, "DescribeCertificate", varargs...) ret0, _ := ret[0].(*acm.DescribeCertificateOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeCertificateWithContext indicates an expected call of DescribeCertificateWithContext. -func (mr *MockapiMockRecorder) DescribeCertificateWithContext(ctx, input interface{}, opts ...interface{}) *gomock.Call { +// DescribeCertificate indicates an expected call of DescribeCertificate. +func (mr *MockapiMockRecorder) DescribeCertificate(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{ctx, input}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeCertificateWithContext", reflect.TypeOf((*Mockapi)(nil).DescribeCertificateWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeCertificate", reflect.TypeOf((*Mockapi)(nil).DescribeCertificate), varargs...) } diff --git a/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs.go b/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs.go index 6f7c195489a..51b626b7aef 100644 --- a/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs.go +++ b/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs.go @@ -5,13 +5,14 @@ package cloudwatchlogs import ( + "context" "fmt" "sort" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudwatchlogs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types" ) const ( @@ -25,8 +26,8 @@ var ( ) type api interface { - DescribeLogStreams(input *cloudwatchlogs.DescribeLogStreamsInput) (*cloudwatchlogs.DescribeLogStreamsOutput, error) - GetLogEvents(input *cloudwatchlogs.GetLogEventsInput) (*cloudwatchlogs.GetLogEventsOutput, error) + DescribeLogStreams(context.Context, *cloudwatchlogs.DescribeLogStreamsInput, ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.DescribeLogStreamsOutput, error) + GetLogEvents(context.Context, *cloudwatchlogs.GetLogEventsInput, ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.GetLogEventsOutput, error) } // CloudWatchLogs wraps an AWS Cloudwatch Logs client. @@ -54,10 +55,10 @@ type LogEventsOpts struct { LogStreamLimit int } -// New returns a CloudWatchLogs configured against the input session. -func New(s *session.Session) *CloudWatchLogs { +// New returns a CloudWatchLogs configured against the input SDK v2 config. +func New(cfg awsv2.Config) *CloudWatchLogs { return &CloudWatchLogs{ - client: cloudwatchlogs.New(s), + client: cloudwatchlogs.NewFromConfig(cfg), } } @@ -67,10 +68,10 @@ func (c *CloudWatchLogs) logStreams(logGroup string, logStreamLimit int, logStre logStreamsResp := &cloudwatchlogs.DescribeLogStreamsOutput{} for { var err error - logStreamsResp, err = c.client.DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ - LogGroupName: aws.String(logGroup), - Descending: aws.Bool(true), - OrderBy: aws.String(cloudwatchlogs.OrderByLastEventTime), + logStreamsResp, err = c.client.DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ + LogGroupName: awsv2.String(logGroup), + Descending: awsv2.Bool(true), + OrderBy: types.OrderByLastEventTime, NextToken: logStreamsResp.NextToken, }) if err != nil { @@ -82,7 +83,7 @@ func (c *CloudWatchLogs) logStreams(logGroup string, logStreamLimit int, logStre var streams []string for _, logStream := range logStreamsResp.LogStreams { - name := aws.StringValue(logStream.LogStreamName) + name := awsv2.ToString(logStream.LogStreamName) if name == "" { continue } @@ -96,7 +97,7 @@ func (c *CloudWatchLogs) logStreams(logGroup string, logStreamLimit int, logStre if logStreamLimit != 0 && len(logStreamNames) >= logStreamLimit { break } - if token := logStreamsResp.NextToken; aws.StringValue(token) == "" { + if token := logStreamsResp.NextToken; awsv2.ToString(token) == "" { break } } @@ -119,14 +120,14 @@ func (c *CloudWatchLogs) LogEvents(opts LogEventsOpts) (*LogEventsOutput, error) } for _, logStream := range logStreams { // Set override value - in.SetLogStreamName(logStream) + in.LogStreamName = awsv2.String(logStream) if streamLastEventTime[logStream] != 0 { // If last event for this log stream exists, increment last log event timestamp // by one to get logs after the last event. - in.SetStartTime(streamLastEventTime[logStream] + 1) + in.StartTime = awsv2.Int64(streamLastEventTime[logStream] + 1) } // TODO: https://github.com/aproint/copilot-cli/pull/628#discussion_r374291068 and https://github.com/aproint/copilot-cli/pull/628#discussion_r374294362 - resp, err := c.client.GetLogEvents(in) + resp, err := c.client.GetLogEvents(context.Background(), in) if err != nil { return nil, fmt.Errorf("get log events of %s/%s: %w", opts.LogGroup, logStream, err) } @@ -134,9 +135,9 @@ func (c *CloudWatchLogs) LogEvents(opts LogEventsOpts) (*LogEventsOutput, error) for _, event := range resp.Events { log := &Event{ LogStreamName: logStream, - IngestionTime: aws.Int64Value(event.IngestionTime), - Message: aws.StringValue(event.Message), - Timestamp: aws.Int64Value(event.Timestamp), + IngestionTime: awsv2.ToInt64(event.IngestionTime), + Message: awsv2.ToString(event.Message), + Timestamp: awsv2.ToInt64(event.Timestamp), } events = append(events, log) } @@ -145,7 +146,7 @@ func (c *CloudWatchLogs) LogEvents(opts LogEventsOpts) (*LogEventsOutput, error) } } sort.SliceStable(events, func(i, j int) bool { return events[i].Timestamp < events[j].Timestamp }) - limit := int(aws.Int64Value(in.Limit)) + limit := int(awsv2.ToInt32(in.Limit)) if limit != 0 { return &LogEventsOutput{ Events: truncateEvents(limit, events), @@ -174,13 +175,21 @@ func truncateStreams(limit int, streams []string) []string { func initGetLogEventsInput(opts LogEventsOpts) *cloudwatchlogs.GetLogEventsInput { return &cloudwatchlogs.GetLogEventsInput{ - LogGroupName: aws.String(opts.LogGroup), + LogGroupName: awsv2.String(opts.LogGroup), StartTime: opts.StartTime, EndTime: opts.EndTime, - Limit: opts.Limit, + Limit: int64ToInt32Ptr(opts.Limit), } } +func int64ToInt32Ptr(v *int64) *int32 { + if v == nil { + return nil + } + converted := int32(*v) + return &converted +} + // Example: if the prefixes is []string{"a"} and all is []string{"a", "b", "ab"} // then it returns []string{"a", "ab"}. Empty string prefixes are not supported. func filterStringSliceByPrefix(all, prefixes []string) []string { diff --git a/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs_test.go b/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs_test.go index 83bcaa1ccdb..530415e5cc1 100644 --- a/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs_test.go +++ b/internal/pkg/aws/cloudwatchlogs/cloudwatchlogs_test.go @@ -4,13 +4,15 @@ package cloudwatchlogs import ( + "context" "errors" "fmt" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatchlogs/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatchlogs" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" + "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -35,12 +37,12 @@ func TestLogEvents(t *testing.T) { logGroupName: "mockLogGroup", logStream: []string{"copilot/mockLogGroup/foo", "copilot/mockLogGroup/bar"}, mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{ + LogStreams: []types.LogStream{ { LogStreamName: aws.String("copilot/mockLogGroup/fooLogStream"), }, @@ -53,11 +55,11 @@ func TestLogEvents(t *testing.T) { }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/fooLogStream"), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("some log"), Timestamp: aws.Int64(1), @@ -65,11 +67,11 @@ func TestLogEvents(t *testing.T) { }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/barLogStream"), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("other log"), Timestamp: aws.Int64(0), @@ -103,24 +105,24 @@ func TestLogEvents(t *testing.T) { "copilot/mockLogGroup/mockLogStream": 1234890, }, mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{ + LogStreams: []types.LogStream{ { LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), }, }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ StartTime: aws.Int64(1234891), LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("some log"), Timestamp: aws.Int64(1234892), @@ -145,24 +147,24 @@ func TestLogEvents(t *testing.T) { logGroupName: "mockLogGroup", limit: aws.Int64(1), mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{ + LogStreams: []types.LogStream{ { LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), }, }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ - Limit: aws.Int64(1), + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ + Limit: aws.Int32(1), LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("some log"), Timestamp: aws.Int64(0), @@ -190,10 +192,10 @@ func TestLogEvents(t *testing.T) { "returns error if fail to describe log streams": { logGroupName: "mockLogGroup", mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(nil, mockError) }, @@ -203,12 +205,12 @@ func TestLogEvents(t *testing.T) { "returns error if no log stream found": { logGroupName: "mockLogGroup", mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{}, + LogStreams: []types.LogStream{}, }, nil) }, @@ -218,18 +220,18 @@ func TestLogEvents(t *testing.T) { "returns error if fail to get log events": { logGroupName: "mockLogGroup", mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{ + LogStreams: []types.LogStream{ { LogStreamName: aws.String("mockLogStream"), }, }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("mockLogStream"), }).Return(nil, mockError) @@ -242,12 +244,12 @@ func TestLogEvents(t *testing.T) { logGroupName: "mockLogGroup", logStream: []string{"copilot/"}, mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{ + LogStreams: []types.LogStream{ { LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), }, @@ -256,11 +258,11 @@ func TestLogEvents(t *testing.T) { }, }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("some log"), Timestamp: aws.Int64(0), @@ -286,12 +288,12 @@ func TestLogEvents(t *testing.T) { limit: aws.Int64(2), logStream: []string{"copilot/"}, mockcloudwatchlogsClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLogStreams(&cloudwatchlogs.DescribeLogStreamsInput{ + m.EXPECT().DescribeLogStreams(context.Background(), &cloudwatchlogs.DescribeLogStreamsInput{ LogGroupName: aws.String("mockLogGroup"), Descending: aws.Bool(true), - OrderBy: aws.String("LastEventTime"), + OrderBy: types.OrderByLastEventTime, }).Return(&cloudwatchlogs.DescribeLogStreamsOutput{ - LogStreams: []*cloudwatchlogs.LogStream{ + LogStreams: []types.LogStream{ { LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), LastEventTimestamp: aws.Int64(5), @@ -310,24 +312,24 @@ func TestLogEvents(t *testing.T) { }, }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream"), - Limit: aws.Int64(2), + Limit: aws.Int32(2), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("some log"), Timestamp: aws.Int64(5), }, }, }, nil) - m.EXPECT().GetLogEvents(&cloudwatchlogs.GetLogEventsInput{ + m.EXPECT().GetLogEvents(context.Background(), &cloudwatchlogs.GetLogEventsInput{ LogGroupName: aws.String("mockLogGroup"), LogStreamName: aws.String("copilot/mockLogGroup/mockLogStream2"), - Limit: aws.Int64(2), + Limit: aws.Int32(2), }).Return(&cloudwatchlogs.GetLogEventsOutput{ - Events: []*cloudwatchlogs.OutputLogEvent{ + Events: []types.OutputLogEvent{ { Message: aws.String("other log"), Timestamp: aws.Int64(1), diff --git a/internal/pkg/aws/cloudwatchlogs/mocks/mock_cloudwatchlogs.go b/internal/pkg/aws/cloudwatchlogs/mocks/mock_cloudwatchlogs.go index 660824d1c95..dad2962a653 100644 --- a/internal/pkg/aws/cloudwatchlogs/mocks/mock_cloudwatchlogs.go +++ b/internal/pkg/aws/cloudwatchlogs/mocks/mock_cloudwatchlogs.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - cloudwatchlogs "github.com/aws/aws-sdk-go/service/cloudwatchlogs" + cloudwatchlogs "github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs" gomock "github.com/golang/mock/gomock" ) @@ -35,31 +36,41 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeLogStreams mocks base method. -func (m *Mockapi) DescribeLogStreams(input *cloudwatchlogs.DescribeLogStreamsInput) (*cloudwatchlogs.DescribeLogStreamsOutput, error) { +func (m *Mockapi) DescribeLogStreams(arg0 context.Context, arg1 *cloudwatchlogs.DescribeLogStreamsInput, arg2 ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.DescribeLogStreamsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeLogStreams", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeLogStreams", varargs...) ret0, _ := ret[0].(*cloudwatchlogs.DescribeLogStreamsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeLogStreams indicates an expected call of DescribeLogStreams. -func (mr *MockapiMockRecorder) DescribeLogStreams(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeLogStreams(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeLogStreams", reflect.TypeOf((*Mockapi)(nil).DescribeLogStreams), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeLogStreams", reflect.TypeOf((*Mockapi)(nil).DescribeLogStreams), varargs...) } // GetLogEvents mocks base method. -func (m *Mockapi) GetLogEvents(input *cloudwatchlogs.GetLogEventsInput) (*cloudwatchlogs.GetLogEventsOutput, error) { +func (m *Mockapi) GetLogEvents(arg0 context.Context, arg1 *cloudwatchlogs.GetLogEventsInput, arg2 ...func(*cloudwatchlogs.Options)) (*cloudwatchlogs.GetLogEventsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetLogEvents", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetLogEvents", varargs...) ret0, _ := ret[0].(*cloudwatchlogs.GetLogEventsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetLogEvents indicates an expected call of GetLogEvents. -func (mr *MockapiMockRecorder) GetLogEvents(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetLogEvents(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogEvents", reflect.TypeOf((*Mockapi)(nil).GetLogEvents), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLogEvents", reflect.TypeOf((*Mockapi)(nil).GetLogEvents), varargs...) } diff --git a/internal/pkg/aws/iam/iam.go b/internal/pkg/aws/iam/iam.go index 44232140bbe..226f33a311a 100644 --- a/internal/pkg/aws/iam/iam.go +++ b/internal/pkg/aws/iam/iam.go @@ -5,14 +5,15 @@ package iam import ( + "context" + "errors" "fmt" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/iam" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/iam" + "github.com/aws/aws-sdk-go-v2/service/iam/types" ) const ( @@ -20,12 +21,12 @@ const ( ) type api interface { - ListRoleTags(input *iam.ListRoleTagsInput) (*iam.ListRoleTagsOutput, error) - DeleteRolePolicy(input *iam.DeleteRolePolicyInput) (*iam.DeleteRolePolicyOutput, error) - ListRolePolicies(input *iam.ListRolePoliciesInput) (*iam.ListRolePoliciesOutput, error) - DeleteRole(input *iam.DeleteRoleInput) (*iam.DeleteRoleOutput, error) - CreateServiceLinkedRole(input *iam.CreateServiceLinkedRoleInput) (*iam.CreateServiceLinkedRoleOutput, error) - ListPolicies(input *iam.ListPoliciesInput) (*iam.ListPoliciesOutput, error) + ListRoleTags(context.Context, *iam.ListRoleTagsInput, ...func(*iam.Options)) (*iam.ListRoleTagsOutput, error) + DeleteRolePolicy(context.Context, *iam.DeleteRolePolicyInput, ...func(*iam.Options)) (*iam.DeleteRolePolicyOutput, error) + ListRolePolicies(context.Context, *iam.ListRolePoliciesInput, ...func(*iam.Options)) (*iam.ListRolePoliciesOutput, error) + DeleteRole(context.Context, *iam.DeleteRoleInput, ...func(*iam.Options)) (*iam.DeleteRoleOutput, error) + CreateServiceLinkedRole(context.Context, *iam.CreateServiceLinkedRoleInput, ...func(*iam.Options)) (*iam.CreateServiceLinkedRoleOutput, error) + ListPolicies(context.Context, *iam.ListPoliciesInput, ...func(*iam.Options)) (*iam.ListPoliciesOutput, error) } // IAM wraps the AWS SDK's IAM client. @@ -33,10 +34,10 @@ type IAM struct { client api } -// New returns an IAM client configured against the input session. -func New(s *session.Session) *IAM { +// New returns an IAM client configured against the input SDK v2 config. +func New(cfg awsv2.Config) *IAM { return &IAM{ - client: iam.New(s), + client: iam.NewFromConfig(cfg), } } @@ -45,17 +46,17 @@ func (c *IAM) ListRoleTags(roleName string) (map[string]string, error) { tags := make(map[string]string) var marker *string for { - out, err := c.client.ListRoleTags(&iam.ListRoleTagsInput{ - RoleName: aws.String(roleName), + out, err := c.client.ListRoleTags(context.Background(), &iam.ListRoleTagsInput{ + RoleName: awsv2.String(roleName), Marker: marker, }) if err != nil { return nil, fmt.Errorf("list role tags for role %s and marker %v: %w", roleName, marker, err) } for _, tag := range out.Tags { - tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + tags[awsv2.ToString(tag.Key)] = awsv2.ToString(tag.Value) } - if !aws.BoolValue(out.IsTruncated) { + if !out.IsTruncated { return tags, nil } marker = out.Marker @@ -75,8 +76,8 @@ func (c *IAM) DeleteRole(roleNameOrARN string) error { if err := c.deleteRolePolicies(roleName); err != nil { return err } - if _, err := c.client.DeleteRole(&iam.DeleteRoleInput{ - RoleName: aws.String(roleName), + if _, err := c.client.DeleteRole(context.Background(), &iam.DeleteRoleInput{ + RoleName: awsv2.String(roleName), }); err != nil { if isNotExistErr(err) { // The role does not exist, exit successfully. @@ -91,8 +92,8 @@ func (c *IAM) DeleteRole(roleNameOrARN string) error { // This role is necessary so that Amazon ECS can call AWS APIs. // https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using-service-linked-roles.html func (c *IAM) CreateECSServiceLinkedRole() error { - if _, err := c.client.CreateServiceLinkedRole(&iam.CreateServiceLinkedRoleInput{ - AWSServiceName: aws.String(ecsServiceName), + if _, err := c.client.CreateServiceLinkedRole(context.Background(), &iam.CreateServiceLinkedRoleInput{ + AWSServiceName: awsv2.String(ecsServiceName), }); err != nil { return fmt.Errorf("create service linked role for %s: %w", ecsServiceName, err) } @@ -101,26 +102,26 @@ func (c *IAM) CreateECSServiceLinkedRole() error { // ListPolicyNames returns a list of local policy names. func (c *IAM) ListPolicyNames() ([]string, error) { - var policies []*iam.Policy + var policies []types.Policy var marker *string for { - output, err := c.client.ListPolicies(&iam.ListPoliciesInput{ + output, err := c.client.ListPolicies(context.Background(), &iam.ListPoliciesInput{ Marker: marker, - Scope: aws.String("Local"), - PolicyUsageFilter: aws.String("PermissionsBoundary"), + Scope: types.PolicyScopeTypeLocal, + PolicyUsageFilter: types.PolicyUsageTypePermissionsBoundary, }) if err != nil { return nil, fmt.Errorf("list IAM policies: %w", err) } policies = append(policies, output.Policies...) - if !aws.BoolValue(output.IsTruncated) { + if !output.IsTruncated { break } marker = output.Marker } var policyNames = make([]string, len(policies)) for i, policy := range policies { - policyNames[i] = aws.StringValue(policy.PolicyName) + policyNames[i] = awsv2.ToString(policy.PolicyName) } return policyNames, nil } @@ -131,23 +132,23 @@ func (c *IAM) deleteRolePolicies(roleName string) error { return err } for _, policyName := range policyNames { - if _, err := c.client.DeleteRolePolicy(&iam.DeleteRolePolicyInput{ - PolicyName: policyName, - RoleName: aws.String(roleName), + if _, err := c.client.DeleteRolePolicy(context.Background(), &iam.DeleteRolePolicyInput{ + PolicyName: awsv2.String(policyName), + RoleName: awsv2.String(roleName), }); err != nil { - return fmt.Errorf("delete policy named %s in role %s: %w", aws.StringValue(policyName), roleName, err) + return fmt.Errorf("delete policy named %s in role %s: %w", policyName, roleName, err) } } return nil } -func (c *IAM) listRolePolicyNames(roleName string) ([]*string, error) { - var policyNames []*string +func (c *IAM) listRolePolicyNames(roleName string) ([]string, error) { + var policyNames []string var marker *string for { - out, err := c.client.ListRolePolicies(&iam.ListRolePoliciesInput{ + out, err := c.client.ListRolePolicies(context.Background(), &iam.ListRolePoliciesInput{ Marker: marker, - RoleName: aws.String(roleName), + RoleName: awsv2.String(roleName), }) if err != nil { if isNotExistErr(err) { @@ -156,7 +157,7 @@ func (c *IAM) listRolePolicyNames(roleName string) ([]*string, error) { return nil, fmt.Errorf("list role policies for role %s: %v", roleName, err) } policyNames = append(policyNames, out.PolicyNames...) - if !aws.BoolValue(out.IsTruncated) { + if !out.IsTruncated { return policyNames, nil } marker = out.Marker @@ -164,14 +165,6 @@ func (c *IAM) listRolePolicyNames(roleName string) ([]*string, error) { } func isNotExistErr(err error) bool { - aerr, ok := err.(awserr.Error) - if !ok { - return false - } - switch aerr.Code() { - case iam.ErrCodeNoSuchEntityException: - return true - default: - return false - } + var notFound *types.NoSuchEntityException + return errors.As(err, ¬Found) } diff --git a/internal/pkg/aws/iam/iam_test.go b/internal/pkg/aws/iam/iam_test.go index b82f074006b..6735ba28998 100644 --- a/internal/pkg/aws/iam/iam_test.go +++ b/internal/pkg/aws/iam/iam_test.go @@ -4,13 +4,14 @@ package iam import ( + "context" "errors" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/iam/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/iam" + "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" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -27,7 +28,7 @@ func TestIAM_ListRoleTags(t *testing.T) { inRoleName: "read-only", inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListRoleTags(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().ListRoleTags(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedErr: errors.New("list role tags for role read-only and marker : some error"), @@ -37,23 +38,23 @@ func TestIAM_ListRoleTags(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) gomock.InOrder( - m.EXPECT().ListRoleTags(&iam.ListRoleTagsInput{ + m.EXPECT().ListRoleTags(context.Background(), &iam.ListRoleTagsInput{ RoleName: aws.String("read-only"), }).Return(&iam.ListRoleTagsOutput{ - IsTruncated: aws.Bool(true), + IsTruncated: true, Marker: aws.String("marker"), - Tags: []*iam.Tag{ + Tags: []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String("hello"), }, }, }, nil), - m.EXPECT().ListRoleTags(&iam.ListRoleTagsInput{ + m.EXPECT().ListRoleTags(context.Background(), &iam.ListRoleTagsInput{ RoleName: aws.String("read-only"), Marker: aws.String("marker"), }).Return(&iam.ListRoleTagsOutput{ - Tags: []*iam.Tag{ + Tags: []types.Tag{ { Key: aws.String("copilot-environment"), Value: aws.String("world"), @@ -105,11 +106,11 @@ func TestIAM_DeleteRole(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListRolePolicies(&iam.ListRolePoliciesInput{ + ListRolePolicies(context.Background(), &iam.ListRolePoliciesInput{ RoleName: aws.String("phonetool-test-CFNExecutionRole"), }). Return(nil, errors.New("some error")) - m.EXPECT().DeleteRolePolicy(gomock.Any()).Times(0) + m.EXPECT().DeleteRolePolicy(gomock.Any(), gomock.Any()).Times(0) return m }, wantedErr: errors.New("list role policies for role phonetool-test-CFNExecutionRole: some error"), @@ -119,11 +120,11 @@ func TestIAM_DeleteRole(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListRolePolicies(gomock.Any()). + ListRolePolicies(gomock.Any(), gomock.Any()). Return(&iam.ListRolePoliciesOutput{ - PolicyNames: []*string{aws.String("policy1")}, + PolicyNames: []string{"policy1"}, }, nil) - m.EXPECT().DeleteRolePolicy(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DeleteRolePolicy(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedErr: errors.New("delete policy named policy1 in role phonetool-test-CFNExecutionRole: some error"), @@ -133,9 +134,9 @@ func TestIAM_DeleteRole(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListRolePolicies(gomock.Any()). + ListRolePolicies(gomock.Any(), gomock.Any()). Return(&iam.ListRolePoliciesOutput{}, nil) - m.EXPECT().DeleteRole(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DeleteRole(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedErr: errors.New("delete role named phonetool-test-CFNExecutionRole: some error"), @@ -145,9 +146,9 @@ func TestIAM_DeleteRole(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListRolePolicies(gomock.Any()). - Return(nil, awserr.New(iam.ErrCodeNoSuchEntityException, "does not exist", nil)) - m.EXPECT().DeleteRole(gomock.Any()).Return(nil, awserr.New(iam.ErrCodeNoSuchEntityException, "does not exist", nil)) + ListRolePolicies(gomock.Any(), gomock.Any()). + Return(nil, &types.NoSuchEntityException{}) + m.EXPECT().DeleteRole(gomock.Any(), gomock.Any()).Return(nil, &types.NoSuchEntityException{}) return m }, }, @@ -156,23 +157,23 @@ func TestIAM_DeleteRole(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListRolePolicies(&iam.ListRolePoliciesInput{ + ListRolePolicies(context.Background(), &iam.ListRolePoliciesInput{ RoleName: aws.String("phonetool-test-CFNExecutionRole"), }). Return(&iam.ListRolePoliciesOutput{ - PolicyNames: []*string{aws.String("policy1"), aws.String("policy2")}, + PolicyNames: []string{"policy1", "policy2"}, }, nil) gomock.InOrder( - m.EXPECT().DeleteRolePolicy(&iam.DeleteRolePolicyInput{ + m.EXPECT().DeleteRolePolicy(context.Background(), &iam.DeleteRolePolicyInput{ PolicyName: aws.String("policy1"), RoleName: aws.String("phonetool-test-CFNExecutionRole"), }).Return(nil, nil), - m.EXPECT().DeleteRolePolicy(&iam.DeleteRolePolicyInput{ + m.EXPECT().DeleteRolePolicy(context.Background(), &iam.DeleteRolePolicyInput{ PolicyName: aws.String("policy2"), RoleName: aws.String("phonetool-test-CFNExecutionRole"), }).Return(nil, nil), ) - m.EXPECT().DeleteRole(&iam.DeleteRoleInput{ + m.EXPECT().DeleteRole(context.Background(), &iam.DeleteRoleInput{ RoleName: aws.String("phonetool-test-CFNExecutionRole"), }).Return(nil, nil) return m @@ -212,7 +213,7 @@ func TestIAM_CreateECSServiceLinkedRole(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - CreateServiceLinkedRole(gomock.Any()). + CreateServiceLinkedRole(gomock.Any(), gomock.Any()). Return(nil, errors.New("some error")) return m }, @@ -254,7 +255,7 @@ func TestIAM_ListPolicies(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListPolicies(gomock.Any()). + ListPolicies(gomock.Any(), gomock.Any()). Return(nil, errors.New("some error")) return m }, @@ -265,9 +266,9 @@ func TestIAM_ListPolicies(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.Mockapi { m := mocks.NewMockapi(ctrl) m.EXPECT(). - ListPolicies(gomock.Any()). + ListPolicies(gomock.Any(), gomock.Any()). Return(&iam.ListPoliciesOutput{ - Policies: []*iam.Policy{ + Policies: []types.Policy{ { PolicyName: aws.String("myFirstPolicyName"), }, diff --git a/internal/pkg/aws/iam/mocks/mock_iam.go b/internal/pkg/aws/iam/mocks/mock_iam.go index 973b3781dd3..a105217d2a9 100644 --- a/internal/pkg/aws/iam/mocks/mock_iam.go +++ b/internal/pkg/aws/iam/mocks/mock_iam.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - iam "github.com/aws/aws-sdk-go/service/iam" + iam "github.com/aws/aws-sdk-go-v2/service/iam" gomock "github.com/golang/mock/gomock" ) @@ -35,91 +36,121 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // CreateServiceLinkedRole mocks base method. -func (m *Mockapi) CreateServiceLinkedRole(input *iam.CreateServiceLinkedRoleInput) (*iam.CreateServiceLinkedRoleOutput, error) { +func (m *Mockapi) CreateServiceLinkedRole(arg0 context.Context, arg1 *iam.CreateServiceLinkedRoleInput, arg2 ...func(*iam.Options)) (*iam.CreateServiceLinkedRoleOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateServiceLinkedRole", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateServiceLinkedRole", varargs...) ret0, _ := ret[0].(*iam.CreateServiceLinkedRoleOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateServiceLinkedRole indicates an expected call of CreateServiceLinkedRole. -func (mr *MockapiMockRecorder) CreateServiceLinkedRole(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) CreateServiceLinkedRole(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateServiceLinkedRole", reflect.TypeOf((*Mockapi)(nil).CreateServiceLinkedRole), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateServiceLinkedRole", reflect.TypeOf((*Mockapi)(nil).CreateServiceLinkedRole), varargs...) } // DeleteRole mocks base method. -func (m *Mockapi) DeleteRole(input *iam.DeleteRoleInput) (*iam.DeleteRoleOutput, error) { +func (m *Mockapi) DeleteRole(arg0 context.Context, arg1 *iam.DeleteRoleInput, arg2 ...func(*iam.Options)) (*iam.DeleteRoleOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRole", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteRole", varargs...) ret0, _ := ret[0].(*iam.DeleteRoleOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteRole indicates an expected call of DeleteRole. -func (mr *MockapiMockRecorder) DeleteRole(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DeleteRole(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRole", reflect.TypeOf((*Mockapi)(nil).DeleteRole), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRole", reflect.TypeOf((*Mockapi)(nil).DeleteRole), varargs...) } // DeleteRolePolicy mocks base method. -func (m *Mockapi) DeleteRolePolicy(input *iam.DeleteRolePolicyInput) (*iam.DeleteRolePolicyOutput, error) { +func (m *Mockapi) DeleteRolePolicy(arg0 context.Context, arg1 *iam.DeleteRolePolicyInput, arg2 ...func(*iam.Options)) (*iam.DeleteRolePolicyOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteRolePolicy", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteRolePolicy", varargs...) ret0, _ := ret[0].(*iam.DeleteRolePolicyOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteRolePolicy indicates an expected call of DeleteRolePolicy. -func (mr *MockapiMockRecorder) DeleteRolePolicy(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DeleteRolePolicy(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRolePolicy", reflect.TypeOf((*Mockapi)(nil).DeleteRolePolicy), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRolePolicy", reflect.TypeOf((*Mockapi)(nil).DeleteRolePolicy), varargs...) } // ListPolicies mocks base method. -func (m *Mockapi) ListPolicies(input *iam.ListPoliciesInput) (*iam.ListPoliciesOutput, error) { +func (m *Mockapi) ListPolicies(arg0 context.Context, arg1 *iam.ListPoliciesInput, arg2 ...func(*iam.Options)) (*iam.ListPoliciesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListPolicies", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListPolicies", varargs...) ret0, _ := ret[0].(*iam.ListPoliciesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListPolicies indicates an expected call of ListPolicies. -func (mr *MockapiMockRecorder) ListPolicies(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListPolicies(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPolicies", reflect.TypeOf((*Mockapi)(nil).ListPolicies), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPolicies", reflect.TypeOf((*Mockapi)(nil).ListPolicies), varargs...) } // ListRolePolicies mocks base method. -func (m *Mockapi) ListRolePolicies(input *iam.ListRolePoliciesInput) (*iam.ListRolePoliciesOutput, error) { +func (m *Mockapi) ListRolePolicies(arg0 context.Context, arg1 *iam.ListRolePoliciesInput, arg2 ...func(*iam.Options)) (*iam.ListRolePoliciesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListRolePolicies", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListRolePolicies", varargs...) ret0, _ := ret[0].(*iam.ListRolePoliciesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListRolePolicies indicates an expected call of ListRolePolicies. -func (mr *MockapiMockRecorder) ListRolePolicies(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListRolePolicies(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRolePolicies", reflect.TypeOf((*Mockapi)(nil).ListRolePolicies), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRolePolicies", reflect.TypeOf((*Mockapi)(nil).ListRolePolicies), varargs...) } // ListRoleTags mocks base method. -func (m *Mockapi) ListRoleTags(input *iam.ListRoleTagsInput) (*iam.ListRoleTagsOutput, error) { +func (m *Mockapi) ListRoleTags(arg0 context.Context, arg1 *iam.ListRoleTagsInput, arg2 ...func(*iam.Options)) (*iam.ListRoleTagsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListRoleTags", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListRoleTags", varargs...) ret0, _ := ret[0].(*iam.ListRoleTagsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListRoleTags indicates an expected call of ListRoleTags. -func (mr *MockapiMockRecorder) ListRoleTags(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListRoleTags(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRoleTags", reflect.TypeOf((*Mockapi)(nil).ListRoleTags), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListRoleTags", reflect.TypeOf((*Mockapi)(nil).ListRoleTags), varargs...) } diff --git a/internal/pkg/aws/route53/mocks/mock_route53.go b/internal/pkg/aws/route53/mocks/mock_route53.go index bf4c18edf11..6a60555fcac 100644 --- a/internal/pkg/aws/route53/mocks/mock_route53.go +++ b/internal/pkg/aws/route53/mocks/mock_route53.go @@ -9,7 +9,7 @@ import ( net "net" reflect "reflect" - route53 "github.com/aws/aws-sdk-go/service/route53" + route53 "github.com/aws/aws-sdk-go-v2/service/route53" gomock "github.com/golang/mock/gomock" ) @@ -37,33 +37,43 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // ListHostedZonesByName mocks base method. -func (m *Mockapi) ListHostedZonesByName(arg0 *route53.ListHostedZonesByNameInput) (*route53.ListHostedZonesByNameOutput, error) { +func (m *Mockapi) ListHostedZonesByName(arg0 context.Context, arg1 *route53.ListHostedZonesByNameInput, arg2 ...func(*route53.Options)) (*route53.ListHostedZonesByNameOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListHostedZonesByName", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListHostedZonesByName", varargs...) ret0, _ := ret[0].(*route53.ListHostedZonesByNameOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListHostedZonesByName indicates an expected call of ListHostedZonesByName. -func (mr *MockapiMockRecorder) ListHostedZonesByName(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListHostedZonesByName(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListHostedZonesByName", reflect.TypeOf((*Mockapi)(nil).ListHostedZonesByName), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListHostedZonesByName", reflect.TypeOf((*Mockapi)(nil).ListHostedZonesByName), varargs...) } // ListResourceRecordSets mocks base method. -func (m *Mockapi) ListResourceRecordSets(arg0 *route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) { +func (m *Mockapi) ListResourceRecordSets(arg0 context.Context, arg1 *route53.ListResourceRecordSetsInput, arg2 ...func(*route53.Options)) (*route53.ListResourceRecordSetsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListResourceRecordSets", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListResourceRecordSets", varargs...) ret0, _ := ret[0].(*route53.ListResourceRecordSetsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListResourceRecordSets indicates an expected call of ListResourceRecordSets. -func (mr *MockapiMockRecorder) ListResourceRecordSets(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListResourceRecordSets(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListResourceRecordSets", reflect.TypeOf((*Mockapi)(nil).ListResourceRecordSets), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListResourceRecordSets", reflect.TypeOf((*Mockapi)(nil).ListResourceRecordSets), varargs...) } // MocknameserverResolver is a mock of nameserverResolver interface. diff --git a/internal/pkg/aws/route53/route53.go b/internal/pkg/aws/route53/route53.go index dba9258ab5e..dfea829ecfc 100644 --- a/internal/pkg/aws/route53/route53.go +++ b/internal/pkg/aws/route53/route53.go @@ -11,9 +11,9 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/route53" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/route53" + "github.com/aws/aws-sdk-go-v2/service/route53/types" ) const ( @@ -23,8 +23,8 @@ const ( ) type api interface { - ListHostedZonesByName(*route53.ListHostedZonesByNameInput) (*route53.ListHostedZonesByNameOutput, error) - ListResourceRecordSets(*route53.ListResourceRecordSetsInput) (*route53.ListResourceRecordSetsOutput, error) + ListHostedZonesByName(context.Context, *route53.ListHostedZonesByNameInput, ...func(*route53.Options)) (*route53.ListHostedZonesByNameOutput, error) + ListResourceRecordSets(context.Context, *route53.ListResourceRecordSetsInput, ...func(*route53.Options)) (*route53.ListResourceRecordSetsOutput, error) } type nameserverResolver interface { @@ -39,10 +39,11 @@ type Route53 struct { hostedZoneIDFor map[string]string } -// New returns a Route53 struct configured against the input session. -func New(s *session.Session) *Route53 { +// New returns a Route53 struct configured against the input SDK v2 config. +func New(cfg awsv2.Config) *Route53 { + cfg.Region = route53Region return &Route53{ - client: route53.New(s, aws.NewConfig().WithRegion(route53Region)), + client: route53.NewFromConfig(cfg), dns: new(net.Resolver), hostedZoneIDFor: make(map[string]string), } @@ -54,8 +55,8 @@ func (r53 *Route53) PublicDomainHostedZoneID(domainName string) (string, error) return id, nil } - in := &route53.ListHostedZonesByNameInput{DNSName: aws.String(domainName)} - resp, err := r53.client.ListHostedZonesByName(in) + in := &route53.ListHostedZonesByNameInput{DNSName: awsv2.String(domainName)} + resp, err := r53.client.ListHostedZonesByName(context.Background(), in) if err != nil { return "", fmt.Errorf("list hosted zone for %s: %w", domainName, err) } @@ -63,17 +64,17 @@ func (r53 *Route53) PublicDomainHostedZoneID(domainName string) (string, error) hostedZones := filterHostedZones(resp.HostedZones, matchesDomain(domainName), matchesPublic()) if len(hostedZones) > 0 { // return the first match. - id := strings.TrimPrefix(aws.StringValue(hostedZones[0].Id), "/hostedzone/") + id := strings.TrimPrefix(awsv2.ToString(hostedZones[0].Id), "/hostedzone/") r53.hostedZoneIDFor[domainName] = id return id, nil } - if !aws.BoolValue(resp.IsTruncated) { + if !resp.IsTruncated { return "", &ErrDomainHostedZoneNotFound{ domainName: domainName, } } in = &route53.ListHostedZonesByNameInput{DNSName: resp.NextDNSName, HostedZoneId: resp.NextHostedZoneId} - resp, err = r53.client.ListHostedZonesByName(in) + resp, err = r53.client.ListHostedZonesByName(context.Background(), in) if err != nil { return "", fmt.Errorf("list hosted zone for %s: %w", domainName, err) } @@ -111,22 +112,22 @@ func (r53 *Route53) ValidateDomainOwnership(domainName string) error { } func (r53 *Route53) listHostedZoneNSRecords(domainName, hostedZoneID string) ([]string, error) { - out, err := r53.client.ListResourceRecordSets(&route53.ListResourceRecordSetsInput{ - HostedZoneId: aws.String(hostedZoneID), + out, err := r53.client.ListResourceRecordSets(context.Background(), &route53.ListResourceRecordSetsInput{ + HostedZoneId: awsv2.String(hostedZoneID), }) if err != nil { return nil, fmt.Errorf("list resource record sets for hosted zone ID %q: %w", hostedZoneID, err) } var records []string for _, set := range out.ResourceRecordSets { - if aws.StringValue(set.Type) != "NS" { + if set.Type != types.RRTypeNs { continue } - if name := aws.StringValue(set.Name); !(name == domainName || name == domainName+".") /* filter only for parent domain */ { + if name := awsv2.ToString(set.Name); !(name == domainName || name == domainName+".") /* filter only for parent domain */ { continue } for _, record := range set.ResourceRecords { - records = append(records, cleanNSRecord(aws.StringValue(record.Value))) + records = append(records, cleanNSRecord(awsv2.ToString(record.Value))) } } return records, nil @@ -147,11 +148,11 @@ func (r53 *Route53) lookupNSRecords(domainName string) ([]string, error) { return records, nil } -type filterZoneFunc func(*route53.HostedZone) bool +type filterZoneFunc func(types.HostedZone) bool -func filterHostedZones(zones []*route53.HostedZone, filterFuncs ...filterZoneFunc) []*route53.HostedZone { - var hostedZones []*route53.HostedZone - passesAllFilters := func(zone *route53.HostedZone) bool { +func filterHostedZones(zones []types.HostedZone, filterFuncs ...filterZoneFunc) []types.HostedZone { + var hostedZones []types.HostedZone + passesAllFilters := func(zone types.HostedZone) bool { for _, fn := range filterFuncs { if !fn(zone) { return false @@ -168,15 +169,18 @@ func filterHostedZones(zones []*route53.HostedZone, filterFuncs ...filterZoneFun } func matchesDomain(domain string) filterZoneFunc { - return func(z *route53.HostedZone) bool { + return func(z types.HostedZone) bool { // example.com. should match example.com - return domain == aws.StringValue(z.Name) || domain+"." == aws.StringValue(z.Name) + return domain == awsv2.ToString(z.Name) || domain+"." == awsv2.ToString(z.Name) } } func matchesPublic() filterZoneFunc { - return func(config *route53.HostedZone) bool { - return !aws.BoolValue(config.Config.PrivateZone) + return func(zone types.HostedZone) bool { + if zone.Config == nil { + return true + } + return !zone.Config.PrivateZone } } diff --git a/internal/pkg/aws/route53/route53_test.go b/internal/pkg/aws/route53/route53_test.go index 6087ea996b1..b2decdeb64c 100644 --- a/internal/pkg/aws/route53/route53_test.go +++ b/internal/pkg/aws/route53/route53_test.go @@ -4,14 +4,16 @@ package route53 import ( + "context" "errors" "fmt" "net" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/route53/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/route53" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/route53" + "github.com/aws/aws-sdk-go-v2/service/route53/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -27,16 +29,16 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { "domain exists": { domainName: "mockDomain.com", mockRoute53Client: func(m *mocks.Mockapi) { - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain.com"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(false), - HostedZones: []*route53.HostedZone{ + IsTruncated: false, + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain.com"), Id: aws.String("mockID"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, @@ -48,16 +50,16 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { "DNS with subdomain": { domainName: "mockDomain.subdomain.com", mockRoute53Client: func(m *mocks.Mockapi) { - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain.subdomain.com"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(false), - HostedZones: []*route53.HostedZone{ + IsTruncated: false, + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain.subdomain.com."), Id: aws.String("mockID"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, @@ -69,40 +71,40 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { "domain exists within more than one page": { domainName: "mockDomain3.com", mockRoute53Client: func(m *mocks.Mockapi) { - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain3.com"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(true), + IsTruncated: true, NextDNSName: aws.String("mockDomain2.com"), NextHostedZoneId: aws.String("mockID"), - HostedZones: []*route53.HostedZone{ + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain1.com"), Id: aws.String("mockID1"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, }, nil) - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain2.com"), HostedZoneId: aws.String("mockID"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(false), - HostedZones: []*route53.HostedZone{ + IsTruncated: false, + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain2.com"), Id: aws.String("mockID2"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, { Name: aws.String("mockDomain3.com"), Id: aws.String("mockID3"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, @@ -114,37 +116,37 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { "domain does not exist": { domainName: "mockDomain4.com", mockRoute53Client: func(m *mocks.Mockapi) { - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain4.com"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(true), + IsTruncated: true, NextDNSName: aws.String("mockDomain2.com"), NextHostedZoneId: aws.String("mockID"), - HostedZones: []*route53.HostedZone{ + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain1.com"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, }, nil) - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain2.com"), HostedZoneId: aws.String("mockID"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(false), - HostedZones: []*route53.HostedZone{ + IsTruncated: false, + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain2.com"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, { Name: aws.String("mockDomain3.com"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, @@ -157,7 +159,7 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { "failed to validate if domain exists": { domainName: "mockDomain.com", mockRoute53Client: func(m *mocks.Mockapi) { - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain.com"), }).Return(nil, errors.New("some error")) }, @@ -166,47 +168,47 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { "filter and pick the first public hosted zone": { domainName: "mockDomain3.com", mockRoute53Client: func(m *mocks.Mockapi) { - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain3.com"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(true), + IsTruncated: true, NextDNSName: aws.String("mockDomain2.com"), NextHostedZoneId: aws.String("mockID"), - HostedZones: []*route53.HostedZone{ + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain1.com"), Id: aws.String("mockID1"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, }, nil) - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("mockDomain2.com"), HostedZoneId: aws.String("mockID"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(false), - HostedZones: []*route53.HostedZone{ + IsTruncated: false, + HostedZones: []types.HostedZone{ { Name: aws.String("mockDomain3.com"), Id: aws.String("mockID2"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(true), + Config: &types.HostedZoneConfig{ + PrivateZone: true, }, }, { Name: aws.String("mockDomain3.com"), Id: aws.String("mockID3"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, { Name: aws.String("mockDomain3.com"), Id: aws.String("mockID4"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, @@ -246,16 +248,16 @@ func TestRoute53_DomainHostedZoneID(t *testing.T) { defer ctrl.Finish() m := mocks.NewMockapi(ctrl) - m.EXPECT().ListHostedZonesByName(&route53.ListHostedZonesByNameInput{ + m.EXPECT().ListHostedZonesByName(context.Background(), &route53.ListHostedZonesByNameInput{ DNSName: aws.String("example.com"), }).Return(&route53.ListHostedZonesByNameOutput{ - IsTruncated: aws.Bool(false), - HostedZones: []*route53.HostedZone{ + IsTruncated: false, + HostedZones: []types.HostedZone{ { Name: aws.String("example.com"), Id: aws.String("Z0698117FUWMJ87C39TF"), - Config: &route53.HostedZoneConfig{ - PrivateZone: aws.Bool(false), + Config: &types.HostedZoneConfig{ + PrivateZone: false, }, }, }, @@ -284,7 +286,7 @@ func TestRoute53_ValidateDomainOwnership(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockAWS := mocks.NewMockapi(ctrl) - mockAWS.EXPECT().ListResourceRecordSets(gomock.Any()).Return(nil, errors.New("some error")) + mockAWS.EXPECT().ListResourceRecordSets(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) r53 := Route53{ client: mockAWS, hostedZoneIDFor: map[string]string{ @@ -303,7 +305,7 @@ func TestRoute53_ValidateDomainOwnership(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockAWS := mocks.NewMockapi(ctrl) - mockAWS.EXPECT().ListResourceRecordSets(gomock.Any()).Return(&route53.ListResourceRecordSetsOutput{}, nil) + mockAWS.EXPECT().ListResourceRecordSets(gomock.Any(), gomock.Any()).Return(&route53.ListResourceRecordSetsOutput{}, nil) mockResolver := mocks.NewMocknameserverResolver(ctrl) mockResolver.EXPECT().LookupNS(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) @@ -326,12 +328,12 @@ func TestRoute53_ValidateDomainOwnership(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockAWS := mocks.NewMockapi(ctrl) - mockAWS.EXPECT().ListResourceRecordSets(gomock.Any()).Return(&route53.ListResourceRecordSetsOutput{ - ResourceRecordSets: []*route53.ResourceRecordSet{ + mockAWS.EXPECT().ListResourceRecordSets(gomock.Any(), gomock.Any()).Return(&route53.ListResourceRecordSetsOutput{ + ResourceRecordSets: []types.ResourceRecordSet{ { Name: aws.String("example.com."), - Type: aws.String("NS"), - ResourceRecords: []*route53.ResourceRecord{ + Type: types.RRTypeNs, + ResourceRecords: []types.ResourceRecord{ { Value: aws.String("ns-1119.awsdns-11.org."), }, @@ -372,14 +374,14 @@ func TestRoute53_ValidateDomainOwnership(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockAWS := mocks.NewMockapi(ctrl) - mockAWS.EXPECT().ListResourceRecordSets(&route53.ListResourceRecordSetsInput{ + mockAWS.EXPECT().ListResourceRecordSets(context.Background(), &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String("Z0698117FUWMJ87C39TF"), }).Return(&route53.ListResourceRecordSetsOutput{ - ResourceRecordSets: []*route53.ResourceRecordSet{ + ResourceRecordSets: []types.ResourceRecordSet{ { Name: aws.String("example.com."), - Type: aws.String("NS"), - ResourceRecords: []*route53.ResourceRecord{ + Type: types.RRTypeNs, + ResourceRecords: []types.ResourceRecord{ { Value: aws.String("dns-ns1.amazon.com."), }, @@ -390,8 +392,8 @@ func TestRoute53_ValidateDomainOwnership(t *testing.T) { }, { Name: aws.String("demo.example.com."), - Type: aws.String("NS"), - ResourceRecords: []*route53.ResourceRecord{ + Type: types.RRTypeNs, + ResourceRecords: []types.ResourceRecord{ { Value: aws.String("ns-473.awsdns-59.com"), }, @@ -428,14 +430,14 @@ func TestRoute53_ValidateDomainOwnership(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() mockAWS := mocks.NewMockapi(ctrl) - mockAWS.EXPECT().ListResourceRecordSets(&route53.ListResourceRecordSetsInput{ + mockAWS.EXPECT().ListResourceRecordSets(context.Background(), &route53.ListResourceRecordSetsInput{ HostedZoneId: aws.String("Z0698117FUWMJ87C39TF"), }).Return(&route53.ListResourceRecordSetsOutput{ - ResourceRecordSets: []*route53.ResourceRecordSet{ + ResourceRecordSets: []types.ResourceRecordSet{ { Name: aws.String("example.com."), - Type: aws.String("NS"), - ResourceRecords: []*route53.ResourceRecord{ + Type: types.RRTypeNs, + ResourceRecords: []types.ResourceRecord{ { Value: aws.String("dns-ns1.amazon.com."), }, diff --git a/internal/pkg/cli/app_init.go b/internal/pkg/cli/app_init.go index eb7d153b3dc..98e8cdbf9fa 100644 --- a/internal/pkg/cli/app_init.go +++ b/internal/pkg/cli/app_init.go @@ -74,12 +74,12 @@ func newInitAppOpts(vars initAppVars) (*initAppOpts, error) { fs := afero.NewOsFs() cfg := v2ConfigFromSessionRegion(sess) identity := identity.New(cfg) - iamClient := iam.New(sess) + iamClient := iam.New(v2ConfigFromSessionRegion(sess)) return &initAppOpts{ initAppVars: vars, identity: identity, store: config.NewSSMStore(identity, ssm.New(sess), aws.StringValue(sess.Config.Region)), - route53: route53.New(sess), + route53: route53.New(v2ConfigFromSessionRegion(sess)), cfn: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), prompt: prompt.New(), prog: termprogress.NewSpinner(log.DiagnosticWriter), diff --git a/internal/pkg/cli/app_upgrade.go b/internal/pkg/cli/app_upgrade.go index 81c8002b80e..c27b5029c11 100644 --- a/internal/pkg/cli/app_upgrade.go +++ b/internal/pkg/cli/app_upgrade.go @@ -67,7 +67,7 @@ func newAppUpgradeOpts(vars appUpgradeVars) (*appUpgradeOpts, error) { appUpgradeVars: vars, store: store, identity: identity.New(cfg), - route53: route53.New(sess), + route53: route53.New(v2ConfigFromSessionRegion(sess)), sel: selector.NewAppEnvSelector(prompt.New(), store), upgrader: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), newVersionGetter: func(appName string) (versionGetter, error) { diff --git a/internal/pkg/cli/deploy/backend.go b/internal/pkg/cli/deploy/backend.go index a95e9c9942d..b588d304ea3 100644 --- a/internal/pkg/cli/deploy/backend.go +++ b/internal/pkg/cli/deploy/backend.go @@ -46,7 +46,7 @@ func NewBackendDeployer(in *WorkloadDeployerInput) (*backendSvcDeployer, error) svcDeployer: svcDeployer, elbGetter: elbv2.New(svcDeployer.envSess), backendMft: bsMft, - aliasCertValidator: acm.New(svcDeployer.envSess), + aliasCertValidator: acm.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), }, nil } diff --git a/internal/pkg/cli/deploy/lbws.go b/internal/pkg/cli/deploy/lbws.go index 8e5a7d7727a..f4ce2c1f009 100644 --- a/internal/pkg/cli/deploy/lbws.go +++ b/internal/pkg/cli/deploy/lbws.go @@ -86,7 +86,7 @@ func NewLBWSDeployer(in *WorkloadDeployerInput) (*lbWebSvcDeployer, error) { sess := svcDeployer.envSess.Copy(&aws.Config{ Region: optionalRegion, }) - return acm.New(sess) + return acm.New(v2ConfigFromSessionRegion(sess)) }, }, nil } diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index ca4c3749dfb..29ddabe84f9 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -124,7 +124,7 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { return fmt.Errorf("create session from environment manager role %s in region %s: %w", env.ManagerRoleARN, env.Region, err) } o.rg = resourcegroupstaggingapi.New(sess) - o.iam = iam.New(sess) + o.iam = iam.New(v2ConfigFromSessionRegion(sess)) o.s3 = s3.New(sess) o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), sess) o.deployer = cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) diff --git a/internal/pkg/cli/env_init.go b/internal/pkg/cli/env_init.go index be526963cf6..2b9aae45b9c 100644 --- a/internal/pkg/cli/env_init.go +++ b/internal/pkg/cli/env_init.go @@ -363,7 +363,7 @@ func (o *initEnvOpts) initRuntimeClients() error { o.cfn = cloudformation.New(o.sess) } if o.iam == nil { - o.iam = iam.New(o.sess) + o.iam = iam.New(v2ConfigFromSessionRegion(o.sess)) } return nil } diff --git a/internal/pkg/cli/init.go b/internal/pkg/cli/init.go index 788ac3f34cf..d125e034884 100644 --- a/internal/pkg/cli/init.go +++ b/internal/pkg/cli/init.go @@ -121,7 +121,7 @@ func newInitOpts(vars initVars) (*initOpts, error) { spin := termprogress.NewSpinner(log.DiagnosticWriter) id := identity.New(v2ConfigFromSessionRegion(defaultSess)) deployer := cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) - iamClient := iam.New(defaultSess) + iamClient := iam.New(v2ConfigFromSessionRegion(defaultSess)) initAppCmd := &initAppOpts{ initAppVars: initAppVars{ name: vars.appName, diff --git a/internal/pkg/describe/status_describe.go b/internal/pkg/describe/status_describe.go index be9c5521c15..d73f9dea654 100644 --- a/internal/pkg/describe/status_describe.go +++ b/internal/pkg/describe/status_describe.go @@ -107,7 +107,7 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er svcDescriber: ecs.New(sess, v2ConfigFromSessionRegion(sess)), cwSvcGetter: cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), ecsSvcGetter: awsecs.New(sess), - aasSvcGetter: aas.New(sess), + aasSvcGetter: aas.New(v2ConfigFromSessionRegion(sess)), targetHealthGetter: elbv2.New(sess), }, nil } @@ -129,7 +129,7 @@ func NewAppRunnerStatusDescriber(opt *NewServiceStatusConfig) (*appRunnerStatusD env: opt.Env, svc: opt.Svc, svcDescriber: appRunnerSvcDescriber, - eventsGetter: cloudwatchlogs.New(appRunnerSvcDescriber.sess), + eventsGetter: cloudwatchlogs.New(v2ConfigFromSessionRegion(appRunnerSvcDescriber.sess)), }, nil } diff --git a/internal/pkg/logging/aws_config.go b/internal/pkg/logging/aws_config.go new file mode 100644 index 00000000000..a770049fc3e --- /dev/null +++ b/internal/pkg/logging/aws_config.go @@ -0,0 +1,15 @@ +package logging + +import ( + "context" + + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + awsv1 "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/session" +) + +func v2ConfigFromSessionRegion(sess *session.Session) awsv2.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), awsv1.StringValue(sess.Config.Region)) + return cfg +} diff --git a/internal/pkg/logging/task.go b/internal/pkg/logging/task.go index 1befd38620b..fcae136dc18 100644 --- a/internal/pkg/logging/task.go +++ b/internal/pkg/logging/task.go @@ -49,7 +49,7 @@ func NewTaskClient(sess *session.Session, groupName string, tasks []*task.Task) tasks: tasks, taskDescriber: ecs.New(sess), - eventsLogger: cloudwatchlogs.New(sess), + eventsLogger: cloudwatchlogs.New(v2ConfigFromSessionRegion(sess)), eventsWriter: log.OutputWriter, sleep: func() { diff --git a/internal/pkg/logging/workload.go b/internal/pkg/logging/workload.go index d9766e8827d..2645aff309c 100644 --- a/internal/pkg/logging/workload.go +++ b/internal/pkg/logging/workload.go @@ -49,7 +49,7 @@ func newWorkloadLogger(opts *NewWorkloadLoggerOpts) *workloadLogger { app: opts.App, env: opts.Env, name: opts.Name, - eventsGetter: cloudwatchlogs.New(opts.Sess), + eventsGetter: cloudwatchlogs.New(v2ConfigFromSessionRegion(opts.Sess)), w: log.OutputWriter, now: time.Now, } From 4e6c187a19169d9d6d697538d5e4f03a7016bb8a Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Mon, 6 Jul 2026 16:00:04 +0200 Subject: [PATCH 06/17] migrate another set --- internal/pkg/aws/codepipeline/codepipeline.go | 74 ++--- .../pkg/aws/codepipeline/codepipeline_test.go | 298 +++++++++--------- .../codepipeline/mocks/mock_codepipeline.go | 55 +++- internal/pkg/aws/ecr/ecr.go | 69 ++-- internal/pkg/aws/ecr/ecr_test.go | 116 +++---- internal/pkg/aws/ecr/mocks/mock_ecr.go | 55 +++- internal/pkg/aws/partitions/partition.go | 145 ++++++++- internal/pkg/cli/app_show.go | 2 +- internal/pkg/cli/deploy/workload.go | 2 +- internal/pkg/cli/env_delete.go | 3 +- internal/pkg/cli/job_delete.go | 2 +- internal/pkg/cli/pipeline_delete.go | 2 +- internal/pkg/cli/pipeline_show.go | 2 +- internal/pkg/cli/pipeline_status.go | 2 +- internal/pkg/cli/run_local.go | 2 +- internal/pkg/cli/svc_delete.go | 2 +- internal/pkg/cli/task_delete.go | 2 +- internal/pkg/cli/task_run.go | 2 +- .../deploy/cloudformation/cloudformation.go | 7 +- internal/pkg/describe/pipeline_show.go | 3 +- internal/pkg/describe/pipeline_status.go | 3 +- 21 files changed, 512 insertions(+), 336 deletions(-) diff --git a/internal/pkg/aws/codepipeline/codepipeline.go b/internal/pkg/aws/codepipeline/codepipeline.go index 5f836841080..ae1f3cedf5a 100644 --- a/internal/pkg/aws/codepipeline/codepipeline.go +++ b/internal/pkg/aws/codepipeline/codepipeline.go @@ -5,6 +5,7 @@ package codepipeline import ( + "context" "errors" "fmt" "time" @@ -14,17 +15,16 @@ import ( rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/term/color" awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" - cp "github.com/aws/aws-sdk-go/service/codepipeline" + "github.com/aws/aws-sdk-go-v2/aws/arn" + cp "github.com/aws/aws-sdk-go-v2/service/codepipeline" + "github.com/aws/aws-sdk-go-v2/service/codepipeline/types" ) type api interface { - GetPipeline(*cp.GetPipelineInput) (*cp.GetPipelineOutput, error) - GetPipelineState(*cp.GetPipelineStateInput) (*cp.GetPipelineStateOutput, error) - ListPipelineExecutions(input *cp.ListPipelineExecutionsInput) (*cp.ListPipelineExecutionsOutput, error) - RetryStageExecution(input *cp.RetryStageExecutionInput) (*cp.RetryStageExecutionOutput, error) + GetPipeline(context.Context, *cp.GetPipelineInput, ...func(*cp.Options)) (*cp.GetPipelineOutput, error) + GetPipelineState(context.Context, *cp.GetPipelineStateInput, ...func(*cp.Options)) (*cp.GetPipelineStateOutput, error) + ListPipelineExecutions(context.Context, *cp.ListPipelineExecutionsInput, ...func(*cp.Options)) (*cp.ListPipelineExecutionsOutput, error) + RetryStageExecution(context.Context, *cp.RetryStageExecutionInput, ...func(*cp.Options)) (*cp.RetryStageExecutionOutput, error) } type resourceGetter interface { @@ -102,10 +102,10 @@ func (ss StageState) AggregateStatus() string { return "" } -// New returns a CodePipeline client configured against the input session and SDK v2 Resource Groups config. -func New(s *session.Session, rgConfig awsv2.Config) *CodePipeline { +// New returns a CodePipeline client configured against the input SDK v2 configs. +func New(cpConfig awsv2.Config, rgConfig awsv2.Config) *CodePipeline { return &CodePipeline{ - client: cp.New(s), + client: cp.NewFromConfig(cpConfig), rgClient: rg.New(rgConfig), } } @@ -113,9 +113,9 @@ func New(s *session.Session, rgConfig awsv2.Config) *CodePipeline { // GetPipeline retrieves information from a given pipeline. func (c *CodePipeline) GetPipeline(name string) (*Pipeline, error) { input := &cp.GetPipelineInput{ - Name: aws.String(name), + Name: awsv2.String(name), } - resp, err := c.client.GetPipeline(input) + resp, err := c.client.GetPipeline(context.Background(), input) if err != nil { return nil, fmt.Errorf("get pipeline %s: %w", name, err) @@ -123,7 +123,7 @@ func (c *CodePipeline) GetPipeline(name string) (*Pipeline, error) { pipeline := resp.Pipeline metadata := resp.Metadata - pipelineArn := aws.StringValue(metadata.PipelineArn) + pipelineArn := awsv2.ToString(metadata.PipelineArn) parsedArn, err := arn.Parse(pipelineArn) if err != nil { @@ -140,7 +140,7 @@ func (c *CodePipeline) GetPipeline(name string) (*Pipeline, error) { } return &Pipeline{ - Name: aws.StringValue(pipeline.Name), + Name: awsv2.ToString(pipeline.Name), Region: parsedArn.Region, AccountID: parsedArn.AccountID, Stages: stages, @@ -164,13 +164,13 @@ func (c *CodePipeline) RetryStageExecution(pipelineName, stageName string) error return fmt.Errorf("retrieve pipeline execution ID: %w", err) } - if _, err = c.client.RetryStageExecution(&cp.RetryStageExecutionInput{ + if _, err = c.client.RetryStageExecution(context.Background(), &cp.RetryStageExecutionInput{ PipelineExecutionId: &executionID, PipelineName: &pipelineName, - RetryMode: aws.String(cp.StageRetryModeFailedActions), + RetryMode: types.StageRetryModeFailedActions, StageName: &stageName, }); err != nil { - noFailedActions := &cp.StageNotRetryableException{} + noFailedActions := &types.StageNotRetryableException{} if !errors.As(err, &noFailedActions) { return fmt.Errorf("retry pipeline source stage: %w", err) } @@ -181,9 +181,9 @@ func (c *CodePipeline) RetryStageExecution(pipelineName, stageName string) error // GetPipelineState retrieves status information from a given pipeline. func (c *CodePipeline) GetPipelineState(name string) (*PipelineState, error) { input := &cp.GetPipelineStateInput{ - Name: aws.String(name), + Name: awsv2.String(name), } - resp, err := c.client.GetPipelineState(input) + resp, err := c.client.GetPipelineState(context.Background(), input) if err != nil { return nil, fmt.Errorf("get pipeline state %s: %w", name, err) } @@ -191,12 +191,12 @@ func (c *CodePipeline) GetPipelineState(name string) (*PipelineState, error) { for _, stage := range resp.StageStates { var stageName string if stage.StageName != nil { - stageName = aws.StringValue(stage.StageName) + stageName = awsv2.ToString(stage.StageName) } var transition string if stage.InboundTransitionState != nil { transition = "DISABLED" - if *stage.InboundTransitionState.Enabled { + if stage.InboundTransitionState.Enabled { transition = "ENABLED" } } @@ -204,8 +204,8 @@ func (c *CodePipeline) GetPipelineState(name string) (*PipelineState, error) { for _, actionState := range stage.ActionStates { if actionState.LatestExecution != nil { actions = append(actions, StageAction{ - Name: aws.StringValue(actionState.ActionName), - Status: aws.StringValue(actionState.LatestExecution.Status), + Name: awsv2.ToString(actionState.ActionName), + Status: string(actionState.LatestExecution.Status), }) } } @@ -216,7 +216,7 @@ func (c *CodePipeline) GetPipelineState(name string) (*PipelineState, error) { }) } return &PipelineState{ - PipelineName: aws.StringValue(resp.PipelineName), + PipelineName: awsv2.ToString(resp.PipelineName), StageStates: stageStates, UpdatedAt: *resp.Updated, }, nil @@ -237,15 +237,15 @@ func (ss *StageState) HumanString() string { return tree.String() } -func (c *CodePipeline) getStage(s *cp.StageDeclaration) (*Stage, error) { - name := aws.StringValue(s.Name) +func (c *CodePipeline) getStage(s types.StageDeclaration) (*Stage, error) { + name := awsv2.ToString(s.Name) var category, provider, details string if len(s.Actions) > 0 { // Currently, we only support Source, Build and Deploy stages, all of which must contain at least one action. action := s.Actions[0] - category = aws.StringValue(action.ActionTypeId.Category) - provider = aws.StringValue(action.ActionTypeId.Provider) + category = string(action.ActionTypeId.Category) + provider = awsv2.ToString(action.ActionTypeId.Provider) config := action.Configuration @@ -255,18 +255,18 @@ func (c *CodePipeline) getStage(s *cp.StageDeclaration) (*Stage, error) { // https://docs.aws.amazon.com/codepipeline/latest/userguide/reference-pipeline-structure.html#structure-configuration-examples switch provider { case "GitHub": - details = fmt.Sprintf("Repository: %s/%s", aws.StringValue(config["Owner"]), aws.StringValue(config["Repo"])) + details = fmt.Sprintf("Repository: %s/%s", config["Owner"], config["Repo"]) case "CodeCommit": - details = fmt.Sprintf("Repository: %s", aws.StringValue(config["RepositoryName"])) + details = fmt.Sprintf("Repository: %s", config["RepositoryName"]) case "CodeStarSourceConnection": - details = fmt.Sprintf("Repository: %s", aws.StringValue(config["FullRepositoryId"])) + details = fmt.Sprintf("Repository: %s", config["FullRepositoryId"]) } case "Build": // Currently, we use CodeBuild only for the build stage: https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CodeBuild.html#action-reference-CodeBuild-config - details = fmt.Sprintf("BuildProject: %s", aws.StringValue(config["ProjectName"])) + details = fmt.Sprintf("BuildProject: %s", config["ProjectName"]) case "Deploy": // Currently, we use Cloudformation only for the build stage: https://docs.aws.amazon.com/codepipeline/latest/userguide/action-reference-CloudFormation.html#action-reference-CloudFormation-config - details = fmt.Sprintf("StackName: %s", aws.StringValue(config["StackName"])) + details = fmt.Sprintf("StackName: %s", config["StackName"]) } } @@ -282,17 +282,17 @@ func (c *CodePipeline) getStage(s *cp.StageDeclaration) (*Stage, error) { // pipelineExecutionID returns the ExecutionID of the most recent execution of a pipeline. func (c *CodePipeline) pipelineExecutionID(pipelineName string) (string, error) { input := &cp.ListPipelineExecutionsInput{ - MaxResults: aws.Int64(1), + MaxResults: awsv2.Int32(1), PipelineName: &pipelineName, } - output, err := c.client.ListPipelineExecutions(input) + output, err := c.client.ListPipelineExecutions(context.Background(), input) if err != nil { return "", fmt.Errorf("list pipeline execution for %s: %w", pipelineName, err) } if len(output.PipelineExecutionSummaries) == 0 { return "", fmt.Errorf("no pipeline execution IDs found for %s", pipelineName) } - return aws.StringValue(output.PipelineExecutionSummaries[0].PipelineExecutionId), nil + return awsv2.ToString(output.PipelineExecutionSummaries[0].PipelineExecutionId), nil } func (sa StageAction) humanString() string { diff --git a/internal/pkg/aws/codepipeline/codepipeline_test.go b/internal/pkg/aws/codepipeline/codepipeline_test.go index 23ecba9c97c..2cd3f2f693e 100644 --- a/internal/pkg/aws/codepipeline/codepipeline_test.go +++ b/internal/pkg/aws/codepipeline/codepipeline_test.go @@ -10,10 +10,10 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline/mocks" - "github.com/aws/aws-sdk-go/aws" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/codepipeline" + "github.com/aws/aws-sdk-go-v2/service/codepipeline/types" "github.com/golang/mock/gomock" - - "github.com/aws/aws-sdk-go/service/codepipeline" "github.com/stretchr/testify/require" ) @@ -27,104 +27,104 @@ func TestCodePipeline_GetPipeline(t *testing.T) { mockError := errors.New("mockError") mockTime := time.Now() mockArn := "arn:aws:codepipeline:us-west-2:1234567890:pipeline-dinder-badgoose-repo" - mockSourceStage := &codepipeline.StageDeclaration{ - Name: aws.String("Source"), - Actions: []*codepipeline.ActionDeclaration{ + mockSourceStage := types.StageDeclaration{ + Name: awsv2.String("Source"), + Actions: []types.ActionDeclaration{ { - ActionTypeId: &codepipeline.ActionTypeId{ - Category: aws.String("Source"), - Owner: aws.String("ThirdParty"), - Provider: aws.String("GitHub"), - Version: aws.String("1"), + ActionTypeId: &types.ActionTypeId{ + Category: types.ActionCategorySource, + Owner: types.ActionOwnerThirdParty, + Provider: awsv2.String("GitHub"), + Version: awsv2.String("1"), }, - Configuration: map[string]*string{ - "Owner": aws.String("badgoose"), - "Repo": aws.String("repo"), - "Branch": aws.String("main"), - "OAuthToken": aws.String("****"), + Configuration: map[string]string{ + "Owner": "badgoose", + "Repo": "repo", + "Branch": "main", + "OAuthToken": "****", }, - Name: aws.String("SourceCodeFor-dinder"), - OutputArtifacts: []*codepipeline.OutputArtifact{ + Name: awsv2.String("SourceCodeFor-dinder"), + OutputArtifacts: []types.OutputArtifact{ { - Name: aws.String("SCCheckoutArtifact"), + Name: awsv2.String("SCCheckoutArtifact"), }, }, - RunOrder: aws.Int64(1), + RunOrder: awsv2.Int32(1), }, }, } - mockBuildStage := &codepipeline.StageDeclaration{ - Name: aws.String("Build"), - Actions: []*codepipeline.ActionDeclaration{ + mockBuildStage := types.StageDeclaration{ + Name: awsv2.String("Build"), + Actions: []types.ActionDeclaration{ { - ActionTypeId: &codepipeline.ActionTypeId{ - Category: aws.String("Build"), - Owner: aws.String("AWS"), - Provider: aws.String("CodeBuild"), - Version: aws.String("1"), + ActionTypeId: &types.ActionTypeId{ + Category: types.ActionCategoryBuild, + Owner: types.ActionOwnerAws, + Provider: awsv2.String("CodeBuild"), + Version: awsv2.String("1"), }, - Configuration: map[string]*string{ - "ProjectName": aws.String("pipeline-dinder-badgoose-repo-BuildProject"), + Configuration: map[string]string{ + "ProjectName": "pipeline-dinder-badgoose-repo-BuildProject", }, - InputArtifacts: []*codepipeline.InputArtifact{ + InputArtifacts: []types.InputArtifact{ { - Name: aws.String("SCCheckoutArtifact"), + Name: awsv2.String("SCCheckoutArtifact"), }, }, - Name: aws.String("Build"), - OutputArtifacts: []*codepipeline.OutputArtifact{ + Name: awsv2.String("Build"), + OutputArtifacts: []types.OutputArtifact{ { - Name: aws.String("BuildOutput"), + Name: awsv2.String("BuildOutput"), }, }, - RunOrder: aws.Int64(1), + RunOrder: awsv2.Int32(1), }, }, } - mockTestStage := &codepipeline.StageDeclaration{ - Name: aws.String("DeployTo-test"), - Actions: []*codepipeline.ActionDeclaration{ + mockTestStage := types.StageDeclaration{ + Name: awsv2.String("DeployTo-test"), + Actions: []types.ActionDeclaration{ { - ActionTypeId: &codepipeline.ActionTypeId{ - Category: aws.String("Deploy"), - Owner: aws.String("AWS"), - Provider: aws.String("CloudFormation"), - Version: aws.String("1"), + ActionTypeId: &types.ActionTypeId{ + Category: types.ActionCategoryDeploy, + Owner: types.ActionOwnerAws, + Provider: awsv2.String("CloudFormation"), + Version: awsv2.String("1"), }, - Configuration: map[string]*string{ - "TemplatePath": aws.String("BuildOutput::infrastructure/test.stack.yml"), - "ActionMode": aws.String("CREATE_UPDATE"), - "Capabilities": aws.String("CAPABILITY_NAMED_IAM"), - "ChangeSetName": aws.String("dinder-test-test"), - "RoleArn": aws.String("arn:aws:iam::1234567890:role/trivia-test-CFNExecutionRole"), - "StackName": aws.String("dinder-test-test"), - "TemplateConfiguration": aws.String("BuildOutput::infrastructure/test-test.params.json"), + Configuration: map[string]string{ + "TemplatePath": "BuildOutput::infrastructure/test.stack.yml", + "ActionMode": "CREATE_UPDATE", + "Capabilities": "CAPABILITY_NAMED_IAM", + "ChangeSetName": "dinder-test-test", + "RoleArn": "arn:aws:iam::1234567890:role/trivia-test-CFNExecutionRole", + "StackName": "dinder-test-test", + "TemplateConfiguration": "BuildOutput::infrastructure/test-test.params.json", }, - InputArtifacts: []*codepipeline.InputArtifact{ - {Name: aws.String("BuildOutput")}, + InputArtifacts: []types.InputArtifact{ + {Name: awsv2.String("BuildOutput")}, }, - Name: aws.String("CreateOrUpdate-test-test"), - Region: aws.String("us-west-2"), - RoleArn: aws.String("arn:aws:iam::12344567890:role/dinder-test-EnvManagerRole"), - RunOrder: aws.Int64(2), + Name: awsv2.String("CreateOrUpdate-test-test"), + Region: awsv2.String("us-west-2"), + RoleArn: awsv2.String("arn:aws:iam::12344567890:role/dinder-test-EnvManagerRole"), + RunOrder: awsv2.Int32(2), }, }, } - mockStages := []*codepipeline.StageDeclaration{mockSourceStage, mockBuildStage, mockTestStage} + mockStages := []types.StageDeclaration{mockSourceStage, mockBuildStage, mockTestStage} - mockStageWithNoAction := &codepipeline.StageDeclaration{ - Name: aws.String("DummyStage"), - Actions: []*codepipeline.ActionDeclaration{}, + mockStageWithNoAction := types.StageDeclaration{ + Name: awsv2.String("DummyStage"), + Actions: []types.ActionDeclaration{}, } mockOutput := &codepipeline.GetPipelineOutput{ - Pipeline: &codepipeline.PipelineDeclaration{ - Name: aws.String(mockPipelineName), + Pipeline: &types.PipelineDeclaration{ + Name: awsv2.String(mockPipelineName), Stages: mockStages, }, - Metadata: &codepipeline.PipelineMetadata{ + Metadata: &types.PipelineMetadata{ Created: &mockTime, Updated: &mockTime, - PipelineArn: aws.String(mockArn), + PipelineArn: awsv2.String(mockArn), }, } @@ -138,8 +138,8 @@ func TestCodePipeline_GetPipeline(t *testing.T) { "happy path": { inPipelineName: mockPipelineName, callMocks: func(m codepipelineMocks) { - m.cp.EXPECT().GetPipeline(&codepipeline.GetPipelineInput{ - Name: aws.String(mockPipelineName), + m.cp.EXPECT().GetPipeline(gomock.Any(), &codepipeline.GetPipelineInput{ + Name: awsv2.String(mockPipelineName), }).Return(mockOutput, nil) }, @@ -175,18 +175,18 @@ func TestCodePipeline_GetPipeline(t *testing.T) { "should only populate stage name if stage has no actions": { inPipelineName: mockPipelineName, callMocks: func(m codepipelineMocks) { - m.cp.EXPECT().GetPipeline(&codepipeline.GetPipelineInput{ - Name: aws.String(mockPipelineName), + m.cp.EXPECT().GetPipeline(gomock.Any(), &codepipeline.GetPipelineInput{ + Name: awsv2.String(mockPipelineName), }).Return( &codepipeline.GetPipelineOutput{ - Pipeline: &codepipeline.PipelineDeclaration{ - Name: aws.String(mockPipelineName), - Stages: []*codepipeline.StageDeclaration{mockSourceStage, mockStageWithNoAction}, + Pipeline: &types.PipelineDeclaration{ + Name: awsv2.String(mockPipelineName), + Stages: []types.StageDeclaration{mockSourceStage, mockStageWithNoAction}, }, - Metadata: &codepipeline.PipelineMetadata{ + Metadata: &types.PipelineMetadata{ Created: &mockTime, Updated: &mockTime, - PipelineArn: aws.String(mockArn), + PipelineArn: awsv2.String(mockArn), }, }, nil) @@ -217,8 +217,8 @@ func TestCodePipeline_GetPipeline(t *testing.T) { "should wrap error from codepipeline client": { inPipelineName: mockPipelineName, callMocks: func(m codepipelineMocks) { - m.cp.EXPECT().GetPipeline(&codepipeline.GetPipelineInput{ - Name: aws.String(mockPipelineName), + m.cp.EXPECT().GetPipeline(gomock.Any(), &codepipeline.GetPipelineInput{ + Name: awsv2.String(mockPipelineName), }).Return(nil, mockError) }, @@ -260,56 +260,56 @@ func TestCodePipeline_GetPipelineState(t *testing.T) { mockPipelineName := "pipeline-dinder-badgoose-repo" mockTime := time.Now() mockOutput := &codepipeline.GetPipelineStateOutput{ - PipelineName: aws.String(mockPipelineName), - StageStates: []*codepipeline.StageState{ + PipelineName: awsv2.String(mockPipelineName), + StageStates: []types.StageState{ { - ActionStates: []*codepipeline.ActionState{ + ActionStates: []types.ActionState{ { - ActionName: aws.String("action1"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusSucceeded)}, + ActionName: awsv2.String("action1"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusSucceeded}, }, { - ActionName: aws.String("action2"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusSucceeded)}, + ActionName: awsv2.String("action2"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusSucceeded}, }, }, - StageName: aws.String("Source"), + StageName: awsv2.String("Source"), }, { - InboundTransitionState: &codepipeline.TransitionState{Enabled: aws.Bool(true)}, - ActionStates: []*codepipeline.ActionState{ + InboundTransitionState: &types.TransitionState{Enabled: true}, + ActionStates: []types.ActionState{ { - ActionName: aws.String("action1"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusFailed)}, + ActionName: awsv2.String("action1"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusFailed}, }, { - ActionName: aws.String("action2"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusInProgress)}, + ActionName: awsv2.String("action2"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusInProgress}, }, { - ActionName: aws.String("action3"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusSucceeded)}, + ActionName: awsv2.String("action3"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusSucceeded}, }, }, - StageName: aws.String("Build"), + StageName: awsv2.String("Build"), }, { - InboundTransitionState: &codepipeline.TransitionState{Enabled: aws.Bool(true)}, - ActionStates: []*codepipeline.ActionState{ + InboundTransitionState: &types.TransitionState{Enabled: true}, + ActionStates: []types.ActionState{ { - ActionName: aws.String("action1"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusSucceeded)}, + ActionName: awsv2.String("action1"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusSucceeded}, }, { - ActionName: aws.String("TestCommands"), - LatestExecution: &codepipeline.ActionExecution{Status: aws.String(codepipeline.ActionExecutionStatusFailed)}, + ActionName: awsv2.String("TestCommands"), + LatestExecution: &types.ActionExecution{Status: types.ActionExecutionStatusFailed}, }, }, - StageName: aws.String("DeployTo-test"), + StageName: awsv2.String("DeployTo-test"), }, { - InboundTransitionState: &codepipeline.TransitionState{Enabled: aws.Bool(false)}, - StageName: aws.String("DeployTo-prod"), + InboundTransitionState: &types.TransitionState{Enabled: false}, + StageName: awsv2.String("DeployTo-prod"), }, }, Updated: &mockTime, @@ -326,8 +326,8 @@ func TestCodePipeline_GetPipelineState(t *testing.T) { "happy path": { inPipelineName: mockPipelineName, callMocks: func(m codepipelineMocks) { - m.cp.EXPECT().GetPipelineState(&codepipeline.GetPipelineStateInput{ - Name: aws.String(mockPipelineName), + m.cp.EXPECT().GetPipelineState(gomock.Any(), &codepipeline.GetPipelineStateInput{ + Name: awsv2.String(mockPipelineName), }).Return(mockOutput, nil) }, @@ -392,8 +392,8 @@ func TestCodePipeline_GetPipelineState(t *testing.T) { "should wrap error from CodePipeline client": { inPipelineName: mockPipelineName, callMocks: func(m codepipelineMocks) { - m.cp.EXPECT().GetPipelineState(&codepipeline.GetPipelineStateInput{ - Name: aws.String(mockPipelineName), + m.cp.EXPECT().GetPipelineState(gomock.Any(), &codepipeline.GetPipelineStateInput{ + Name: awsv2.String(mockPipelineName), }).Return(nil, mockError) }, @@ -431,15 +431,15 @@ func TestCodePipeline_GetPipelineState(t *testing.T) { func TestCodePipeline_RetryStageExecution(t *testing.T) { mockPipelineName := "pipeline-dinder-badgoose-repo" mockStageName := "Source" - failedActions := codepipeline.StageRetryModeFailedActions - notRetryable := codepipeline.StageNotRetryableException{} - mockPipelineExecutionID := aws.String("12345678-fake-exec-utio-nid987654321") + failedActions := types.StageRetryModeFailedActions + notRetryable := &types.StageNotRetryableException{} + mockPipelineExecutionID := awsv2.String("12345678-fake-exec-utio-nid987654321") mockBadOutput := &codepipeline.ListPipelineExecutionsOutput{ - PipelineExecutionSummaries: []*codepipeline.PipelineExecutionSummary{}, + PipelineExecutionSummaries: []types.PipelineExecutionSummary{}, } mockErr := errors.New("some error") mockOutput := &codepipeline.RetryStageExecutionOutput{ - PipelineExecutionId: aws.String("12345678-fake-exec-utio-nid987654321"), + PipelineExecutionId: awsv2.String("12345678-fake-exec-utio-nid987654321"), } tests := map[string]struct { @@ -450,21 +450,23 @@ func TestCodePipeline_RetryStageExecution(t *testing.T) { "returns nil when executes as expected": { callMocks: func(m codepipelineMocks) { m.cp.EXPECT().ListPipelineExecutions( + gomock.Any(), &codepipeline.ListPipelineExecutionsInput{ - MaxResults: aws.Int64(1), - PipelineName: aws.String(mockPipelineName)}).Return(&codepipeline.ListPipelineExecutionsOutput{ - PipelineExecutionSummaries: []*codepipeline.PipelineExecutionSummary{ + MaxResults: awsv2.Int32(1), + PipelineName: awsv2.String(mockPipelineName)}).Return(&codepipeline.ListPipelineExecutionsOutput{ + PipelineExecutionSummaries: []types.PipelineExecutionSummary{ { - PipelineExecutionId: aws.String("12345678-fake-exec-utio-nid987654321"), + PipelineExecutionId: awsv2.String("12345678-fake-exec-utio-nid987654321"), }, }, }, nil) m.cp.EXPECT().RetryStageExecution( + gomock.Any(), &codepipeline.RetryStageExecutionInput{ PipelineExecutionId: mockPipelineExecutionID, - PipelineName: aws.String(mockPipelineName), - RetryMode: aws.String(failedActions), - StageName: aws.String(mockStageName), + PipelineName: awsv2.String(mockPipelineName), + RetryMode: failedActions, + StageName: awsv2.String(mockStageName), }).Return(mockOutput, nil) }, expectedOut: nil, @@ -472,37 +474,41 @@ func TestCodePipeline_RetryStageExecution(t *testing.T) { "catches error and returns nil if pipeline succeeds before failing so not a 'retry'": { callMocks: func(m codepipelineMocks) { m.cp.EXPECT().ListPipelineExecutions( + gomock.Any(), &codepipeline.ListPipelineExecutionsInput{ - MaxResults: aws.Int64(1), - PipelineName: aws.String(mockPipelineName)}).Return(&codepipeline.ListPipelineExecutionsOutput{ - PipelineExecutionSummaries: []*codepipeline.PipelineExecutionSummary{ + MaxResults: awsv2.Int32(1), + PipelineName: awsv2.String(mockPipelineName)}).Return(&codepipeline.ListPipelineExecutionsOutput{ + PipelineExecutionSummaries: []types.PipelineExecutionSummary{ { - PipelineExecutionId: aws.String("12345678-fake-exec-utio-nid987654321"), + PipelineExecutionId: awsv2.String("12345678-fake-exec-utio-nid987654321"), }, }, }, nil) m.cp.EXPECT().RetryStageExecution( + gomock.Any(), &codepipeline.RetryStageExecutionInput{ PipelineExecutionId: mockPipelineExecutionID, - PipelineName: aws.String(mockPipelineName), - RetryMode: aws.String(failedActions), - StageName: aws.String(mockStageName), - }).Return(nil, notRetryable.OrigErr()) // OrigErr always returns nil, so may not actually catch the StageNotRetryableException + PipelineName: awsv2.String(mockPipelineName), + RetryMode: failedActions, + StageName: awsv2.String(mockStageName), + }).Return(nil, notRetryable) }, expectedOut: nil, }, "returns wrapped error if ListPipelineExecutions fails": { callMocks: func(m codepipelineMocks) { m.cp.EXPECT().ListPipelineExecutions( + gomock.Any(), &codepipeline.ListPipelineExecutionsInput{ - MaxResults: aws.Int64(1), - PipelineName: aws.String(mockPipelineName)}).Return(nil, mockErr) + MaxResults: awsv2.Int32(1), + PipelineName: awsv2.String(mockPipelineName)}).Return(nil, mockErr) m.cp.EXPECT().RetryStageExecution( + gomock.Any(), &codepipeline.RetryStageExecutionInput{ PipelineExecutionId: mockPipelineExecutionID, - PipelineName: aws.String(mockPipelineName), - RetryMode: aws.String(failedActions), - StageName: aws.String(mockStageName), + PipelineName: awsv2.String(mockPipelineName), + RetryMode: failedActions, + StageName: awsv2.String(mockStageName), }).Times(0) }, expectedOut: nil, @@ -511,15 +517,17 @@ func TestCodePipeline_RetryStageExecution(t *testing.T) { "returns wrapped error if no pipeline execution IDs are returned": { callMocks: func(m codepipelineMocks) { m.cp.EXPECT().ListPipelineExecutions( + gomock.Any(), &codepipeline.ListPipelineExecutionsInput{ - MaxResults: aws.Int64(1), - PipelineName: aws.String(mockPipelineName)}).Return(mockBadOutput, nil) + MaxResults: awsv2.Int32(1), + PipelineName: awsv2.String(mockPipelineName)}).Return(mockBadOutput, nil) m.cp.EXPECT().RetryStageExecution( + gomock.Any(), &codepipeline.RetryStageExecutionInput{ PipelineExecutionId: mockPipelineExecutionID, - PipelineName: aws.String(mockPipelineName), - RetryMode: aws.String(failedActions), - StageName: aws.String(mockStageName), + PipelineName: awsv2.String(mockPipelineName), + RetryMode: failedActions, + StageName: awsv2.String(mockStageName), }).Times(0) }, expectedOut: nil, @@ -528,21 +536,23 @@ func TestCodePipeline_RetryStageExecution(t *testing.T) { "returns wrapped error if RetryStageExecution fails": { callMocks: func(m codepipelineMocks) { m.cp.EXPECT().ListPipelineExecutions( + gomock.Any(), &codepipeline.ListPipelineExecutionsInput{ - MaxResults: aws.Int64(1), - PipelineName: aws.String(mockPipelineName)}).Return(&codepipeline.ListPipelineExecutionsOutput{ - PipelineExecutionSummaries: []*codepipeline.PipelineExecutionSummary{ + MaxResults: awsv2.Int32(1), + PipelineName: awsv2.String(mockPipelineName)}).Return(&codepipeline.ListPipelineExecutionsOutput{ + PipelineExecutionSummaries: []types.PipelineExecutionSummary{ { - PipelineExecutionId: aws.String("12345678-fake-exec-utio-nid987654321"), + PipelineExecutionId: awsv2.String("12345678-fake-exec-utio-nid987654321"), }, }, }, nil) m.cp.EXPECT().RetryStageExecution( + gomock.Any(), &codepipeline.RetryStageExecutionInput{ PipelineExecutionId: mockPipelineExecutionID, - PipelineName: aws.String(mockPipelineName), - RetryMode: aws.String(failedActions), - StageName: aws.String(mockStageName), + PipelineName: awsv2.String(mockPipelineName), + RetryMode: failedActions, + StageName: awsv2.String(mockStageName), }).Return(nil, mockErr) }, expectedOut: nil, diff --git a/internal/pkg/aws/codepipeline/mocks/mock_codepipeline.go b/internal/pkg/aws/codepipeline/mocks/mock_codepipeline.go index f8eff29c917..bcced20368c 100644 --- a/internal/pkg/aws/codepipeline/mocks/mock_codepipeline.go +++ b/internal/pkg/aws/codepipeline/mocks/mock_codepipeline.go @@ -5,10 +5,11 @@ package mocks import ( + context "context" reflect "reflect" resourcegroups "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - codepipeline "github.com/aws/aws-sdk-go/service/codepipeline" + codepipeline "github.com/aws/aws-sdk-go-v2/service/codepipeline" gomock "github.com/golang/mock/gomock" ) @@ -36,63 +37,83 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // GetPipeline mocks base method. -func (m *Mockapi) GetPipeline(arg0 *codepipeline.GetPipelineInput) (*codepipeline.GetPipelineOutput, error) { +func (m *Mockapi) GetPipeline(arg0 context.Context, arg1 *codepipeline.GetPipelineInput, arg2 ...func(*codepipeline.Options)) (*codepipeline.GetPipelineOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPipeline", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetPipeline", varargs...) ret0, _ := ret[0].(*codepipeline.GetPipelineOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPipeline indicates an expected call of GetPipeline. -func (mr *MockapiMockRecorder) GetPipeline(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetPipeline(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPipeline", reflect.TypeOf((*Mockapi)(nil).GetPipeline), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPipeline", reflect.TypeOf((*Mockapi)(nil).GetPipeline), varargs...) } // GetPipelineState mocks base method. -func (m *Mockapi) GetPipelineState(arg0 *codepipeline.GetPipelineStateInput) (*codepipeline.GetPipelineStateOutput, error) { +func (m *Mockapi) GetPipelineState(arg0 context.Context, arg1 *codepipeline.GetPipelineStateInput, arg2 ...func(*codepipeline.Options)) (*codepipeline.GetPipelineStateOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPipelineState", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetPipelineState", varargs...) ret0, _ := ret[0].(*codepipeline.GetPipelineStateOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetPipelineState indicates an expected call of GetPipelineState. -func (mr *MockapiMockRecorder) GetPipelineState(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetPipelineState(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPipelineState", reflect.TypeOf((*Mockapi)(nil).GetPipelineState), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPipelineState", reflect.TypeOf((*Mockapi)(nil).GetPipelineState), varargs...) } // ListPipelineExecutions mocks base method. -func (m *Mockapi) ListPipelineExecutions(input *codepipeline.ListPipelineExecutionsInput) (*codepipeline.ListPipelineExecutionsOutput, error) { +func (m *Mockapi) ListPipelineExecutions(arg0 context.Context, arg1 *codepipeline.ListPipelineExecutionsInput, arg2 ...func(*codepipeline.Options)) (*codepipeline.ListPipelineExecutionsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListPipelineExecutions", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListPipelineExecutions", varargs...) ret0, _ := ret[0].(*codepipeline.ListPipelineExecutionsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListPipelineExecutions indicates an expected call of ListPipelineExecutions. -func (mr *MockapiMockRecorder) ListPipelineExecutions(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListPipelineExecutions(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPipelineExecutions", reflect.TypeOf((*Mockapi)(nil).ListPipelineExecutions), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListPipelineExecutions", reflect.TypeOf((*Mockapi)(nil).ListPipelineExecutions), varargs...) } // RetryStageExecution mocks base method. -func (m *Mockapi) RetryStageExecution(input *codepipeline.RetryStageExecutionInput) (*codepipeline.RetryStageExecutionOutput, error) { +func (m *Mockapi) RetryStageExecution(arg0 context.Context, arg1 *codepipeline.RetryStageExecutionInput, arg2 ...func(*codepipeline.Options)) (*codepipeline.RetryStageExecutionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RetryStageExecution", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "RetryStageExecution", varargs...) ret0, _ := ret[0].(*codepipeline.RetryStageExecutionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // RetryStageExecution indicates an expected call of RetryStageExecution. -func (mr *MockapiMockRecorder) RetryStageExecution(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) RetryStageExecution(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetryStageExecution", reflect.TypeOf((*Mockapi)(nil).RetryStageExecution), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RetryStageExecution", reflect.TypeOf((*Mockapi)(nil).RetryStageExecution), varargs...) } // MockresourceGetter is a mock of resourceGetter interface. diff --git a/internal/pkg/aws/ecr/ecr.go b/internal/pkg/aws/ecr/ecr.go index ac5025a5f13..36c816aed82 100644 --- a/internal/pkg/aws/ecr/ecr.go +++ b/internal/pkg/aws/ecr/ecr.go @@ -5,18 +5,17 @@ package ecr import ( + "context" "encoding/base64" "errors" "fmt" "strings" "github.com/aproint/copilot-cli/internal/pkg/term/log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ecr" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/ecr" + "github.com/aws/aws-sdk-go-v2/service/ecr/types" ) const ( @@ -27,10 +26,10 @@ const ( ) type api interface { - DescribeImages(*ecr.DescribeImagesInput) (*ecr.DescribeImagesOutput, error) - GetAuthorizationToken(*ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) - DescribeRepositories(*ecr.DescribeRepositoriesInput) (*ecr.DescribeRepositoriesOutput, error) - BatchDeleteImage(*ecr.BatchDeleteImageInput) (*ecr.BatchDeleteImageOutput, error) + DescribeImages(context.Context, *ecr.DescribeImagesInput, ...func(*ecr.Options)) (*ecr.DescribeImagesOutput, error) + GetAuthorizationToken(context.Context, *ecr.GetAuthorizationTokenInput, ...func(*ecr.Options)) (*ecr.GetAuthorizationTokenOutput, error) + DescribeRepositories(context.Context, *ecr.DescribeRepositoriesInput, ...func(*ecr.Options)) (*ecr.DescribeRepositoriesOutput, error) + BatchDeleteImage(context.Context, *ecr.BatchDeleteImageInput, ...func(*ecr.Options)) (*ecr.BatchDeleteImageOutput, error) } // ECR wraps an AWS ECR client. @@ -38,16 +37,16 @@ type ECR struct { client api } -// New returns a ECR configured against the input session. -func New(s *session.Session) ECR { +// New returns a ECR configured against the input SDK v2 config. +func New(cfg awsv2.Config) ECR { return ECR{ - client: ecr.New(s), + client: ecr.NewFromConfig(cfg), } } // Auth returns the basic authentication credentials needed to push images. func (c ECR) Auth() (username string, password string, err error) { - response, err := c.client.GetAuthorizationToken(&ecr.GetAuthorizationTokenInput{}) + response, err := c.client.GetAuthorizationToken(context.Background(), &ecr.GetAuthorizationTokenInput{}) if err != nil { return "", "", fmt.Errorf("get ECR auth: %w", err) @@ -65,8 +64,8 @@ func (c ECR) Auth() (username string, password string, err error) { // RepositoryURI returns the ECR repository URI. func (c ECR) RepositoryURI(name string) (string, error) { - result, err := c.client.DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RepositoryNames: aws.StringSlice([]string{name}), + result, err := c.client.DescribeRepositories(context.Background(), &ecr.DescribeRepositoriesInput{ + RepositoryNames: []string{name}, }) if err != nil { @@ -89,9 +88,9 @@ type Image struct { Digest string } -func (i Image) imageIdentifier() *ecr.ImageIdentifier { - return &ecr.ImageIdentifier{ - ImageDigest: aws.String(i.Digest), +func (i Image) imageIdentifier() types.ImageIdentifier { + return types.ImageIdentifier{ + ImageDigest: awsv2.String(i.Digest), } } @@ -99,20 +98,20 @@ func (i Image) imageIdentifier() *ecr.ImageIdentifier { // Image metadata for images in the input ECR repository name. func (c ECR) ListImages(repoName string) ([]Image, error) { var images []Image - resp, err := c.client.DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(repoName), + resp, err := c.client.DescribeImages(context.Background(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(repoName), }) if err != nil { return nil, fmt.Errorf("ecr repo %s describe images: %w", repoName, err) } for _, imageDetails := range resp.ImageDetails { images = append(images, Image{ - Digest: *imageDetails.ImageDigest, + Digest: awsv2.ToString(imageDetails.ImageDigest), }) } for resp.NextToken != nil { - resp, err = c.client.DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(repoName), + resp, err = c.client.DescribeImages(context.Background(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(repoName), NextToken: resp.NextToken, }) if err != nil { @@ -120,7 +119,7 @@ func (c ECR) ListImages(repoName string) ([]Image, error) { } for _, imageDetails := range resp.ImageDetails { images = append(images, Image{ - Digest: *imageDetails.ImageDigest, + Digest: awsv2.ToString(imageDetails.ImageDigest), }) } } @@ -133,18 +132,18 @@ func (c ECR) DeleteImages(images []Image, repoName string) error { return nil } - var imageIdentifiers []*ecr.ImageIdentifier + var imageIdentifiers []types.ImageIdentifier for _, image := range images { imageIdentifiers = append(imageIdentifiers, image.imageIdentifier()) } - var imageIdentifiersBatch [][]*ecr.ImageIdentifier + var imageIdentifiersBatch [][]types.ImageIdentifier for batchDeleteLimit < len(imageIdentifiers) { imageIdentifiers, imageIdentifiersBatch = imageIdentifiers[batchDeleteLimit:], append(imageIdentifiersBatch, imageIdentifiers[0:batchDeleteLimit]) } imageIdentifiersBatch = append(imageIdentifiersBatch, imageIdentifiers) for _, identifiers := range imageIdentifiersBatch { - resp, err := c.client.BatchDeleteImage(&ecr.BatchDeleteImageInput{ - RepositoryName: aws.String(repoName), + resp, err := c.client.BatchDeleteImage(context.Background(), &ecr.BatchDeleteImageInput{ + RepositoryName: awsv2.String(repoName), ImageIds: identifiers, }) if resp != nil { @@ -182,7 +181,7 @@ func URIFromARN(repositoryARN string) (string, error) { return "", fmt.Errorf("parsing repository ARN %s: %w", repositoryARN, err) } urlFmtStr := urlFmtString - if repoARN.Partition == endpoints.AwsCnPartitionID { + if repoARN.Partition == "aws-cn" { urlFmtStr = urlFmtStringForCN } // Repo ARNs look like arn:aws:ecr:region:012345678910:repository/test @@ -195,12 +194,6 @@ func URIFromARN(repositoryARN string) (string, error) { } func isRepoNotFoundErr(err error) bool { - aerr, ok := err.(awserr.Error) - if !ok { - return false - } - if aerr.Code() == "RepositoryNotFoundException" { - return true - } - return false + var repoNotFound *types.RepositoryNotFoundException + return errors.As(err, &repoNotFound) } diff --git a/internal/pkg/aws/ecr/ecr_test.go b/internal/pkg/aws/ecr/ecr_test.go index 4be903230f2..f6361da83c4 100644 --- a/internal/pkg/aws/ecr/ecr_test.go +++ b/internal/pkg/aws/ecr/ecr_test.go @@ -10,9 +10,9 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/ecr/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ecr" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecr" + "github.com/aws/aws-sdk-go-v2/service/ecr/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -34,16 +34,16 @@ func TestAuth(t *testing.T) { }{ "should return wrapped error given error returned from GetAuthorizationToken": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().GetAuthorizationToken(gomock.Any()).Return(nil, mockError) + m.EXPECT().GetAuthorizationToken(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantErr: fmt.Errorf("get ECR auth: %w", mockError), }, "should return Auth data": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().GetAuthorizationToken(gomock.Any()).Return(&ecr.GetAuthorizationTokenOutput{ - AuthorizationData: []*ecr.AuthorizationData{ + m.EXPECT().GetAuthorizationToken(gomock.Any(), gomock.Any()).Return(&ecr.GetAuthorizationTokenOutput{ + AuthorizationData: []types.AuthorizationData{ { - AuthorizationToken: aws.String(encoded), + AuthorizationToken: awsv2.String(encoded), }, }, }, nil) @@ -90,28 +90,28 @@ func TestRepositoryURI(t *testing.T) { }{ "should return wrapped error given error returned from DescribeRepositories": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRepositories(gomock.Any()).Return(nil, mockError) + m.EXPECT().DescribeRepositories(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantErr: fmt.Errorf("ecr describe repository %s: %w", mockRepoName, mockError), }, "should return error given no repositories returned in list": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RepositoryNames: aws.StringSlice([]string{mockRepoName}), + m.EXPECT().DescribeRepositories(gomock.Any(), &ecr.DescribeRepositoriesInput{ + RepositoryNames: []string{mockRepoName}, }).Return(&ecr.DescribeRepositoriesOutput{ - Repositories: []*ecr.Repository{}, + Repositories: []types.Repository{}, }, nil) }, wantErr: errors.New("no repositories found"), }, "should return repository URI": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRepositories(&ecr.DescribeRepositoriesInput{ - RepositoryNames: aws.StringSlice([]string{mockRepoName}), + m.EXPECT().DescribeRepositories(gomock.Any(), &ecr.DescribeRepositoriesInput{ + RepositoryNames: []string{mockRepoName}, }).Return(&ecr.DescribeRepositoriesOutput{ - Repositories: []*ecr.Repository{ + Repositories: []types.Repository{ { - RepositoryUri: aws.String(mockRepoURI), + RepositoryUri: awsv2.String(mockRepoURI), }, }, }, nil) @@ -197,17 +197,17 @@ func TestListImages(t *testing.T) { }{ "should wrap error returned by ECR DescribeImages": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(gomock.Any()).Return(nil, mockError) + m.EXPECT().DescribeImages(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantImages: nil, wantError: fmt.Errorf("ecr repo %s describe images: %w", mockRepoName, mockError), }, "should return Image list": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(gomock.Any()).Return(&ecr.DescribeImagesOutput{ - ImageDetails: []*ecr.ImageDetail{ + m.EXPECT().DescribeImages(gomock.Any(), gomock.Any()).Return(&ecr.DescribeImagesOutput{ + ImageDetails: []types.ImageDetail{ { - ImageDigest: aws.String(mockDigest), + ImageDigest: awsv2.String(mockDigest), }, }, }, nil) @@ -217,23 +217,23 @@ func TestListImages(t *testing.T) { }, "should return all images when paginated": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().DescribeImages(gomock.Any(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(mockRepoName), }).Return(&ecr.DescribeImagesOutput{ - ImageDetails: []*ecr.ImageDetail{ + ImageDetails: []types.ImageDetail{ { - ImageDigest: aws.String(mockDigest), + ImageDigest: awsv2.String(mockDigest), }, }, NextToken: &mockNextToken, }, nil) - m.EXPECT().DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().DescribeImages(gomock.Any(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(mockRepoName), NextToken: &mockNextToken, }).Return(&ecr.DescribeImagesOutput{ - ImageDetails: []*ecr.ImageDetail{ + ImageDetails: []types.ImageDetail{ { - ImageDigest: aws.String(mockDigest), + ImageDigest: awsv2.String(mockDigest), }, }, }, nil) @@ -276,7 +276,7 @@ func TestDeleteImages(t *testing.T) { mockFailCode := "400" mockFailReason := "some reason" // with only one image identifier - var imageIdentifiers []*ecr.ImageIdentifier + var imageIdentifiers []types.ImageIdentifier for _, image := range mockImages { imageIdentifiers = append(imageIdentifiers, image.imageIdentifier()) } @@ -285,7 +285,7 @@ func TestDeleteImages(t *testing.T) { mockBatchImages = append(mockBatchImages, mockImages[0]) } // with a batch limit number of image identifiers - var batchImageIdentifiers []*ecr.ImageIdentifier + var batchImageIdentifiers []types.ImageIdentifier for ii := 0; ii < batchDeleteLimit; ii++ { batchImageIdentifiers = append(batchImageIdentifiers, mockImages[0].imageIdentifier()) } @@ -304,15 +304,15 @@ func TestDeleteImages(t *testing.T) { "should wrap error return from BatchDeleteImage": { images: mockImages, mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().BatchDeleteImage(gomock.Any()).Return(nil, mockError) + m.EXPECT().BatchDeleteImage(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantError: fmt.Errorf("ecr repo %s batch delete image: %w", mockRepoName, mockError), }, "should return nil if call to BatchDeleteImage successful": { images: mockImages, mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().BatchDeleteImage(&ecr.BatchDeleteImageInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().BatchDeleteImage(gomock.Any(), &ecr.BatchDeleteImageInput{ + RepositoryName: awsv2.String(mockRepoName), ImageIds: imageIdentifiers, }).Return(&ecr.BatchDeleteImageOutput{}, nil) }, @@ -321,12 +321,12 @@ func TestDeleteImages(t *testing.T) { fmt.Sprintf("should be able to batch delete more than %d images", batchDeleteLimit): { images: mockBatchImages, mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().BatchDeleteImage(&ecr.BatchDeleteImageInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().BatchDeleteImage(gomock.Any(), &ecr.BatchDeleteImageInput{ + RepositoryName: awsv2.String(mockRepoName), ImageIds: batchImageIdentifiers, }).Return(&ecr.BatchDeleteImageOutput{}, nil).Times(1) - m.EXPECT().BatchDeleteImage(&ecr.BatchDeleteImageInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().BatchDeleteImage(gomock.Any(), &ecr.BatchDeleteImageInput{ + RepositoryName: awsv2.String(mockRepoName), ImageIds: imageIdentifiers, }).Return(&ecr.BatchDeleteImageOutput{}, nil).Times(1) }, @@ -335,15 +335,15 @@ func TestDeleteImages(t *testing.T) { "warns if fail to delete some images": { images: mockImages, mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().BatchDeleteImage(&ecr.BatchDeleteImageInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().BatchDeleteImage(gomock.Any(), &ecr.BatchDeleteImageInput{ + RepositoryName: awsv2.String(mockRepoName), ImageIds: imageIdentifiers, }).Return(&ecr.BatchDeleteImageOutput{ - Failures: []*ecr.ImageFailure{ + Failures: []types.ImageFailure{ { - FailureCode: &mockFailCode, + FailureCode: types.ImageFailureCode(mockFailCode), FailureReason: &mockFailReason, - ImageId: imageIdentifiers[0], + ImageId: &imageIdentifiers[0], }, }, }, nil) @@ -374,12 +374,12 @@ func TestDeleteImages(t *testing.T) { func TestClearRepository(t *testing.T) { mockRepoName := "mockRepoName" - mockAwsError := awserr.New("someErrorCode", "some error", nil) + mockAwsError := errors.New("some error") mockError := errors.New("some error") - mockRepoNotFoundError := awserr.New("RepositoryNotFoundException", "some error", nil) + mockRepoNotFoundError := &types.RepositoryNotFoundException{Message: awsv2.String("some error")} mockDigest := "mockDigest" - mockImageID := ecr.ImageIdentifier{ - ImageDigest: aws.String(mockDigest), + mockImageID := types.ImageIdentifier{ + ImageDigest: awsv2.String(mockDigest), } tests := map[string]struct { @@ -389,42 +389,42 @@ func TestClearRepository(t *testing.T) { }{ "should clear repo if exists": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().DescribeImages(gomock.Any(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(mockRepoName), }).Return(&ecr.DescribeImagesOutput{ - ImageDetails: []*ecr.ImageDetail{ + ImageDetails: []types.ImageDetail{ { - ImageDigest: aws.String(mockDigest), + ImageDigest: awsv2.String(mockDigest), }, }, }, nil) - m.EXPECT().BatchDeleteImage(&ecr.BatchDeleteImageInput{ - RepositoryName: aws.String(mockRepoName), - ImageIds: []*ecr.ImageIdentifier{&mockImageID}, + m.EXPECT().BatchDeleteImage(gomock.Any(), &ecr.BatchDeleteImageInput{ + RepositoryName: awsv2.String(mockRepoName), + ImageIds: []types.ImageIdentifier{mockImageID}, }).Return(&ecr.BatchDeleteImageOutput{}, nil) }, wantError: nil, }, "returns nil if repo not exists": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().DescribeImages(gomock.Any(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(mockRepoName), }).Return(nil, mockRepoNotFoundError) }, wantError: nil, }, "returns error if fail to check repo existence": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().DescribeImages(gomock.Any(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(mockRepoName), }).Return(nil, mockAwsError) }, wantError: fmt.Errorf("ecr repo mockRepoName describe images: %w", mockAwsError), }, "returns error if fail to check repo existence because of non-awserr error type": { mockECRClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeImages(&ecr.DescribeImagesInput{ - RepositoryName: aws.String(mockRepoName), + m.EXPECT().DescribeImages(gomock.Any(), &ecr.DescribeImagesInput{ + RepositoryName: awsv2.String(mockRepoName), }).Return(nil, mockError) }, wantError: fmt.Errorf("ecr repo mockRepoName describe images: %w", mockError), diff --git a/internal/pkg/aws/ecr/mocks/mock_ecr.go b/internal/pkg/aws/ecr/mocks/mock_ecr.go index 79115be81d6..ea0f2afb100 100644 --- a/internal/pkg/aws/ecr/mocks/mock_ecr.go +++ b/internal/pkg/aws/ecr/mocks/mock_ecr.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - ecr "github.com/aws/aws-sdk-go/service/ecr" + ecr "github.com/aws/aws-sdk-go-v2/service/ecr" gomock "github.com/golang/mock/gomock" ) @@ -35,61 +36,81 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // BatchDeleteImage mocks base method. -func (m *Mockapi) BatchDeleteImage(arg0 *ecr.BatchDeleteImageInput) (*ecr.BatchDeleteImageOutput, error) { +func (m *Mockapi) BatchDeleteImage(arg0 context.Context, arg1 *ecr.BatchDeleteImageInput, arg2 ...func(*ecr.Options)) (*ecr.BatchDeleteImageOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "BatchDeleteImage", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "BatchDeleteImage", varargs...) ret0, _ := ret[0].(*ecr.BatchDeleteImageOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // BatchDeleteImage indicates an expected call of BatchDeleteImage. -func (mr *MockapiMockRecorder) BatchDeleteImage(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) BatchDeleteImage(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchDeleteImage", reflect.TypeOf((*Mockapi)(nil).BatchDeleteImage), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BatchDeleteImage", reflect.TypeOf((*Mockapi)(nil).BatchDeleteImage), varargs...) } // DescribeImages mocks base method. -func (m *Mockapi) DescribeImages(arg0 *ecr.DescribeImagesInput) (*ecr.DescribeImagesOutput, error) { +func (m *Mockapi) DescribeImages(arg0 context.Context, arg1 *ecr.DescribeImagesInput, arg2 ...func(*ecr.Options)) (*ecr.DescribeImagesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeImages", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeImages", varargs...) ret0, _ := ret[0].(*ecr.DescribeImagesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeImages indicates an expected call of DescribeImages. -func (mr *MockapiMockRecorder) DescribeImages(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeImages(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeImages", reflect.TypeOf((*Mockapi)(nil).DescribeImages), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeImages", reflect.TypeOf((*Mockapi)(nil).DescribeImages), varargs...) } // DescribeRepositories mocks base method. -func (m *Mockapi) DescribeRepositories(arg0 *ecr.DescribeRepositoriesInput) (*ecr.DescribeRepositoriesOutput, error) { +func (m *Mockapi) DescribeRepositories(arg0 context.Context, arg1 *ecr.DescribeRepositoriesInput, arg2 ...func(*ecr.Options)) (*ecr.DescribeRepositoriesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeRepositories", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeRepositories", varargs...) ret0, _ := ret[0].(*ecr.DescribeRepositoriesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeRepositories indicates an expected call of DescribeRepositories. -func (mr *MockapiMockRecorder) DescribeRepositories(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeRepositories(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRepositories", reflect.TypeOf((*Mockapi)(nil).DescribeRepositories), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRepositories", reflect.TypeOf((*Mockapi)(nil).DescribeRepositories), varargs...) } // GetAuthorizationToken mocks base method. -func (m *Mockapi) GetAuthorizationToken(arg0 *ecr.GetAuthorizationTokenInput) (*ecr.GetAuthorizationTokenOutput, error) { +func (m *Mockapi) GetAuthorizationToken(arg0 context.Context, arg1 *ecr.GetAuthorizationTokenInput, arg2 ...func(*ecr.Options)) (*ecr.GetAuthorizationTokenOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAuthorizationToken", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetAuthorizationToken", varargs...) ret0, _ := ret[0].(*ecr.GetAuthorizationTokenOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetAuthorizationToken indicates an expected call of GetAuthorizationToken. -func (mr *MockapiMockRecorder) GetAuthorizationToken(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) GetAuthorizationToken(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizationToken", reflect.TypeOf((*Mockapi)(nil).GetAuthorizationToken), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthorizationToken", reflect.TypeOf((*Mockapi)(nil).GetAuthorizationToken), varargs...) } diff --git a/internal/pkg/aws/partitions/partition.go b/internal/pkg/aws/partitions/partition.go index aa72501b79f..e1117bd6940 100644 --- a/internal/pkg/aws/partitions/partition.go +++ b/internal/pkg/aws/partitions/partition.go @@ -5,20 +5,41 @@ package partitions import ( "fmt" + "regexp" +) - "github.com/aws/aws-sdk-go/aws/endpoints" +var ( + awsRegionRegex = regexp.MustCompile(`^(us|eu|ap|sa|ca|me|af|il)-\w+-\d+$`) + awsChinaRegionRegex = regexp.MustCompile(`^cn-\w+-\d+$`) + awsGovRegionRegex = regexp.MustCompile(`^us-gov-\w+-\d+$`) ) // Region is an AWS region ID. type Region string +// Partition describes the AWS partition that a region belongs to. +type Partition struct { + id string +} + +// ID returns the partition identifier. +func (p Partition) ID() string { + return p.id +} + // Partition returns the first partition which includes the region passed in, from a list of the partitions the SDK is bundled with. -func (r Region) Partition() (endpoints.Partition, error) { - partition, ok := endpoints.PartitionForRegion(endpoints.DefaultPartitions(), string(r)) - if !ok { - return endpoints.Partition{}, fmt.Errorf("find the partition for region %s", string(r)) +func (r Region) Partition() (Partition, error) { + region := string(r) + switch { + case awsRegionRegex.MatchString(region): + return Partition{id: "aws"}, nil + case awsChinaRegionRegex.MatchString(region): + return Partition{id: "aws-cn"}, nil + case awsGovRegionRegex.MatchString(region): + return Partition{id: "aws-us-gov"}, nil + default: + return Partition{}, fmt.Errorf("find the partition for region %s", region) } - return partition, nil } // IsAvailableInRegion returns true if the service ID is available in the given region. @@ -27,10 +48,118 @@ func IsAvailableInRegion(sID string, region string) (bool, error) { if err != nil { return false, err } - regions, partitionOrServiceExists := endpoints.RegionsForService(endpoints.DefaultPartitions(), partition.ID(), sID) - if !partitionOrServiceExists { + regions, ok := serviceRegions[partition.ID()][sID] + if !ok { return false, nil } _, existInRegion := regions[region] return existInRegion, nil } + +var serviceRegions = map[string]map[string]map[string]struct{}{ + "aws": { + "apprunner": regions( + "ap-northeast-1", + "ap-south-1", + "ap-southeast-1", + "ap-southeast-2", + "eu-central-1", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "us-east-1", + "us-east-2", + "us-west-2", + ), + "ecs": regions( + "af-south-1", + "ap-east-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-south-2", + "ap-southeast-1", + "ap-southeast-2", + "ap-southeast-3", + "ap-southeast-4", + "ca-central-1", + "ca-west-1", + "eu-central-1", + "eu-central-2", + "eu-north-1", + "eu-south-1", + "eu-south-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "il-central-1", + "me-central-1", + "me-south-1", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ), + "s3": regions( + "af-south-1", + "ap-east-1", + "ap-northeast-1", + "ap-northeast-2", + "ap-northeast-3", + "ap-south-1", + "ap-south-2", + "ap-southeast-1", + "ap-southeast-2", + "ap-southeast-3", + "ap-southeast-4", + "ca-central-1", + "ca-west-1", + "eu-central-1", + "eu-central-2", + "eu-north-1", + "eu-south-1", + "eu-south-2", + "eu-west-1", + "eu-west-2", + "eu-west-3", + "il-central-1", + "me-central-1", + "me-south-1", + "sa-east-1", + "us-east-1", + "us-east-2", + "us-west-1", + "us-west-2", + ), + }, + "aws-cn": { + "ecs": regions( + "cn-north-1", + "cn-northwest-1", + ), + "s3": regions( + "cn-north-1", + "cn-northwest-1", + ), + }, + "aws-us-gov": { + "ecs": regions( + "us-gov-east-1", + "us-gov-west-1", + ), + "s3": regions( + "us-gov-east-1", + "us-gov-west-1", + ), + }, +} + +func regions(ids ...string) map[string]struct{} { + out := make(map[string]struct{}, len(ids)) + for _, id := range ids { + out[id] = struct{}{} + } + return out +} diff --git a/internal/pkg/cli/app_show.go b/internal/pkg/cli/app_show.go index 1db93d23fcc..7054ce12e22 100644 --- a/internal/pkg/cli/app_show.go +++ b/internal/pkg/cli/app_show.go @@ -70,7 +70,7 @@ func newShowAppOpts(vars showAppVars) (*showAppOpts, error) { w: log.OutputWriter, sel: selector.NewAppEnvSelector(prompt.New(), store), deployStore: deployStore, - codepipeline: codepipeline.New(defaultSession, v2ConfigFromSessionRegion(defaultSession)), + codepipeline: codepipeline.New(v2ConfigFromSessionRegion(defaultSession), v2ConfigFromSessionRegion(defaultSession)), pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), newVersionGetter: func(s string) (versionGetter, error) { d, err := describe.NewAppDescriber(s) diff --git a/internal/pkg/cli/deploy/workload.go b/internal/pkg/cli/deploy/workload.go index 02e908ebb8a..d341cce55a7 100644 --- a/internal/pkg/cli/deploy/workload.go +++ b/internal/pkg/cli/deploy/workload.go @@ -287,7 +287,7 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { repoName := RepoName(in.App.Name, in.Name) repository := repository.NewWithURI( - ecr.New(defaultSessEnvRegion), repoName, resources.RepositoryURLs[in.Name]) + ecr.New(v2ConfigFromSessionRegion(defaultSessEnvRegion)), repoName, resources.RepositoryURLs[in.Name]) store := config.NewSSMStore(identity.New(defaultConfig), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ App: in.App.Name, diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index 29ddabe84f9..818a63703f3 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -129,7 +129,8 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), sess) o.deployer = cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) o.envDeleterFromApp = cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) - o.pipelineGetter = codepipeline.New(defaultSess, v2ConfigFromSessionRegion(defaultSess)) + defaultV2Config := v2ConfigFromSessionRegion(defaultSess) + o.pipelineGetter = codepipeline.New(defaultV2Config, defaultV2Config) o.deployedPipelineLister = deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSess))) return nil }, diff --git a/internal/pkg/cli/job_delete.go b/internal/pkg/cli/job_delete.go index 6c4a5d7bafc..048a078a26c 100644 --- a/internal/pkg/cli/job_delete.go +++ b/internal/pkg/cli/job_delete.go @@ -93,7 +93,7 @@ func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { return cloudformation.New(session, cloudformation.WithProgressTracker(os.Stderr)) }, newImageRemover: func(session *session.Session) imageRemover { - return ecr.New(session) + return ecr.New(v2ConfigFromSessionRegion(session)) }, newTaskStopper: func(session *session.Session) taskStopper { return ecs.New(session, v2ConfigFromSessionRegion(session)) diff --git a/internal/pkg/cli/pipeline_delete.go b/internal/pkg/cli/pipeline_delete.go index e92146f6754..8b5b1ef0668 100644 --- a/internal/pkg/cli/pipeline_delete.go +++ b/internal/pkg/cli/pipeline_delete.go @@ -89,7 +89,7 @@ func newDeletePipelineOpts(vars deletePipelineVars) (*deletePipelineOpts, error) } prompter := prompt.New() v2Config := v2ConfigFromSessionRegion(defaultSess) - codepipeline := codepipeline.New(defaultSess, v2Config) + codepipeline := codepipeline.New(v2Config, v2Config) pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) opts := &deletePipelineOpts{ diff --git a/internal/pkg/cli/pipeline_show.go b/internal/pkg/cli/pipeline_show.go index 92c9fff4f49..c09b4be7d2f 100644 --- a/internal/pkg/cli/pipeline_show.go +++ b/internal/pkg/cli/pipeline_show.go @@ -69,7 +69,7 @@ func newShowPipelineOpts(vars showPipelineVars) (*showPipelineOpts, error) { return nil, err } v2Config := v2ConfigFromSessionRegion(defaultSession) - codepipeline := codepipeline.New(defaultSession, v2Config) + codepipeline := codepipeline.New(v2Config, v2Config) pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) prompter := prompt.New() opts := &showPipelineOpts{ diff --git a/internal/pkg/cli/pipeline_status.go b/internal/pkg/cli/pipeline_status.go index eb52e1f0cb2..304007eafc0 100644 --- a/internal/pkg/cli/pipeline_status.go +++ b/internal/pkg/cli/pipeline_status.go @@ -68,7 +68,7 @@ func newPipelineStatusOpts(vars pipelineStatusVars) (*pipelineStatusOpts, error) return nil, err } v2Config := v2ConfigFromSessionRegion(session) - codepipeline := codepipeline.New(session, v2Config) + codepipeline := codepipeline.New(v2Config, v2Config) pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) prompter := prompt.New() return &pipelineStatusOpts{ diff --git a/internal/pkg/cli/run_local.go b/internal/pkg/cli/run_local.go index 2d50411afb7..02766e57df2 100644 --- a/internal/pkg/cli/run_local.go +++ b/internal/pkg/cli/run_local.go @@ -217,7 +217,7 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { return fmt.Errorf("get application %s resources from region %s: %w", o.appName, o.envName, err) } repoName := clideploy.RepoName(o.appName, o.wkldName) - o.repository = repository.NewWithURI(ecr.New(defaultSessEnvRegion), repoName, resources.RepositoryURLs[o.wkldName]) + o.repository = repository.NewWithURI(ecr.New(v2ConfigFromSessionRegion(defaultSessEnvRegion)), repoName, resources.RepositoryURLs[o.wkldName]) idPrefix := fmt.Sprintf("%s-%s-%s-", o.appName, o.envName, o.wkldName) colorGen := termcolor.ColorGenerator() diff --git a/internal/pkg/cli/svc_delete.go b/internal/pkg/cli/svc_delete.go index abb51b551ea..7981c37c0da 100644 --- a/internal/pkg/cli/svc_delete.go +++ b/internal/pkg/cli/svc_delete.go @@ -96,7 +96,7 @@ func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { return cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) }, getECR: func(sess *awssession.Session) imageRemover { - return ecr.New(sess) + return ecr.New(v2ConfigFromSessionRegion(sess)) }, } opts.newSvcCleaner = func(sess *awssession.Session, env *config.Environment, manifestType string) cleaner { diff --git a/internal/pkg/cli/task_delete.go b/internal/pkg/cli/task_delete.go index 3ee49ae39f8..8158373505f 100644 --- a/internal/pkg/cli/task_delete.go +++ b/internal/pkg/cli/task_delete.go @@ -108,7 +108,7 @@ func newDeleteTaskOpts(vars deleteTaskVars) (*deleteTaskOpts, error) { return cloudformation.New(session, cloudformation.WithProgressTracker(os.Stderr)) }, newImageRemover: func(session *session.Session) imageRemover { - return ecr.New(session) + return ecr.New(v2ConfigFromSessionRegion(session)) }, newBucketEmptier: func(session *session.Session) bucketEmptier { return s3.New(session) diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index 789274c0a39..b34686615bf 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -225,7 +225,7 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { opts.configureRepository = func() error { repoName := fmt.Sprintf(deploy.FmtTaskECRRepoName, opts.groupName) - opts.repository = repository.New(ecr.New(opts.sess), repoName) + opts.repository = repository.New(ecr.New(v2ConfigFromSessionRegion(opts.sess)), repoName) return nil } diff --git a/internal/pkg/deploy/cloudformation/cloudformation.go b/internal/pkg/deploy/cloudformation/cloudformation.go index eeaf8657f67..969e926f8ba 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation.go +++ b/internal/pkg/deploy/cloudformation/cloudformation.go @@ -213,7 +213,7 @@ func New(sess *session.Session, opts ...OptFn) CloudFormation { client := CloudFormation{ cfnClient: cloudformation.New(sess), codeStarClient: codestar.New(v2Config), - cpClient: codepipeline.New(sess, v2Config), + cpClient: codepipeline.New(v2Config, v2Config), ecsClient: ecs.New(sess), cwClient: cloudwatch.New(sess, v2Config), regionalClient: func(region string) cfnClient { @@ -222,9 +222,8 @@ func New(sess *session.Session, opts ...OptFn) CloudFormation { })) }, regionalECRClient: func(region string) imageRemover { - return ecr.New(sess.Copy(&aws.Config{ - Region: aws.String(region), - })) + regionalV2Config, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), region) + return ecr.New(regionalV2Config) }, appStackSet: stackset.New(sess), s3Client: s3.New(sess), diff --git a/internal/pkg/describe/pipeline_show.go b/internal/pkg/describe/pipeline_show.go index 933a3d34d2c..325cf4f1da7 100644 --- a/internal/pkg/describe/pipeline_show.go +++ b/internal/pkg/describe/pipeline_show.go @@ -49,7 +49,8 @@ func NewPipelineDescriber(pipeline deploy.Pipeline, showResources bool) (*Pipeli return nil, err } - pipelineSvc := codepipeline.New(sess, v2ConfigFromSessionRegion(sess)) + v2Config := v2ConfigFromSessionRegion(sess) + pipelineSvc := codepipeline.New(v2Config, v2Config) return &PipelineDescriber{ pipeline: pipeline, diff --git a/internal/pkg/describe/pipeline_status.go b/internal/pkg/describe/pipeline_status.go index f6024f832b9..4eb4972638f 100644 --- a/internal/pkg/describe/pipeline_status.go +++ b/internal/pkg/describe/pipeline_status.go @@ -39,7 +39,8 @@ func NewPipelineStatusDescriber(pipeline deploy.Pipeline) (*PipelineStatusDescri return nil, err } - pipelineSvc := codepipeline.New(sess, v2ConfigFromSessionRegion(sess)) + v2Config := v2ConfigFromSessionRegion(sess) + pipelineSvc := codepipeline.New(v2Config, v2Config) return &PipelineStatusDescriber{ pipeline: pipeline, pipelineSvc: pipelineSvc, From 003b17b70e8df982bff358cc282a3023a0be0def Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 13:17:31 +0200 Subject: [PATCH 07/17] migrate another set --- internal/pkg/aws/elbv2/elbv2.go | 94 ++++---- internal/pkg/aws/elbv2/elbv2_test.go | 213 +++++++++--------- internal/pkg/aws/elbv2/mocks/mock_elbv2.go | 75 +++--- internal/pkg/cli/deploy/backend.go | 2 +- internal/pkg/cli/deploy/env.go | 2 +- internal/pkg/cli/deploy/env_test.go | 10 +- internal/pkg/cli/deploy/lbws.go | 2 +- internal/pkg/describe/backend_service.go | 2 +- internal/pkg/describe/lb_web_service.go | 2 +- internal/pkg/describe/status_describe.go | 2 +- internal/pkg/describe/status_describe_test.go | 50 ++-- 11 files changed, 226 insertions(+), 228 deletions(-) diff --git a/internal/pkg/aws/elbv2/elbv2.go b/internal/pkg/aws/elbv2/elbv2.go index fa862937319..16ef1b78d5d 100644 --- a/internal/pkg/aws/elbv2/elbv2.go +++ b/internal/pkg/aws/elbv2/elbv2.go @@ -8,27 +8,25 @@ import ( "context" "errors" "fmt" - "github.com/aws/aws-sdk-go/aws/arn" "sort" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/elbv2" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "github.com/dustin/go-humanize/english" ) const ( // TargetHealthStateHealthy wraps the ELBV2 health status HEALTHY. - TargetHealthStateHealthy = elbv2.TargetHealthStateEnumHealthy + TargetHealthStateHealthy = string(types.TargetHealthStateEnumHealthy) ) type api interface { - DescribeTargetHealth(*elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error) - DescribeRules(*elbv2.DescribeRulesInput) (*elbv2.DescribeRulesOutput, error) - DescribeRulesWithContext(context.Context, *elbv2.DescribeRulesInput, ...request.Option) (*elbv2.DescribeRulesOutput, error) - DescribeLoadBalancers(input *elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) - DescribeListeners(input *elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error) + DescribeTargetHealth(context.Context, *elbv2.DescribeTargetHealthInput, ...func(*elbv2.Options)) (*elbv2.DescribeTargetHealthOutput, error) + DescribeRules(context.Context, *elbv2.DescribeRulesInput, ...func(*elbv2.Options)) (*elbv2.DescribeRulesOutput, error) + DescribeLoadBalancers(context.Context, *elbv2.DescribeLoadBalancersInput, ...func(*elbv2.Options)) (*elbv2.DescribeLoadBalancersOutput, error) + DescribeListeners(context.Context, *elbv2.DescribeListenersInput, ...func(*elbv2.Options)) (*elbv2.DescribeListenersOutput, error) } // ELBV2 wraps an AWS ELBV2 client. @@ -36,17 +34,17 @@ type ELBV2 struct { client api } -// New returns a ELBV2 configured against the input session. -func New(sess *session.Session) *ELBV2 { +// New returns a ELBV2 configured against the input SDK v2 config. +func New(cfg awsv2.Config) *ELBV2 { return &ELBV2{ - client: elbv2.New(sess), + client: elbv2.NewFromConfig(cfg), } } // ListenerRulesHostHeaders returns all the host headers for all listener rules. func (e *ELBV2) ListenerRulesHostHeaders(ruleARNs []string) ([]string, error) { - resp, err := e.client.DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice(ruleARNs), + resp, err := e.client.DescribeRules(context.Background(), &elbv2.DescribeRulesInput{ + RuleArns: ruleARNs, }) if err != nil { return nil, fmt.Errorf("get listener rule for %s: %w", english.WordSeries(ruleARNs, "and"), err) @@ -58,18 +56,18 @@ func (e *ELBV2) ListenerRulesHostHeaders(ruleARNs []string) ([]string, error) { hostHeaderSet := make(map[string]struct{}) for _, rule := range resp.Rules { for _, condition := range rule.Conditions { - if aws.StringValue(condition.Field) == "host-header" { + if awsv2.ToString(condition.Field) == "host-header" { // Values is a legacy field that allowed specifying only a single host name. // The alternative is to use HostHeaderConfig for multiple values. // Only one of these fields should be set, but we collect from both to be safe. for _, value := range condition.Values { - hostHeaderSet[aws.StringValue(value)] = exists + hostHeaderSet[value] = exists } if condition.HostHeaderConfig == nil { break } for _, value := range condition.HostHeaderConfig.Values { - hostHeaderSet[aws.StringValue(value)] = exists + hostHeaderSet[value] = exists } break } @@ -84,12 +82,12 @@ func (e *ELBV2) ListenerRulesHostHeaders(ruleARNs []string) ([]string, error) { } // Rule wraps an elbv2.Rule to add some nice functionality to it. -type Rule elbv2.Rule +type Rule types.Rule // DescribeRule returns the Rule with ruleARN. func (e *ELBV2) DescribeRule(ctx context.Context, ruleARN string) (Rule, error) { - resp, err := e.client.DescribeRulesWithContext(ctx, &elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{ruleARN}), + resp, err := e.client.DescribeRules(ctx, &elbv2.DescribeRulesInput{ + RuleArns: []string{ruleARN}, }) if err != nil { return Rule{}, err @@ -97,13 +95,13 @@ func (e *ELBV2) DescribeRule(ctx context.Context, ruleARN string) (Rule, error) return Rule{}, errors.New("not found") } - return Rule(*resp.Rules[0]), nil + return Rule(resp.Rules[0]), nil } // HasRedirectAction returns true if the rule has a redirect action. func (r *Rule) HasRedirectAction() bool { for _, action := range r.Actions { - if aws.StringValue(action.Type) == elbv2.ActionTypeEnumRedirect { + if action.Type == types.ActionTypeEnumRedirect { return true } } @@ -111,21 +109,21 @@ func (r *Rule) HasRedirectAction() bool { } // TargetHealth wraps up elbv2.TargetHealthDescription. -type TargetHealth elbv2.TargetHealthDescription +type TargetHealth types.TargetHealthDescription // TargetsHealth returns the health status of the targets in a target group. func (e *ELBV2) TargetsHealth(targetGroupARN string) ([]*TargetHealth, error) { in := &elbv2.DescribeTargetHealthInput{ - TargetGroupArn: aws.String(targetGroupARN), + TargetGroupArn: awsv2.String(targetGroupARN), } - out, err := e.client.DescribeTargetHealth(in) + out, err := e.client.DescribeTargetHealth(context.Background(), in) if err != nil { return nil, fmt.Errorf("describe target health for target group %s: %w", targetGroupARN, err) } ret := make([]*TargetHealth, len(out.TargetHealthDescriptions)) - for idx, description := range out.TargetHealthDescriptions { - ret[idx] = (*TargetHealth)(description) + for idx := range out.TargetHealthDescriptions { + ret[idx] = (*TargetHealth)(&out.TargetHealthDescriptions[idx]) } return ret, nil } @@ -147,14 +145,14 @@ type HealthStatus struct { func (t *TargetHealth) HealthStatus() *HealthStatus { return &HealthStatus{ TargetID: t.targetID(), - HealthDescription: aws.StringValue(t.TargetHealth.Description), - HealthState: aws.StringValue(t.TargetHealth.State), - HealthReason: aws.StringValue(t.TargetHealth.Reason), + HealthDescription: awsv2.ToString(t.TargetHealth.Description), + HealthState: string(t.TargetHealth.State), + HealthReason: string(t.TargetHealth.Reason), } } func (t *TargetHealth) targetID() string { - return aws.StringValue(t.Target.Id) + return awsv2.ToString(t.Target.Id) } // LoadBalancer contains information about a given load balancer. @@ -173,14 +171,14 @@ func (e *ELBV2) LoadBalancer(nameOrARN string) (*LoadBalancer, error) { var input *elbv2.DescribeLoadBalancersInput if arn.IsARN(nameOrARN) { input = &elbv2.DescribeLoadBalancersInput{ - LoadBalancerArns: []*string{aws.String(nameOrARN)}, + LoadBalancerArns: []string{nameOrARN}, } } else { input = &elbv2.DescribeLoadBalancersInput{ - Names: []*string{aws.String(nameOrARN)}, + Names: []string{nameOrARN}, } } - output, err := e.client.DescribeLoadBalancers(input) + output, err := e.client.DescribeLoadBalancers(context.Background(), input) if err != nil { return nil, fmt.Errorf("describe load balancer %q: %w", nameOrARN, err) } @@ -188,18 +186,18 @@ func (e *ELBV2) LoadBalancer(nameOrARN string) (*LoadBalancer, error) { return nil, fmt.Errorf("no load balancer %q found", nameOrARN) } lb := output.LoadBalancers[0] - listeners, err := e.listeners(aws.StringValue(lb.LoadBalancerArn)) + listeners, err := e.listeners(awsv2.ToString(lb.LoadBalancerArn)) if err != nil { return nil, err } return &LoadBalancer{ - ARN: aws.StringValue(lb.LoadBalancerArn), - Name: aws.StringValue(lb.LoadBalancerName), - DNSName: aws.StringValue(lb.DNSName), - Scheme: aws.StringValue(lb.Scheme), - HostedZoneID: aws.StringValue(lb.CanonicalHostedZoneId), + ARN: awsv2.ToString(lb.LoadBalancerArn), + Name: awsv2.ToString(lb.LoadBalancerName), + DNSName: awsv2.ToString(lb.DNSName), + Scheme: string(lb.Scheme), + HostedZoneID: awsv2.ToString(lb.CanonicalHostedZoneId), Listeners: listeners, - SecurityGroups: aws.StringValueSlice(lb.SecurityGroups), + SecurityGroups: append([]string(nil), lb.SecurityGroups...), }, nil } @@ -213,9 +211,9 @@ type Listener struct { // listeners returns select information about all listeners on a given load balancer. func (e *ELBV2) listeners(lbARN string) ([]Listener, error) { var listeners []Listener - in := &elbv2.DescribeListenersInput{LoadBalancerArn: aws.String(lbARN)} + in := &elbv2.DescribeListenersInput{LoadBalancerArn: awsv2.String(lbARN)} for { - output, err := e.client.DescribeListeners(in) + output, err := e.client.DescribeListeners(context.Background(), in) if err != nil { return nil, fmt.Errorf("describe listeners on load balancer %q: %w", lbARN, err) } @@ -224,9 +222,9 @@ func (e *ELBV2) listeners(lbARN string) ([]Listener, error) { } for _, listener := range output.Listeners { listeners = append(listeners, Listener{ - ARN: aws.StringValue(listener.ListenerArn), - Port: aws.Int64Value(listener.Port), - Protocol: aws.StringValue(listener.Protocol), + ARN: awsv2.ToString(listener.ListenerArn), + Port: int64(awsv2.ToInt32(listener.Port)), + Protocol: string(listener.Protocol), }) } if output.NextMarker == nil { diff --git a/internal/pkg/aws/elbv2/elbv2_test.go b/internal/pkg/aws/elbv2/elbv2_test.go index a2ee0ec0e69..f9f2f28ce4a 100644 --- a/internal/pkg/aws/elbv2/elbv2_test.go +++ b/internal/pkg/aws/elbv2/elbv2_test.go @@ -12,9 +12,10 @@ import ( "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/service/elbv2" + elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "github.com/aproint/copilot-cli/internal/pkg/aws/elbv2/mocks" ) @@ -32,39 +33,39 @@ func TestELBV2_TargetsHealth(t *testing.T) { targetGroupARN: "group-1", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{ + m.EXPECT().DescribeTargetHealth(gomock.Any(), &elbv2.DescribeTargetHealthInput{ TargetGroupArn: aws.String("group-1"), }).Return(&elbv2.DescribeTargetHealthOutput{ - TargetHealthDescriptions: []*elbv2.TargetHealthDescription{ + TargetHealthDescriptions: []types.TargetHealthDescription{ { HealthCheckPort: aws.String("80"), - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("10.00.233"), }, - TargetHealth: &elbv2.TargetHealth{ + TargetHealth: &types.TargetHealth{ Description: aws.String("timed out"), - Reason: aws.String(elbv2.TargetHealthReasonEnumTargetTimeout), - State: aws.String(elbv2.TargetHealthStateEnumUnhealthy), + Reason: types.TargetHealthReasonEnumTimeout, + State: types.TargetHealthStateEnumUnhealthy, }, }, { HealthCheckPort: aws.String("80"), - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("10.00.322"), }, - TargetHealth: &elbv2.TargetHealth{ - State: aws.String(elbv2.TargetHealthStateEnumHealthy), + TargetHealth: &types.TargetHealth{ + State: types.TargetHealthStateEnumHealthy, }, }, { HealthCheckPort: aws.String("80"), - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("10.00.332"), }, - TargetHealth: &elbv2.TargetHealth{ + TargetHealth: &types.TargetHealth{ Description: aws.String("mismatch"), - Reason: aws.String(elbv2.TargetHealthReasonEnumTargetResponseCodeMismatch), - State: aws.String(elbv2.TargetHealthStateEnumUnhealthy), + Reason: types.TargetHealthReasonEnumResponseCodeMismatch, + State: types.TargetHealthStateEnumUnhealthy, }, }, }, @@ -74,33 +75,33 @@ func TestELBV2_TargetsHealth(t *testing.T) { wantedOut: []*TargetHealth{ { HealthCheckPort: aws.String("80"), - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("10.00.233"), }, - TargetHealth: &elbv2.TargetHealth{ + TargetHealth: &types.TargetHealth{ Description: aws.String("timed out"), - Reason: aws.String(elbv2.TargetHealthReasonEnumTargetTimeout), - State: aws.String(elbv2.TargetHealthStateEnumUnhealthy), + Reason: types.TargetHealthReasonEnumTimeout, + State: types.TargetHealthStateEnumUnhealthy, }, }, { HealthCheckPort: aws.String("80"), - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("10.00.322"), }, - TargetHealth: &elbv2.TargetHealth{ - State: aws.String(elbv2.TargetHealthStateEnumHealthy), + TargetHealth: &types.TargetHealth{ + State: types.TargetHealthStateEnumHealthy, }, }, { HealthCheckPort: aws.String("80"), - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("10.00.332"), }, - TargetHealth: &elbv2.TargetHealth{ + TargetHealth: &types.TargetHealth{ Description: aws.String("mismatch"), - Reason: aws.String(elbv2.TargetHealthReasonEnumTargetResponseCodeMismatch), - State: aws.String(elbv2.TargetHealthStateEnumUnhealthy), + Reason: types.TargetHealthReasonEnumResponseCodeMismatch, + State: types.TargetHealthStateEnumUnhealthy, }, }, }, @@ -109,7 +110,7 @@ func TestELBV2_TargetsHealth(t *testing.T) { targetGroupARN: "group-1", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeTargetHealth(&elbv2.DescribeTargetHealthInput{ + m.EXPECT().DescribeTargetHealth(gomock.Any(), &elbv2.DescribeTargetHealthInput{ TargetGroupArn: aws.String("group-1"), }).Return(nil, errors.New("some error")) }, @@ -155,8 +156,8 @@ func TestELBV2_ListenerRuleHostHeaders(t *testing.T) { "fail to describe rules": { inARNs: []string{mockARN1}, setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN1}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN1}, }).Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("get listener rule for mockListenerRuleARN1: some error"), @@ -164,8 +165,8 @@ func TestELBV2_ListenerRuleHostHeaders(t *testing.T) { "cannot find listener rule": { inARNs: []string{mockARN1}, setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN1}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN1}, }).Return(&elbv2.DescribeRulesOutput{}, nil) }, wantedError: fmt.Errorf("cannot find listener rule mockListenerRuleARN1"), @@ -173,21 +174,21 @@ func TestELBV2_ListenerRuleHostHeaders(t *testing.T) { "success": { inARNs: []string{mockARN1}, setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN1}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN1}, }).Return(&elbv2.DescribeRulesOutput{ - Rules: []*elbv2.Rule{ + Rules: []types.Rule{ { - Conditions: []*elbv2.RuleCondition{ + Conditions: []types.RuleCondition{ { Field: aws.String("path-pattern"), - Values: []*string{aws.String("/*")}, + Values: []string{"/*"}, }, { Field: aws.String("host-header"), - Values: aws.StringSlice([]string{"copilot.com", "archer.com"}), - HostHeaderConfig: &elbv2.HostHeaderConditionConfig{ - Values: aws.StringSlice([]string{"copilot.com", "archer.com"}), + Values: []string{"copilot.com", "archer.com"}, + HostHeaderConfig: &types.HostHeaderConditionConfig{ + Values: []string{"copilot.com", "archer.com"}, }, }, }, @@ -200,36 +201,36 @@ func TestELBV2_ListenerRuleHostHeaders(t *testing.T) { "success in case of multiple rules": { inARNs: []string{mockARN1, mockARN2}, setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRules(&elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN1, mockARN2}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN1, mockARN2}, }).Return(&elbv2.DescribeRulesOutput{ - Rules: []*elbv2.Rule{ + Rules: []types.Rule{ { - Conditions: []*elbv2.RuleCondition{ + Conditions: []types.RuleCondition{ { Field: aws.String("path-pattern"), - Values: []*string{aws.String("/*")}, + Values: []string{"/*"}, }, { Field: aws.String("host-header"), - Values: aws.StringSlice([]string{"copilot.com", "archer.com"}), - HostHeaderConfig: &elbv2.HostHeaderConditionConfig{ - Values: aws.StringSlice([]string{"copilot.com", "archer.com"}), + Values: []string{"copilot.com", "archer.com"}, + HostHeaderConfig: &types.HostHeaderConditionConfig{ + Values: []string{"copilot.com", "archer.com"}, }, }, }, }, { - Conditions: []*elbv2.RuleCondition{ + Conditions: []types.RuleCondition{ { Field: aws.String("path-pattern"), - Values: []*string{aws.String("/*")}, + Values: []string{"/*"}, }, { Field: aws.String("host-header"), - Values: aws.StringSlice([]string{"v1.copilot.com", "v1.archer.com"}), - HostHeaderConfig: &elbv2.HostHeaderConditionConfig{ - Values: aws.StringSlice([]string{"v1.copilot.com", "v1.archer.com"}), + Values: []string{"v1.copilot.com", "v1.archer.com"}, + HostHeaderConfig: &types.HostHeaderConditionConfig{ + Values: []string{"v1.copilot.com", "v1.archer.com"}, }, }, }, @@ -276,33 +277,33 @@ func TestELBV2_DescribeRule(t *testing.T) { }{ "fail to describe rules": { setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRulesWithContext(gomock.Any(), &elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN}, }).Return(nil, errors.New("some error")) }, expectedErr: "some error", }, "cannot find listener rule": { setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRulesWithContext(gomock.Any(), &elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN}, }).Return(&elbv2.DescribeRulesOutput{}, nil) }, expectedErr: `not found`, }, "success": { setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRulesWithContext(gomock.Any(), &elbv2.DescribeRulesInput{ - RuleArns: aws.StringSlice([]string{mockARN}), + m.EXPECT().DescribeRules(gomock.Any(), &elbv2.DescribeRulesInput{ + RuleArns: []string{mockARN}, }).Return(&elbv2.DescribeRulesOutput{ - Rules: []*elbv2.Rule{ + Rules: []types.Rule{ { RuleArn: aws.String(mockARN), }, }, }, nil) }, - expected: Rule(elbv2.Rule{ + expected: Rule(types.Rule{ RuleArn: aws.String(mockARN), }), }, @@ -336,19 +337,19 @@ func TestELBV2Rule_HasRedirectAction(t *testing.T) { expected bool }{ "rule doesn't have redirect": { - rule: Rule(elbv2.Rule{ - Actions: []*elbv2.Action{ + rule: Rule(types.Rule{ + Actions: []types.Action{ { - Type: aws.String(elbv2.ActionTypeEnumForward), + Type: types.ActionTypeEnumForward, }, }, }), }, "rule has redirect": { - rule: Rule(elbv2.Rule{ - Actions: []*elbv2.Action{ + rule: Rule(types.Rule{ + Actions: []types.Action{ { - Type: aws.String(elbv2.ActionTypeEnumRedirect), + Type: types.ActionTypeEnumRedirect, }, }, }), @@ -371,34 +372,34 @@ func TestTargetHealth_HealthStatus(t *testing.T) { }{ "unhealthy status with all params": { inTargetHealth: &TargetHealth{ - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("42.42.42.42"), }, - TargetHealth: &elbv2.TargetHealth{ - State: aws.String("unhealthy"), + TargetHealth: &types.TargetHealth{ + State: types.TargetHealthStateEnumUnhealthy, Description: aws.String("some description"), - Reason: aws.String("some reason"), + Reason: types.TargetHealthReasonEnum("some reason"), }, }, wanted: &HealthStatus{ TargetID: "42.42.42.42", - HealthState: "unhealthy", + HealthState: string(types.TargetHealthStateEnumUnhealthy), HealthDescription: "some description", HealthReason: "some reason", }, }, "healthy status with description and reason empty": { inTargetHealth: &TargetHealth{ - Target: &elbv2.TargetDescription{ + Target: &types.TargetDescription{ Id: aws.String("24.24.24.24"), }, - TargetHealth: &elbv2.TargetHealth{ - State: aws.String("healthy"), + TargetHealth: &types.TargetHealth{ + State: types.TargetHealthStateEnumHealthy, }, }, wanted: &HealthStatus{ TargetID: "24.24.24.24", - HealthState: "healthy", + HealthState: string(types.TargetHealthStateEnumHealthy), HealthDescription: "", HealthReason: "", }, @@ -414,14 +415,14 @@ func TestTargetHealth_HealthStatus(t *testing.T) { func TestELBV2_LoadBalancer(t *testing.T) { mockOutput := &elbv2.DescribeLoadBalancersOutput{ - LoadBalancers: []*elbv2.LoadBalancer{ + LoadBalancers: []types.LoadBalancer{ { LoadBalancerArn: aws.String("mockLBARN"), LoadBalancerName: aws.String("mockLBName"), DNSName: aws.String("mockDNSName"), - Scheme: aws.String("internet-facing"), + Scheme: types.LoadBalancerSchemeEnumInternetFacing, CanonicalHostedZoneId: aws.String("mockHostedZoneID"), - SecurityGroups: aws.StringSlice([]string{"sg1", "sg2"}), + SecurityGroups: []string{"sg1", "sg2"}, }, }, } @@ -435,17 +436,17 @@ func TestELBV2_LoadBalancer(t *testing.T) { "successfully return LB info from name": { mockID: "loadBalancerName", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ - Names: []*string{aws.String("loadBalancerName")}, + m.EXPECT().DescribeLoadBalancers(gomock.Any(), &elbv2.DescribeLoadBalancersInput{ + Names: []string{"loadBalancerName"}, }).Return(mockOutput, nil) - m.EXPECT().DescribeListeners(&elbv2.DescribeListenersInput{ + m.EXPECT().DescribeListeners(gomock.Any(), &elbv2.DescribeListenersInput{ LoadBalancerArn: aws.String("mockLBARN"), }).Return(&elbv2.DescribeListenersOutput{ - Listeners: []*elbv2.Listener{ + Listeners: []types.Listener{ { ListenerArn: aws.String("mockListenerARN"), - Port: aws.Int64(80), - Protocol: aws.String("http"), + Port: aws.Int32(80), + Protocol: types.ProtocolEnum("http"), }, }, NextMarker: nil, @@ -471,16 +472,16 @@ func TestELBV2_LoadBalancer(t *testing.T) { "successfully return LB info from ARN": { mockID: "arn:aws:elasticloadbalancing:us-west-2:123594734248:loadbalancer/app/ALBForImport/8db123b49az6de94", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ - LoadBalancerArns: []*string{aws.String("arn:aws:elasticloadbalancing:us-west-2:123594734248:loadbalancer/app/ALBForImport/8db123b49az6de94")}}).Return(mockOutput, nil) - m.EXPECT().DescribeListeners(&elbv2.DescribeListenersInput{ + m.EXPECT().DescribeLoadBalancers(gomock.Any(), &elbv2.DescribeLoadBalancersInput{ + LoadBalancerArns: []string{"arn:aws:elasticloadbalancing:us-west-2:123594734248:loadbalancer/app/ALBForImport/8db123b49az6de94"}}).Return(mockOutput, nil) + m.EXPECT().DescribeListeners(gomock.Any(), &elbv2.DescribeListenersInput{ LoadBalancerArn: aws.String("mockLBARN"), }).Return(&elbv2.DescribeListenersOutput{ - Listeners: []*elbv2.Listener{ + Listeners: []types.Listener{ { ListenerArn: aws.String("mockListenerARN"), - Port: aws.Int64(80), - Protocol: aws.String("http"), + Port: aws.Int32(80), + Protocol: types.ProtocolEnum("http"), }, }, NextMarker: nil, @@ -505,18 +506,18 @@ func TestELBV2_LoadBalancer(t *testing.T) { "error if describe LB call fails": { mockID: "loadBalancerName", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ - Names: []*string{aws.String("loadBalancerName")}}).Return(nil, errors.New("some error")) + m.EXPECT().DescribeLoadBalancers(gomock.Any(), &elbv2.DescribeLoadBalancersInput{ + Names: []string{"loadBalancerName"}}).Return(nil, errors.New("some error")) }, expectedErr: `describe load balancer "loadBalancerName": some error`, }, "error if no load balancers returned": { mockID: "mockLBName", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ - Names: []*string{aws.String("mockLBName")}, + m.EXPECT().DescribeLoadBalancers(gomock.Any(), &elbv2.DescribeLoadBalancersInput{ + Names: []string{"mockLBName"}, }).Return(&elbv2.DescribeLoadBalancersOutput{ - LoadBalancers: []*elbv2.LoadBalancer{}, + LoadBalancers: []types.LoadBalancer{}, }, nil) }, expectedErr: `no load balancer "mockLBName" found`, @@ -524,10 +525,10 @@ func TestELBV2_LoadBalancer(t *testing.T) { "error if describe listeners call fails": { mockID: "loadBalancerName", setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeLoadBalancers(&elbv2.DescribeLoadBalancersInput{ - Names: []*string{aws.String("loadBalancerName")}, + m.EXPECT().DescribeLoadBalancers(gomock.Any(), &elbv2.DescribeLoadBalancersInput{ + Names: []string{"loadBalancerName"}, }).Return(mockOutput, nil) - m.EXPECT().DescribeListeners(&elbv2.DescribeListenersInput{ + m.EXPECT().DescribeListeners(gomock.Any(), &elbv2.DescribeListenersInput{ LoadBalancerArn: aws.String("mockLBARN"), }).Return(nil, errors.New("some error")) }, @@ -559,16 +560,16 @@ func TestELBV2_LoadBalancer(t *testing.T) { func TestELBV2_listeners(t *testing.T) { mockLBARN := aws.String("mockLoadBalancerARN") mockOutput := &elbv2.DescribeListenersOutput{ - Listeners: []*elbv2.Listener{ + Listeners: []types.Listener{ { ListenerArn: aws.String("listenerARN1"), - Port: aws.Int64(80), - Protocol: aws.String("HTTP"), + Port: aws.Int32(80), + Protocol: types.ProtocolEnumHttp, }, { ListenerArn: aws.String("listenerARN2"), - Port: aws.Int64(443), - Protocol: aws.String("HTTPS"), + Port: aws.Int32(443), + Protocol: types.ProtocolEnumHttps, }, }, } @@ -580,7 +581,7 @@ func TestELBV2_listeners(t *testing.T) { }{ "successfully return listeners from LB ARN": { setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeListeners(&elbv2.DescribeListenersInput{ + m.EXPECT().DescribeListeners(gomock.Any(), &elbv2.DescribeListenersInput{ LoadBalancerArn: mockLBARN, }).Return(mockOutput, nil) }, @@ -599,7 +600,7 @@ func TestELBV2_listeners(t *testing.T) { }, "error if describe call fails": { setUpMock: func(m *mocks.Mockapi) { - m.EXPECT().DescribeListeners(&elbv2.DescribeListenersInput{ + m.EXPECT().DescribeListeners(gomock.Any(), &elbv2.DescribeListenersInput{ LoadBalancerArn: mockLBARN, }).Return(nil, errors.New("some error")) }, @@ -618,7 +619,7 @@ func TestELBV2_listeners(t *testing.T) { client: mockAPI, } - actual, err := elbv2Client.listeners(aws.StringValue(mockLBARN)) + actual, err := elbv2Client.listeners(aws.ToString(mockLBARN)) if tc.expectedErr != "" { require.EqualError(t, err, tc.expectedErr) } else { diff --git a/internal/pkg/aws/elbv2/mocks/mock_elbv2.go b/internal/pkg/aws/elbv2/mocks/mock_elbv2.go index 3c8aaf6c0df..7d8b8a8cee6 100644 --- a/internal/pkg/aws/elbv2/mocks/mock_elbv2.go +++ b/internal/pkg/aws/elbv2/mocks/mock_elbv2.go @@ -8,8 +8,7 @@ import ( context "context" reflect "reflect" - request "github.com/aws/aws-sdk-go/aws/request" - elbv2 "github.com/aws/aws-sdk-go/service/elbv2" + elasticloadbalancingv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" gomock "github.com/golang/mock/gomock" ) @@ -37,81 +36,81 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeListeners mocks base method. -func (m *Mockapi) DescribeListeners(input *elbv2.DescribeListenersInput) (*elbv2.DescribeListenersOutput, error) { +func (m *Mockapi) DescribeListeners(arg0 context.Context, arg1 *elasticloadbalancingv2.DescribeListenersInput, arg2 ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeListenersOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeListeners", input) - ret0, _ := ret[0].(*elbv2.DescribeListenersOutput) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeListeners", varargs...) + ret0, _ := ret[0].(*elasticloadbalancingv2.DescribeListenersOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeListeners indicates an expected call of DescribeListeners. -func (mr *MockapiMockRecorder) DescribeListeners(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeListeners(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeListeners", reflect.TypeOf((*Mockapi)(nil).DescribeListeners), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeListeners", reflect.TypeOf((*Mockapi)(nil).DescribeListeners), varargs...) } // DescribeLoadBalancers mocks base method. -func (m *Mockapi) DescribeLoadBalancers(input *elbv2.DescribeLoadBalancersInput) (*elbv2.DescribeLoadBalancersOutput, error) { +func (m *Mockapi) DescribeLoadBalancers(arg0 context.Context, arg1 *elasticloadbalancingv2.DescribeLoadBalancersInput, arg2 ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeLoadBalancersOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeLoadBalancers", input) - ret0, _ := ret[0].(*elbv2.DescribeLoadBalancersOutput) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeLoadBalancers", varargs...) + ret0, _ := ret[0].(*elasticloadbalancingv2.DescribeLoadBalancersOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeLoadBalancers indicates an expected call of DescribeLoadBalancers. -func (mr *MockapiMockRecorder) DescribeLoadBalancers(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeLoadBalancers(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeLoadBalancers", reflect.TypeOf((*Mockapi)(nil).DescribeLoadBalancers), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeLoadBalancers", reflect.TypeOf((*Mockapi)(nil).DescribeLoadBalancers), varargs...) } // DescribeRules mocks base method. -func (m *Mockapi) DescribeRules(arg0 *elbv2.DescribeRulesInput) (*elbv2.DescribeRulesOutput, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeRules", arg0) - ret0, _ := ret[0].(*elbv2.DescribeRulesOutput) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRules indicates an expected call of DescribeRules. -func (mr *MockapiMockRecorder) DescribeRules(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRules", reflect.TypeOf((*Mockapi)(nil).DescribeRules), arg0) -} - -// DescribeRulesWithContext mocks base method. -func (m *Mockapi) DescribeRulesWithContext(arg0 context.Context, arg1 *elbv2.DescribeRulesInput, arg2 ...request.Option) (*elbv2.DescribeRulesOutput, error) { +func (m *Mockapi) DescribeRules(arg0 context.Context, arg1 *elasticloadbalancingv2.DescribeRulesInput, arg2 ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeRulesOutput, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "DescribeRulesWithContext", varargs...) - ret0, _ := ret[0].(*elbv2.DescribeRulesOutput) + ret := m.ctrl.Call(m, "DescribeRules", varargs...) + ret0, _ := ret[0].(*elasticloadbalancingv2.DescribeRulesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } -// DescribeRulesWithContext indicates an expected call of DescribeRulesWithContext. -func (mr *MockapiMockRecorder) DescribeRulesWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// DescribeRules indicates an expected call of DescribeRules. +func (mr *MockapiMockRecorder) DescribeRules(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, "DescribeRulesWithContext", reflect.TypeOf((*Mockapi)(nil).DescribeRulesWithContext), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRules", reflect.TypeOf((*Mockapi)(nil).DescribeRules), varargs...) } // DescribeTargetHealth mocks base method. -func (m *Mockapi) DescribeTargetHealth(arg0 *elbv2.DescribeTargetHealthInput) (*elbv2.DescribeTargetHealthOutput, error) { +func (m *Mockapi) DescribeTargetHealth(arg0 context.Context, arg1 *elasticloadbalancingv2.DescribeTargetHealthInput, arg2 ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeTargetHealthOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeTargetHealth", arg0) - ret0, _ := ret[0].(*elbv2.DescribeTargetHealthOutput) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeTargetHealth", varargs...) + ret0, _ := ret[0].(*elasticloadbalancingv2.DescribeTargetHealthOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeTargetHealth indicates an expected call of DescribeTargetHealth. -func (mr *MockapiMockRecorder) DescribeTargetHealth(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeTargetHealth(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTargetHealth", reflect.TypeOf((*Mockapi)(nil).DescribeTargetHealth), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTargetHealth", reflect.TypeOf((*Mockapi)(nil).DescribeTargetHealth), varargs...) } diff --git a/internal/pkg/cli/deploy/backend.go b/internal/pkg/cli/deploy/backend.go index b588d304ea3..844bb8c793b 100644 --- a/internal/pkg/cli/deploy/backend.go +++ b/internal/pkg/cli/deploy/backend.go @@ -44,7 +44,7 @@ func NewBackendDeployer(in *WorkloadDeployerInput) (*backendSvcDeployer, error) } return &backendSvcDeployer{ svcDeployer: svcDeployer, - elbGetter: elbv2.New(svcDeployer.envSess), + elbGetter: elbv2.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), backendMft: bsMft, aliasCertValidator: acm.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), }, nil diff --git a/internal/pkg/cli/deploy/env.go b/internal/pkg/cli/deploy/env.go index 15b126b3796..3a1c66d13e1 100644 --- a/internal/pkg/cli/deploy/env.go +++ b/internal/pkg/cli/deploy/env.go @@ -166,7 +166,7 @@ func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { return deploycfn.WrapWithTemplateOverrider(stack, overrider), nil }, envDescriber: envDescriber, - lbDescriber: elbv2.New(envManagerSession), + lbDescriber: elbv2.New(v2ConfigFromSessionRegion(envManagerSession)), newServiceStackDescriber: func(svc string) stackDescriber { return stack.NewStackDescriber(cfnstack.NameForWorkload(in.App.Name, in.Env.Name, svc), envManagerSession) }, diff --git a/internal/pkg/cli/deploy/env_test.go b/internal/pkg/cli/deploy/env_test.go index 39f195a2280..fca61746553 100644 --- a/internal/pkg/cli/deploy/env_test.go +++ b/internal/pkg/cli/deploy/env_test.go @@ -25,9 +25,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template/artifactpath" "github.com/aproint/copilot-cli/internal/pkg/term/log" + awselb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "github.com/aws/aws-sdk-go/aws" awscfn "github.com/aws/aws-sdk-go/service/cloudformation" - awselb "github.com/aws/aws-sdk-go/service/elbv2" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -731,16 +731,16 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) { func TestEnvDeployer_Validate(t *testing.T) { listenerRuleNoRedirect := elbv2.Rule{ - Actions: []*awselb.Action{ + Actions: []awselb.Action{ { - Type: aws.String(awselb.ActionTypeEnumForward), + Type: awselb.ActionTypeEnumForward, }, }, } listenerRuleWithRedirect := elbv2.Rule{ - Actions: []*awselb.Action{ + Actions: []awselb.Action{ { - Type: aws.String(awselb.ActionTypeEnumRedirect), + Type: awselb.ActionTypeEnumRedirect, }, }, } diff --git a/internal/pkg/cli/deploy/lbws.go b/internal/pkg/cli/deploy/lbws.go index f4ce2c1f009..22e852673d7 100644 --- a/internal/pkg/cli/deploy/lbws.go +++ b/internal/pkg/cli/deploy/lbws.go @@ -80,7 +80,7 @@ func NewLBWSDeployer(in *WorkloadDeployerInput) (*lbWebSvcDeployer, error) { return &lbWebSvcDeployer{ svcDeployer: svcDeployer, appVersionGetter: versionGetter, - elbGetter: elbv2.New(svcDeployer.envSess), + elbGetter: elbv2.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), lbMft: lbMft, newAliasCertValidator: func(optionalRegion *string) aliasCertValidator { sess := svcDeployer.envSess.Copy(&aws.Config{ diff --git a/internal/pkg/describe/backend_service.go b/internal/pkg/describe/backend_service.go index 4b64910a1af..ee1e3258bdb 100644 --- a/internal/pkg/describe/backend_service.go +++ b/internal/pkg/describe/backend_service.go @@ -64,7 +64,7 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if err != nil { return nil, err } - return elbv2.New(sess), nil + return elbv2.New(v2ConfigFromSessionRegion(sess)), nil } describer.initECSServiceDescribers = func(env string) (ecsDescriber, error) { if describer, ok := describer.ecsServiceDescribers[env]; ok { diff --git a/internal/pkg/describe/lb_web_service.go b/internal/pkg/describe/lb_web_service.go index 39f0ef76745..104d50229a1 100644 --- a/internal/pkg/describe/lb_web_service.go +++ b/internal/pkg/describe/lb_web_service.go @@ -87,7 +87,7 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if err != nil { return nil, err } - return elbv2.New(sess), nil + return elbv2.New(v2ConfigFromSessionRegion(sess)), nil } describer.initECSServiceDescribers = func(env string) (ecsDescriber, error) { if describer, ok := describer.ecsServiceDescribers[env]; ok { diff --git a/internal/pkg/describe/status_describe.go b/internal/pkg/describe/status_describe.go index d73f9dea654..97c6c55c9f1 100644 --- a/internal/pkg/describe/status_describe.go +++ b/internal/pkg/describe/status_describe.go @@ -108,7 +108,7 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er cwSvcGetter: cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), ecsSvcGetter: awsecs.New(sess), aasSvcGetter: aas.New(v2ConfigFromSessionRegion(sess)), - targetHealthGetter: elbv2.New(sess), + targetHealthGetter: elbv2.New(v2ConfigFromSessionRegion(sess)), }, nil } diff --git a/internal/pkg/describe/status_describe_test.go b/internal/pkg/describe/status_describe_test.go index 5dbce81819c..4e16e17d722 100644 --- a/internal/pkg/describe/status_describe_test.go +++ b/internal/pkg/describe/status_describe_test.go @@ -16,9 +16,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/elbv2" "github.com/aproint/copilot-cli/internal/pkg/describe/mocks" "github.com/aproint/copilot-cli/internal/pkg/ecs" + elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "github.com/aws/aws-sdk-go/aws" ecsapi "github.com/aws/aws-sdk-go/service/ecs" - elbv2api "github.com/aws/aws-sdk-go/service/elbv2" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -353,38 +353,38 @@ func TestServiceStatus_Describe(t *testing.T) { m.alarmStatusGetter.EXPECT().AlarmStatuses(gomock.Any()).Return(nil, nil), m.targetHealthGetter.EXPECT().TargetsHealth("group-1").Return([]*elbv2.TargetHealth{ { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("1.2.3.4"), }, - TargetHealth: &elbv2api.TargetHealth{ - State: aws.String("unhealthy"), - Reason: aws.String("Target.ResponseCodeMismatch"), + TargetHealth: &elbv2types.TargetHealth{ + State: elbv2types.TargetHealthStateEnumUnhealthy, + Reason: elbv2types.TargetHealthReasonEnumResponseCodeMismatch, }, }, { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("4.3.2.1"), }, - TargetHealth: &elbv2api.TargetHealth{ - State: aws.String("healthy"), + TargetHealth: &elbv2types.TargetHealth{ + State: elbv2types.TargetHealthStateEnumHealthy, }, }, }, nil), m.targetHealthGetter.EXPECT().TargetsHealth("group-2").Return([]*elbv2.TargetHealth{ { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("1.2.3.4"), }, - TargetHealth: &elbv2api.TargetHealth{ - State: aws.String("healthy"), + TargetHealth: &elbv2types.TargetHealth{ + State: elbv2types.TargetHealthStateEnumHealthy, }, }, { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("4.3.2.1"), }, - TargetHealth: &elbv2api.TargetHealth{ - State: aws.String("healthy"), + TargetHealth: &elbv2types.TargetHealth{ + State: elbv2types.TargetHealthStateEnumHealthy, }, }, }, nil), @@ -852,16 +852,16 @@ func Test_targetHealthForTasks(t *testing.T) { "include target health in output even if it's not matchable to a task": { inTargetsHealth: []*elbv2.TargetHealth{ { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("42.42.42.42"), }, - TargetHealth: &elbv2api.TargetHealth{}, + TargetHealth: &elbv2types.TargetHealth{}, }, { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("24.24.24.24"), }, - TargetHealth: &elbv2api.TargetHealth{}, + TargetHealth: &elbv2types.TargetHealth{}, }, }, inTasks: []*awsecs.Task{ @@ -913,21 +913,21 @@ func Test_targetHealthForTasks(t *testing.T) { "target health should be matched to a task if applicable": { inTargetsHealth: []*elbv2.TargetHealth{ { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("42.42.42.42"), }, - TargetHealth: &elbv2api.TargetHealth{ + TargetHealth: &elbv2types.TargetHealth{ Description: aws.String("unhealthy because this and that"), - State: aws.String("unhealthy"), - Reason: aws.String("Target.Timeout"), + State: elbv2types.TargetHealthStateEnumUnhealthy, + Reason: elbv2types.TargetHealthReasonEnumTimeout, }, }, { - Target: &elbv2api.TargetDescription{ + Target: &elbv2types.TargetDescription{ Id: aws.String("24.24.24.24"), }, - TargetHealth: &elbv2api.TargetHealth{ - State: aws.String("healthy"), + TargetHealth: &elbv2types.TargetHealth{ + State: elbv2types.TargetHealthStateEnumHealthy, }, }, }, From ba83b90df6562fe8a827f137b7f8af75ea57bbbd Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 14:01:06 +0200 Subject: [PATCH 08/17] migrate yet another set of wrappers --- internal/pkg/apprunner/apprunner.go | 8 +- .../pkg/apprunner/mocks/mock_apprunner.go | 6 +- internal/pkg/aws/apprunner/apprunner.go | 111 +-- internal/pkg/aws/apprunner/apprunner_test.go | 211 ++--- .../pkg/aws/apprunner/mocks/mock_apprunner.go | 107 ++- internal/pkg/aws/apprunner/service.go | 4 +- internal/pkg/aws/cloudwatch/alarm.go | 42 +- internal/pkg/aws/cloudwatch/cloudwatch.go | 70 +- .../pkg/aws/cloudwatch/cloudwatch_test.go | 175 ++-- .../aws/cloudwatch/mocks/mock_cloudwatch.go | 16 +- internal/pkg/aws/ec2/ec2.go | 133 +-- internal/pkg/aws/ec2/ec2_test.go | 351 +++---- internal/pkg/aws/ec2/mocks/mock_ec2.go | 107 ++- internal/pkg/aws/ecs/ecs.go | 259 +++--- internal/pkg/aws/ecs/ecs_test.go | 864 +++++++++--------- internal/pkg/aws/ecs/errors.go | 16 +- internal/pkg/aws/ecs/mocks/mock_ecs.go | 159 +++- internal/pkg/aws/ecs/service.go | 52 +- internal/pkg/aws/ecs/service_test.go | 74 +- internal/pkg/aws/ecs/task.go | 90 +- internal/pkg/aws/ecs/task_test.go | 238 ++--- internal/pkg/aws/s3/mocks/mock_s3.go | 69 +- internal/pkg/aws/s3/s3.go | 92 +- internal/pkg/aws/s3/s3_test.go | 285 +++--- internal/pkg/cli/app_delete.go | 2 +- internal/pkg/cli/deploy/env.go | 4 +- internal/pkg/cli/deploy/rdws.go | 2 +- internal/pkg/cli/deploy/workload.go | 2 +- internal/pkg/cli/env_delete.go | 2 +- internal/pkg/cli/env_init.go | 6 +- internal/pkg/cli/run_local.go | 21 +- internal/pkg/cli/run_local_test.go | 148 +-- internal/pkg/cli/svc_delete.go | 2 +- internal/pkg/cli/svc_exec.go | 4 +- internal/pkg/cli/svc_pause.go | 2 +- internal/pkg/cli/svc_resume.go | 2 +- internal/pkg/cli/task_delete.go | 2 +- internal/pkg/cli/task_exec.go | 4 +- internal/pkg/cli/task_exec_test.go | 6 +- internal/pkg/cli/task_run.go | 12 +- .../deploy/cloudformation/cloudformation.go | 11 +- .../cloudformation_integration_test.go | 6 +- .../cloudformation/cloudformation_test.go | 6 +- internal/pkg/describe/backend_service.go | 3 +- internal/pkg/describe/lb_web_service.go | 3 +- internal/pkg/describe/rd_web_service.go | 4 +- internal/pkg/describe/rd_web_service_test.go | 4 +- internal/pkg/describe/service.go | 5 +- internal/pkg/describe/service_test.go | 26 +- internal/pkg/describe/static_site.go | 3 +- internal/pkg/describe/status_describe.go | 7 +- internal/pkg/describe/status_describe_test.go | 58 +- internal/pkg/describe/worker_service.go | 3 +- internal/pkg/ecs/ecs.go | 6 +- internal/pkg/ecs/ecs_test.go | 75 +- internal/pkg/ecs/run_task_request_test.go | 34 +- internal/pkg/exec/ssm_plugin.go | 14 +- internal/pkg/exec/ssm_plugin_test.go | 21 +- internal/pkg/logging/task.go | 2 +- internal/pkg/manifest/loader.go | 12 +- internal/pkg/stream/ecs.go | 15 +- internal/pkg/stream/ecs_test.go | 72 +- internal/pkg/task/config_runner_test.go | 6 +- internal/pkg/task/env_runner_test.go | 6 +- 64 files changed, 2175 insertions(+), 1987 deletions(-) diff --git a/internal/pkg/apprunner/apprunner.go b/internal/pkg/apprunner/apprunner.go index a363098934c..e480e4eb31f 100644 --- a/internal/pkg/apprunner/apprunner.go +++ b/internal/pkg/apprunner/apprunner.go @@ -12,8 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy" awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/apprunner/types" "github.com/aws/aws-sdk-go/aws/session" - awsapprunner "github.com/aws/aws-sdk-go/service/apprunner" ) const ( @@ -21,7 +21,7 @@ const ( ) type appRunnerClient interface { - DescribeOperation(operationId, svcARN string) (*awsapprunner.OperationSummary, error) + DescribeOperation(operationId, svcARN string) (*types.OperationSummary, error) StartDeployment(svcARN string) (string, error) DescribeService(svcARN string) (*apprunner.Service, error) WaitForOperation(operationId, svcARN string) error @@ -38,10 +38,10 @@ type Client struct { } // New inits a new Client. -func New(sess *session.Session, rgConfig awsv2.Config) *Client { +func New(_ *session.Session, rgConfig awsv2.Config) *Client { return &Client{ rgGetter: resourcegroups.New(rgConfig), - appRunnerClient: apprunner.New(sess), + appRunnerClient: apprunner.New(rgConfig), } } diff --git a/internal/pkg/apprunner/mocks/mock_apprunner.go b/internal/pkg/apprunner/mocks/mock_apprunner.go index fdffaa9e3a4..1c5cdc01ac1 100644 --- a/internal/pkg/apprunner/mocks/mock_apprunner.go +++ b/internal/pkg/apprunner/mocks/mock_apprunner.go @@ -9,7 +9,7 @@ import ( apprunner "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" resourcegroups "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - apprunner0 "github.com/aws/aws-sdk-go/service/apprunner" + types "github.com/aws/aws-sdk-go-v2/service/apprunner/types" gomock "github.com/golang/mock/gomock" ) @@ -37,10 +37,10 @@ func (m *MockappRunnerClient) EXPECT() *MockappRunnerClientMockRecorder { } // DescribeOperation mocks base method. -func (m *MockappRunnerClient) DescribeOperation(operationId, svcARN string) (*apprunner0.OperationSummary, error) { +func (m *MockappRunnerClient) DescribeOperation(operationId, svcARN string) (*types.OperationSummary, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DescribeOperation", operationId, svcARN) - ret0, _ := ret[0].(*apprunner0.OperationSummary) + ret0, _ := ret[0].(*types.OperationSummary) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/internal/pkg/aws/apprunner/apprunner.go b/internal/pkg/aws/apprunner/apprunner.go index 4995e67c464..9719c814ab7 100644 --- a/internal/pkg/aws/apprunner/apprunner.go +++ b/internal/pkg/aws/apprunner/apprunner.go @@ -5,16 +5,17 @@ package apprunner import ( + "context" "fmt" "regexp" "sort" "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/apprunner" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/apprunner" + "github.com/aws/aws-sdk-go-v2/service/apprunner/types" ) const ( @@ -32,18 +33,18 @@ const ( repositoryTypeECRPublic = "ECR_PUBLIC" // EndpointsID is the ID to look up the App Runner service endpoint. - EndpointsID = apprunner.EndpointsID + EndpointsID = "apprunner" ) type api interface { - DescribeService(input *apprunner.DescribeServiceInput) (*apprunner.DescribeServiceOutput, error) - ListOperations(input *apprunner.ListOperationsInput) (*apprunner.ListOperationsOutput, error) - ListServices(input *apprunner.ListServicesInput) (*apprunner.ListServicesOutput, error) - PauseService(input *apprunner.PauseServiceInput) (*apprunner.PauseServiceOutput, error) - ResumeService(input *apprunner.ResumeServiceInput) (*apprunner.ResumeServiceOutput, error) - StartDeployment(input *apprunner.StartDeploymentInput) (*apprunner.StartDeploymentOutput, error) - DescribeObservabilityConfiguration(input *apprunner.DescribeObservabilityConfigurationInput) (*apprunner.DescribeObservabilityConfigurationOutput, error) - DescribeVpcIngressConnection(input *apprunner.DescribeVpcIngressConnectionInput) (*apprunner.DescribeVpcIngressConnectionOutput, error) + DescribeService(ctx context.Context, input *apprunner.DescribeServiceInput, opts ...func(*apprunner.Options)) (*apprunner.DescribeServiceOutput, error) + ListOperations(ctx context.Context, input *apprunner.ListOperationsInput, opts ...func(*apprunner.Options)) (*apprunner.ListOperationsOutput, error) + ListServices(ctx context.Context, input *apprunner.ListServicesInput, opts ...func(*apprunner.Options)) (*apprunner.ListServicesOutput, error) + PauseService(ctx context.Context, input *apprunner.PauseServiceInput, opts ...func(*apprunner.Options)) (*apprunner.PauseServiceOutput, error) + ResumeService(ctx context.Context, input *apprunner.ResumeServiceInput, opts ...func(*apprunner.Options)) (*apprunner.ResumeServiceOutput, error) + StartDeployment(ctx context.Context, input *apprunner.StartDeploymentInput, opts ...func(*apprunner.Options)) (*apprunner.StartDeploymentOutput, error) + DescribeObservabilityConfiguration(ctx context.Context, input *apprunner.DescribeObservabilityConfigurationInput, opts ...func(*apprunner.Options)) (*apprunner.DescribeObservabilityConfigurationOutput, error) + DescribeVpcIngressConnection(ctx context.Context, input *apprunner.DescribeVpcIngressConnectionInput, opts ...func(*apprunner.Options)) (*apprunner.DescribeVpcIngressConnectionOutput, error) } // AppRunner wraps an AWS AppRunner client. @@ -51,17 +52,17 @@ type AppRunner struct { client api } -// New returns a Service configured against the input session. -func New(s *session.Session) *AppRunner { +// New returns a Service configured against the input config. +func New(cfg awsv2.Config) *AppRunner { return &AppRunner{ - client: apprunner.New(s), + client: apprunner.NewFromConfig(cfg), } } // DescribeService returns a description of an AppRunner service given its ARN. func (a *AppRunner) DescribeService(svcARN string) (*Service, error) { - resp, err := a.client.DescribeService(&apprunner.DescribeServiceInput{ - ServiceArn: aws.String(svcARN), + resp, err := a.client.DescribeService(context.Background(), &apprunner.DescribeServiceInput{ + ServiceArn: awsv2.String(svcARN), }) if err != nil { return nil, fmt.Errorf("describe service %s: %w", svcARN, err) @@ -70,7 +71,7 @@ func (a *AppRunner) DescribeService(svcARN string) (*Service, error) { for k, v := range resp.Service.SourceConfiguration.ImageRepository.ImageConfiguration.RuntimeEnvironmentVariables { envVars = append(envVars, &EnvironmentVariable{ Name: k, - Value: aws.StringValue(v), + Value: v, }) } sort.SliceStable(envVars, func(i int, j int) bool { return envVars[i].Name < envVars[j].Name }) @@ -79,14 +80,14 @@ func (a *AppRunner) DescribeService(svcARN string) (*Service, error) { for k, v := range resp.Service.SourceConfiguration.ImageRepository.ImageConfiguration.RuntimeEnvironmentSecrets { secrets = append(secrets, &EnvironmentSecret{ Name: k, - Value: aws.StringValue(v), + Value: v, }) } sort.SliceStable(secrets, func(i int, j int) bool { return secrets[i].Name < secrets[j].Name }) var observabilityConfiguration ObservabilityConfiguration - if resp.Service.ObservabilityConfiguration != nil && aws.BoolValue(resp.Service.ObservabilityConfiguration.ObservabilityEnabled) { - if out, err := a.client.DescribeObservabilityConfiguration(&apprunner.DescribeObservabilityConfigurationInput{ + if resp.Service.ObservabilityConfiguration != nil && resp.Service.ObservabilityConfiguration.ObservabilityEnabled { + if out, err := a.client.DescribeObservabilityConfiguration(context.Background(), &apprunner.DescribeObservabilityConfigurationInput{ ObservabilityConfigurationArn: resp.Service.ObservabilityConfiguration.ObservabilityConfigurationArn, }); err == nil { // NOTE: swallow the error otherwise, because observability is an optional description of the service. @@ -97,18 +98,18 @@ func (a *AppRunner) DescribeService(svcARN string) (*Service, error) { } } return &Service{ - ServiceARN: aws.StringValue(resp.Service.ServiceArn), - Name: aws.StringValue(resp.Service.ServiceName), - ID: aws.StringValue(resp.Service.ServiceId), - Status: aws.StringValue(resp.Service.Status), - ServiceURL: aws.StringValue(resp.Service.ServiceUrl), + ServiceARN: awsv2.ToString(resp.Service.ServiceArn), + Name: awsv2.ToString(resp.Service.ServiceName), + ID: awsv2.ToString(resp.Service.ServiceId), + Status: string(resp.Service.Status), + ServiceURL: awsv2.ToString(resp.Service.ServiceUrl), DateCreated: *resp.Service.CreatedAt, DateUpdated: *resp.Service.UpdatedAt, EnvironmentVariables: envVars, - CPU: *resp.Service.InstanceConfiguration.Cpu, - Memory: *resp.Service.InstanceConfiguration.Memory, - ImageID: *resp.Service.SourceConfiguration.ImageRepository.ImageIdentifier, - Port: *resp.Service.SourceConfiguration.ImageRepository.ImageConfiguration.Port, + CPU: awsv2.ToString(resp.Service.InstanceConfiguration.Cpu), + Memory: awsv2.ToString(resp.Service.InstanceConfiguration.Memory), + ImageID: awsv2.ToString(resp.Service.SourceConfiguration.ImageRepository.ImageIdentifier), + Port: awsv2.ToString(resp.Service.SourceConfiguration.ImageRepository.ImageConfiguration.Port), Observability: observabilityConfiguration, EnvironmentSecrets: secrets, }, nil @@ -118,15 +119,15 @@ func (a *AppRunner) DescribeService(svcARN string) (*Service, error) { func (a *AppRunner) ServiceARN(svc string) (string, error) { var nextToken *string for { - resp, err := a.client.ListServices(&apprunner.ListServicesInput{ + resp, err := a.client.ListServices(context.Background(), &apprunner.ListServicesInput{ NextToken: nextToken, }) if err != nil { return "", fmt.Errorf("list AppRunner services: %w", err) } for _, service := range resp.ServiceSummaryList { - if aws.StringValue(service.ServiceName) == svc { - return aws.StringValue(service.ServiceArn), nil + if awsv2.ToString(service.ServiceName) == svc { + return awsv2.ToString(service.ServiceArn), nil } } if resp.NextToken == nil { @@ -139,16 +140,16 @@ func (a *AppRunner) ServiceARN(svc string) (string, error) { // PauseService pause the running App Runner service. func (a *AppRunner) PauseService(svcARN string) error { - resp, err := a.client.PauseService(&apprunner.PauseServiceInput{ - ServiceArn: aws.String(svcARN), + resp, err := a.client.PauseService(context.Background(), &apprunner.PauseServiceInput{ + ServiceArn: awsv2.String(svcARN), }) if err != nil { return fmt.Errorf("pause service operation failed: %w", err) } - if resp.OperationId == nil && aws.StringValue(resp.Service.Status) == svcStatusPaused { + if resp.OperationId == nil && string(resp.Service.Status) == svcStatusPaused { return nil } - if err := a.WaitForOperation(aws.StringValue(resp.OperationId), svcARN); err != nil { + if err := a.WaitForOperation(awsv2.ToString(resp.OperationId), svcARN); err != nil { return err } return nil @@ -156,16 +157,16 @@ func (a *AppRunner) PauseService(svcARN string) error { // ResumeService resumes a paused App Runner service. func (a *AppRunner) ResumeService(svcARN string) error { - resp, err := a.client.ResumeService(&apprunner.ResumeServiceInput{ - ServiceArn: aws.String(svcARN), + resp, err := a.client.ResumeService(context.Background(), &apprunner.ResumeServiceInput{ + ServiceArn: awsv2.String(svcARN), }) if err != nil { return fmt.Errorf("resume service operation failed: %w", err) } - if resp.OperationId == nil && aws.StringValue(resp.Service.Status) == svcStatusRunning { + if resp.OperationId == nil && string(resp.Service.Status) == svcStatusRunning { return nil } - if err := a.WaitForOperation(aws.StringValue(resp.OperationId), svcARN); err != nil { + if err := a.WaitForOperation(awsv2.ToString(resp.OperationId), svcARN); err != nil { return err } return nil @@ -173,29 +174,29 @@ func (a *AppRunner) ResumeService(svcARN string) error { // StartDeployment initiates a manual deployment to an AWS App Runner service. func (a *AppRunner) StartDeployment(svcARN string) (string, error) { - out, err := a.client.StartDeployment(&apprunner.StartDeploymentInput{ - ServiceArn: aws.String(svcARN), + out, err := a.client.StartDeployment(context.Background(), &apprunner.StartDeploymentInput{ + ServiceArn: awsv2.String(svcARN), }) if err != nil { return "", fmt.Errorf("start new deployment: %w", err) } - return aws.StringValue(out.OperationId), nil + return awsv2.ToString(out.OperationId), nil } // DescribeOperation return OperationSummary for given OperationId and ServiceARN. -func (a *AppRunner) DescribeOperation(operationId, svcARN string) (*apprunner.OperationSummary, error) { +func (a *AppRunner) DescribeOperation(operationId, svcARN string) (*types.OperationSummary, error) { var nextToken *string for { - resp, err := a.client.ListOperations(&apprunner.ListOperationsInput{ - ServiceArn: aws.String(svcARN), + resp, err := a.client.ListOperations(context.Background(), &apprunner.ListOperationsInput{ + ServiceArn: awsv2.String(svcARN), NextToken: nextToken, }) if err != nil { return nil, fmt.Errorf("list operations: %w", err) } - for _, operation := range resp.OperationSummaryList { - if aws.StringValue(operation.Id) == operationId { - return operation, nil + for i := range resp.OperationSummaryList { + if awsv2.ToString(resp.OperationSummaryList[i].Id) == operationId { + return &resp.OperationSummaryList[i], nil } } if resp.NextToken == nil { @@ -213,7 +214,7 @@ func (a *AppRunner) WaitForOperation(operationId, svcARN string) error { if err != nil { return fmt.Errorf("error describing operation %s: %w", operationId, err) } - switch status := aws.StringValue(resp.Status); status { + switch status := string(resp.Status); status { case opStatusSucceeded: return nil case opStatusFailed: @@ -227,14 +228,14 @@ func (a *AppRunner) WaitForOperation(operationId, svcARN string) error { // PrivateURL returns the url associated with a VPC Ingress Connection. func (a *AppRunner) PrivateURL(vicARN string) (string, error) { - resp, err := a.client.DescribeVpcIngressConnection(&apprunner.DescribeVpcIngressConnectionInput{ - VpcIngressConnectionArn: aws.String(vicARN), + resp, err := a.client.DescribeVpcIngressConnection(context.Background(), &apprunner.DescribeVpcIngressConnectionInput{ + VpcIngressConnectionArn: awsv2.String(vicARN), }) if err != nil { return "", fmt.Errorf("describe vpc ingress connection %q: %w", vicARN, err) } - return aws.StringValue(resp.VpcIngressConnection.DomainName), nil + return awsv2.ToString(resp.VpcIngressConnection.DomainName), nil } // ParseServiceName returns the service name. diff --git a/internal/pkg/aws/apprunner/apprunner_test.go b/internal/pkg/aws/apprunner/apprunner_test.go index dbbf3cbd60f..926def8f673 100644 --- a/internal/pkg/aws/apprunner/apprunner_test.go +++ b/internal/pkg/aws/apprunner/apprunner_test.go @@ -10,8 +10,9 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/apprunner" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/apprunner" + "github.com/aws/aws-sdk-go-v2/service/apprunner/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -29,34 +30,34 @@ func TestAppRunner_DescribeService(t *testing.T) { "success": { serviceArn: "mock-svc-arn", mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeService(&apprunner.DescribeServiceInput{ - ServiceArn: aws.String("mock-svc-arn"), + m.EXPECT().DescribeService(gomock.Any(), &apprunner.DescribeServiceInput{ + ServiceArn: awsv2.String("mock-svc-arn"), }).Return(&apprunner.DescribeServiceOutput{ - Service: &apprunner.Service{ - ServiceArn: aws.String("111111111111.apprunner.us-east-1.amazonaws.com/service/testsvc/test-svc-id"), - ServiceId: aws.String("test-svc-id"), - ServiceName: aws.String("testapp-testenv-testsvc"), - ServiceUrl: aws.String("tumkjmvjif.public.us-east-1.apprunner.aws.dev"), - Status: aws.String("RUNNING"), + Service: &types.Service{ + ServiceArn: awsv2.String("111111111111.apprunner.us-east-1.amazonaws.com/service/testsvc/test-svc-id"), + ServiceId: awsv2.String("test-svc-id"), + ServiceName: awsv2.String("testapp-testenv-testsvc"), + ServiceUrl: awsv2.String("tumkjmvjif.public.us-east-1.apprunner.aws.dev"), + Status: types.ServiceStatusRunning, CreatedAt: &mockTime, UpdatedAt: &mockTime, - InstanceConfiguration: &apprunner.InstanceConfiguration{ - Cpu: aws.String("1024"), - Memory: aws.String("2048"), + InstanceConfiguration: &types.InstanceConfiguration{ + Cpu: awsv2.String("1024"), + Memory: awsv2.String("2048"), }, - SourceConfiguration: &apprunner.SourceConfiguration{ - ImageRepository: &apprunner.ImageRepository{ - ImageIdentifier: aws.String("111111111111.dkr.ecr.us-east-1.amazonaws.com/testapp/testsvc:8cdef9a"), - ImageConfiguration: &apprunner.ImageConfiguration{ - RuntimeEnvironmentVariables: aws.StringMap(map[string]string{ + SourceConfiguration: &types.SourceConfiguration{ + ImageRepository: &types.ImageRepository{ + ImageIdentifier: awsv2.String("111111111111.dkr.ecr.us-east-1.amazonaws.com/testapp/testsvc:8cdef9a"), + ImageConfiguration: &types.ImageConfiguration{ + RuntimeEnvironmentVariables: map[string]string{ "LOG_LEVEL": "info", "COPILOT_APPLICATION_NAME": "testapp", - }), - RuntimeEnvironmentSecrets: aws.StringMap(map[string]string{ + }, + RuntimeEnvironmentSecrets: map[string]string{ "zzz123": "parameter/zzz123", "my-ssm-secret": "arn:aws:ssm:us-east-1:111111111111:parameter/jan11ssm", - }), - Port: aws.String("80"), + }, + Port: awsv2.String("80"), }, }, }, @@ -137,15 +138,15 @@ func TestAppRunner_ServiceARN(t *testing.T) { }{ "success": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ListServices(&apprunner.ListServicesInput{}).Return(&apprunner.ListServicesOutput{ - ServiceSummaryList: []*apprunner.ServiceSummary{ + m.EXPECT().ListServices(gomock.Any(), &apprunner.ListServicesInput{}).Return(&apprunner.ListServicesOutput{ + ServiceSummaryList: []types.ServiceSummary{ { - ServiceName: aws.String("mockSvc"), - ServiceArn: aws.String("mockSvcArn"), + ServiceName: awsv2.String("mockSvc"), + ServiceArn: awsv2.String("mockSvcArn"), }, { - ServiceName: aws.String("mockSvc2"), - ServiceArn: aws.String("mockSvcArn2"), + ServiceName: awsv2.String("mockSvc2"), + ServiceArn: awsv2.String("mockSvcArn2"), }, }, }, nil) @@ -154,17 +155,17 @@ func TestAppRunner_ServiceARN(t *testing.T) { }, "errors if fail to get services": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ListServices(&apprunner.ListServicesInput{}).Return(nil, testError) + m.EXPECT().ListServices(gomock.Any(), &apprunner.ListServicesInput{}).Return(nil, testError) }, wantErr: fmt.Errorf("list AppRunner services: some error"), }, "errors if no service found": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ListServices(&apprunner.ListServicesInput{}).Return(&apprunner.ListServicesOutput{ - ServiceSummaryList: []*apprunner.ServiceSummary{ + m.EXPECT().ListServices(gomock.Any(), &apprunner.ListServicesInput{}).Return(&apprunner.ListServicesOutput{ + ServiceSummaryList: []types.ServiceSummary{ { - ServiceName: aws.String("mockSvc2"), - ServiceArn: aws.String("mockSvcArn2"), + ServiceName: awsv2.String("mockSvc2"), + ServiceArn: awsv2.String("mockSvcArn2"), }, }, }, nil) @@ -339,31 +340,31 @@ func TestAppRunner_DescribeOperation(t *testing.T) { mockOperationId = "mock-operation" mockSvcARN = "mockSvcArn" ) - mockOperationSummary := apprunner.OperationSummary{ - Id: aws.String("mock-operation"), - TargetArn: aws.String("mockSvcArn"), - Status: aws.String("SUCCEEDED"), + mockOperationSummary := types.OperationSummary{ + Id: awsv2.String("mock-operation"), + TargetArn: awsv2.String("mockSvcArn"), + Status: types.OperationStatusSucceeded, } testError := errors.New("some error") testCases := map[string]struct { mockAppRunnerClient func(m *mocks.Mockapi) wantErr error - wantSvcOperation *apprunner.OperationSummary + wantSvcOperation *types.OperationSummary }{ "error if fail to get operation": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(nil, testError) + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(nil, testError) }, wantErr: fmt.Errorf("list operations: some error"), }, "error if no operation found for given operation id": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ - OperationSummaryList: []*apprunner.OperationSummary{ + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ + OperationSummaryList: []types.OperationSummary{ { - Id: aws.String("badOperationId"), - TargetArn: aws.String(mockSvcARN), + Id: awsv2.String("badOperationId"), + TargetArn: awsv2.String(mockSvcARN), }, }, }, nil) @@ -372,12 +373,12 @@ func TestAppRunner_DescribeOperation(t *testing.T) { }, "success": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ - OperationSummaryList: []*apprunner.OperationSummary{ + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ + OperationSummaryList: []types.OperationSummary{ { - Id: aws.String(mockOperationId), - TargetArn: aws.String(mockSvcARN), - Status: aws.String("SUCCEEDED"), + Id: awsv2.String(mockOperationId), + TargetArn: awsv2.String(mockSvcARN), + Status: types.OperationStatusSucceeded, }, }, }, nil) @@ -418,19 +419,19 @@ func TestAppRunner_PrivateURL(t *testing.T) { }{ "error if error from sdk": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeVpcIngressConnection(&apprunner.DescribeVpcIngressConnectionInput{ - VpcIngressConnectionArn: aws.String(mockARN), + m.EXPECT().DescribeVpcIngressConnection(gomock.Any(), &apprunner.DescribeVpcIngressConnectionInput{ + VpcIngressConnectionArn: awsv2.String(mockARN), }).Return(nil, errors.New("some error")) }, expectedErr: `describe vpc ingress connection "mockVicArn": some error`, }, "success": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeVpcIngressConnection(&apprunner.DescribeVpcIngressConnectionInput{ - VpcIngressConnectionArn: aws.String(mockARN), + m.EXPECT().DescribeVpcIngressConnection(gomock.Any(), &apprunner.DescribeVpcIngressConnectionInput{ + VpcIngressConnectionArn: awsv2.String(mockARN), }).Return(&apprunner.DescribeVpcIngressConnectionOutput{ - VpcIngressConnection: &apprunner.VpcIngressConnection{ - DomainName: aws.String("example.com"), + VpcIngressConnection: &types.VpcIngressConnection{ + DomainName: awsv2.String("example.com"), }, }, nil) }, @@ -468,33 +469,33 @@ func TestAppRunner_PauseService(t *testing.T) { mockAppRunnerClient func(m *mocks.Mockapi) wantErr error - wantSvcOperation *apprunner.OperationSummary + wantSvcOperation *types.OperationSummary }{ "success if service is already paused": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().PauseService(&apprunner.PauseServiceInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.PauseServiceOutput{ + m.EXPECT().PauseService(gomock.Any(), &apprunner.PauseServiceInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.PauseServiceOutput{ OperationId: nil, - Service: &apprunner.Service{ - ServiceArn: aws.String(mockSvcARN), - Status: aws.String("PAUSED"), + Service: &types.Service{ + ServiceArn: awsv2.String(mockSvcARN), + Status: types.ServiceStatusPaused, }, }, nil) }, }, "waits until operation succeeds": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().PauseService(&apprunner.PauseServiceInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.PauseServiceOutput{ - OperationId: aws.String(mockOperationId), - Service: &apprunner.Service{ - ServiceArn: aws.String(mockSvcARN), + m.EXPECT().PauseService(gomock.Any(), &apprunner.PauseServiceInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.PauseServiceOutput{ + OperationId: awsv2.String(mockOperationId), + Service: &types.Service{ + ServiceArn: awsv2.String(mockSvcARN), }, }, nil) - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ - OperationSummaryList: []*apprunner.OperationSummary{ + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ + OperationSummaryList: []types.OperationSummary{ { - Id: aws.String(mockOperationId), - TargetArn: aws.String(mockSvcARN), - Status: aws.String("SUCCEEDED"), + Id: awsv2.String(mockOperationId), + TargetArn: awsv2.String(mockSvcARN), + Status: types.OperationStatusSucceeded, }, }, }, nil) @@ -502,18 +503,18 @@ func TestAppRunner_PauseService(t *testing.T) { }, "return error if operation failed": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().PauseService(&apprunner.PauseServiceInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.PauseServiceOutput{ - OperationId: aws.String(mockOperationId), - Service: &apprunner.Service{ - ServiceArn: aws.String(mockSvcARN), + m.EXPECT().PauseService(gomock.Any(), &apprunner.PauseServiceInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.PauseServiceOutput{ + OperationId: awsv2.String(mockOperationId), + Service: &types.Service{ + ServiceArn: awsv2.String(mockSvcARN), }, }, nil) - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ - OperationSummaryList: []*apprunner.OperationSummary{ + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ + OperationSummaryList: []types.OperationSummary{ { - Id: aws.String(mockOperationId), - TargetArn: aws.String(mockSvcARN), - Status: aws.String("FAILED"), + Id: awsv2.String(mockOperationId), + TargetArn: awsv2.String(mockSvcARN), + Status: types.OperationStatusFailed, }, }, }, nil) @@ -553,33 +554,33 @@ func TestAppRunner_ResumeService(t *testing.T) { mockAppRunnerClient func(m *mocks.Mockapi) wantErr error - wantSvcOperation *apprunner.OperationSummary + wantSvcOperation *types.OperationSummary }{ "success if service is already running": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ResumeService(&apprunner.ResumeServiceInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ResumeServiceOutput{ + m.EXPECT().ResumeService(gomock.Any(), &apprunner.ResumeServiceInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ResumeServiceOutput{ OperationId: nil, - Service: &apprunner.Service{ - ServiceArn: aws.String(mockSvcARN), - Status: aws.String("RUNNING"), + Service: &types.Service{ + ServiceArn: awsv2.String(mockSvcARN), + Status: types.ServiceStatusRunning, }, }, nil) }, }, "waits until operation succeeds": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ResumeService(&apprunner.ResumeServiceInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ResumeServiceOutput{ - OperationId: aws.String(mockOperationId), - Service: &apprunner.Service{ - ServiceArn: aws.String(mockSvcARN), + m.EXPECT().ResumeService(gomock.Any(), &apprunner.ResumeServiceInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ResumeServiceOutput{ + OperationId: awsv2.String(mockOperationId), + Service: &types.Service{ + ServiceArn: awsv2.String(mockSvcARN), }, }, nil) - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ - OperationSummaryList: []*apprunner.OperationSummary{ + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ + OperationSummaryList: []types.OperationSummary{ { - Id: aws.String(mockOperationId), - TargetArn: aws.String(mockSvcARN), - Status: aws.String("SUCCEEDED"), + Id: awsv2.String(mockOperationId), + TargetArn: awsv2.String(mockSvcARN), + Status: types.OperationStatusSucceeded, }, }, }, nil) @@ -587,18 +588,18 @@ func TestAppRunner_ResumeService(t *testing.T) { }, "return error if operation failed": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().ResumeService(&apprunner.ResumeServiceInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ResumeServiceOutput{ - OperationId: aws.String(mockOperationId), - Service: &apprunner.Service{ - ServiceArn: aws.String(mockSvcARN), + m.EXPECT().ResumeService(gomock.Any(), &apprunner.ResumeServiceInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ResumeServiceOutput{ + OperationId: awsv2.String(mockOperationId), + Service: &types.Service{ + ServiceArn: awsv2.String(mockSvcARN), }, }, nil) - m.EXPECT().ListOperations(&apprunner.ListOperationsInput{ServiceArn: aws.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ - OperationSummaryList: []*apprunner.OperationSummary{ + m.EXPECT().ListOperations(gomock.Any(), &apprunner.ListOperationsInput{ServiceArn: awsv2.String(mockSvcARN)}).Return(&apprunner.ListOperationsOutput{ + OperationSummaryList: []types.OperationSummary{ { - Id: aws.String(mockOperationId), - TargetArn: aws.String(mockSvcARN), - Status: aws.String("FAILED"), + Id: awsv2.String(mockOperationId), + TargetArn: awsv2.String(mockSvcARN), + Status: types.OperationStatusFailed, }, }, }, nil) @@ -642,18 +643,18 @@ func TestAppRunner_StartDeployment(t *testing.T) { }{ "error if fail to start new deployment": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().StartDeployment(&apprunner.StartDeploymentInput{ - ServiceArn: aws.String(mockSvcARN), + m.EXPECT().StartDeployment(gomock.Any(), &apprunner.StartDeploymentInput{ + ServiceArn: awsv2.String(mockSvcARN), }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("start new deployment: some error"), }, "success": { mockAppRunnerClient: func(m *mocks.Mockapi) { - m.EXPECT().StartDeployment(&apprunner.StartDeploymentInput{ - ServiceArn: aws.String(mockSvcARN), + m.EXPECT().StartDeployment(gomock.Any(), &apprunner.StartDeploymentInput{ + ServiceArn: awsv2.String(mockSvcARN), }).Return(&apprunner.StartDeploymentOutput{ - OperationId: aws.String(mockOperationId), + OperationId: awsv2.String(mockOperationId), }, nil) }, wantOperationID: mockOperationId, diff --git a/internal/pkg/aws/apprunner/mocks/mock_apprunner.go b/internal/pkg/aws/apprunner/mocks/mock_apprunner.go index e00754c904d..7911278c24a 100644 --- a/internal/pkg/aws/apprunner/mocks/mock_apprunner.go +++ b/internal/pkg/aws/apprunner/mocks/mock_apprunner.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - apprunner "github.com/aws/aws-sdk-go/service/apprunner" + apprunner "github.com/aws/aws-sdk-go-v2/service/apprunner" gomock "github.com/golang/mock/gomock" ) @@ -35,121 +36,161 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeObservabilityConfiguration mocks base method. -func (m *Mockapi) DescribeObservabilityConfiguration(input *apprunner.DescribeObservabilityConfigurationInput) (*apprunner.DescribeObservabilityConfigurationOutput, error) { +func (m *Mockapi) DescribeObservabilityConfiguration(ctx context.Context, input *apprunner.DescribeObservabilityConfigurationInput, opts ...func(*apprunner.Options)) (*apprunner.DescribeObservabilityConfigurationOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeObservabilityConfiguration", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeObservabilityConfiguration", varargs...) ret0, _ := ret[0].(*apprunner.DescribeObservabilityConfigurationOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeObservabilityConfiguration indicates an expected call of DescribeObservabilityConfiguration. -func (mr *MockapiMockRecorder) DescribeObservabilityConfiguration(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeObservabilityConfiguration(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeObservabilityConfiguration", reflect.TypeOf((*Mockapi)(nil).DescribeObservabilityConfiguration), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeObservabilityConfiguration", reflect.TypeOf((*Mockapi)(nil).DescribeObservabilityConfiguration), varargs...) } // DescribeService mocks base method. -func (m *Mockapi) DescribeService(input *apprunner.DescribeServiceInput) (*apprunner.DescribeServiceOutput, error) { +func (m *Mockapi) DescribeService(ctx context.Context, input *apprunner.DescribeServiceInput, opts ...func(*apprunner.Options)) (*apprunner.DescribeServiceOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeService", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeService", varargs...) ret0, _ := ret[0].(*apprunner.DescribeServiceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeService indicates an expected call of DescribeService. -func (mr *MockapiMockRecorder) DescribeService(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeService(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeService", reflect.TypeOf((*Mockapi)(nil).DescribeService), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeService", reflect.TypeOf((*Mockapi)(nil).DescribeService), varargs...) } // DescribeVpcIngressConnection mocks base method. -func (m *Mockapi) DescribeVpcIngressConnection(input *apprunner.DescribeVpcIngressConnectionInput) (*apprunner.DescribeVpcIngressConnectionOutput, error) { +func (m *Mockapi) DescribeVpcIngressConnection(ctx context.Context, input *apprunner.DescribeVpcIngressConnectionInput, opts ...func(*apprunner.Options)) (*apprunner.DescribeVpcIngressConnectionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeVpcIngressConnection", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeVpcIngressConnection", varargs...) ret0, _ := ret[0].(*apprunner.DescribeVpcIngressConnectionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeVpcIngressConnection indicates an expected call of DescribeVpcIngressConnection. -func (mr *MockapiMockRecorder) DescribeVpcIngressConnection(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeVpcIngressConnection(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeVpcIngressConnection", reflect.TypeOf((*Mockapi)(nil).DescribeVpcIngressConnection), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeVpcIngressConnection", reflect.TypeOf((*Mockapi)(nil).DescribeVpcIngressConnection), varargs...) } // ListOperations mocks base method. -func (m *Mockapi) ListOperations(input *apprunner.ListOperationsInput) (*apprunner.ListOperationsOutput, error) { +func (m *Mockapi) ListOperations(ctx context.Context, input *apprunner.ListOperationsInput, opts ...func(*apprunner.Options)) (*apprunner.ListOperationsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListOperations", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListOperations", varargs...) ret0, _ := ret[0].(*apprunner.ListOperationsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListOperations indicates an expected call of ListOperations. -func (mr *MockapiMockRecorder) ListOperations(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListOperations(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListOperations", reflect.TypeOf((*Mockapi)(nil).ListOperations), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListOperations", reflect.TypeOf((*Mockapi)(nil).ListOperations), varargs...) } // ListServices mocks base method. -func (m *Mockapi) ListServices(input *apprunner.ListServicesInput) (*apprunner.ListServicesOutput, error) { +func (m *Mockapi) ListServices(ctx context.Context, input *apprunner.ListServicesInput, opts ...func(*apprunner.Options)) (*apprunner.ListServicesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServices", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListServices", varargs...) ret0, _ := ret[0].(*apprunner.ListServicesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListServices indicates an expected call of ListServices. -func (mr *MockapiMockRecorder) ListServices(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListServices(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*Mockapi)(nil).ListServices), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServices", reflect.TypeOf((*Mockapi)(nil).ListServices), varargs...) } // PauseService mocks base method. -func (m *Mockapi) PauseService(input *apprunner.PauseServiceInput) (*apprunner.PauseServiceOutput, error) { +func (m *Mockapi) PauseService(ctx context.Context, input *apprunner.PauseServiceInput, opts ...func(*apprunner.Options)) (*apprunner.PauseServiceOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "PauseService", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "PauseService", varargs...) ret0, _ := ret[0].(*apprunner.PauseServiceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // PauseService indicates an expected call of PauseService. -func (mr *MockapiMockRecorder) PauseService(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) PauseService(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PauseService", reflect.TypeOf((*Mockapi)(nil).PauseService), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PauseService", reflect.TypeOf((*Mockapi)(nil).PauseService), varargs...) } // ResumeService mocks base method. -func (m *Mockapi) ResumeService(input *apprunner.ResumeServiceInput) (*apprunner.ResumeServiceOutput, error) { +func (m *Mockapi) ResumeService(ctx context.Context, input *apprunner.ResumeServiceInput, opts ...func(*apprunner.Options)) (*apprunner.ResumeServiceOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ResumeService", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ResumeService", varargs...) ret0, _ := ret[0].(*apprunner.ResumeServiceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ResumeService indicates an expected call of ResumeService. -func (mr *MockapiMockRecorder) ResumeService(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ResumeService(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResumeService", reflect.TypeOf((*Mockapi)(nil).ResumeService), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResumeService", reflect.TypeOf((*Mockapi)(nil).ResumeService), varargs...) } // StartDeployment mocks base method. -func (m *Mockapi) StartDeployment(input *apprunner.StartDeploymentInput) (*apprunner.StartDeploymentOutput, error) { +func (m *Mockapi) StartDeployment(ctx context.Context, input *apprunner.StartDeploymentInput, opts ...func(*apprunner.Options)) (*apprunner.StartDeploymentOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StartDeployment", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "StartDeployment", varargs...) ret0, _ := ret[0].(*apprunner.StartDeploymentOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // StartDeployment indicates an expected call of StartDeployment. -func (mr *MockapiMockRecorder) StartDeployment(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) StartDeployment(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartDeployment", reflect.TypeOf((*Mockapi)(nil).StartDeployment), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartDeployment", reflect.TypeOf((*Mockapi)(nil).StartDeployment), varargs...) } diff --git a/internal/pkg/aws/apprunner/service.go b/internal/pkg/aws/apprunner/service.go index 7a9060a03e9..b7ff2abdef2 100644 --- a/internal/pkg/aws/apprunner/service.go +++ b/internal/pkg/aws/apprunner/service.go @@ -7,7 +7,7 @@ package apprunner import ( "time" - "github.com/aws/aws-sdk-go/service/apprunner" + "github.com/aws/aws-sdk-go-v2/service/apprunner/types" ) // Service wraps up AppRunner Service struct. @@ -46,4 +46,4 @@ type ObservabilityConfiguration struct { } // TraceConfiguration wraps AppRunner TraceConfiguration. -type TraceConfiguration apprunner.TraceConfiguration +type TraceConfiguration types.TraceConfiguration diff --git a/internal/pkg/aws/cloudwatch/alarm.go b/internal/pkg/aws/cloudwatch/alarm.go index 21c159c1848..2b2d1b00405 100644 --- a/internal/pkg/aws/cloudwatch/alarm.go +++ b/internal/pkg/aws/cloudwatch/alarm.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" ) const ( @@ -30,42 +30,42 @@ type comparisonOperator string func (c comparisonOperator) humanString() string { switch c { - case cloudwatch.ComparisonOperatorGreaterThanOrEqualToThreshold: + case comparisonOperator(types.ComparisonOperatorGreaterThanOrEqualToThreshold): return "≥" - case cloudwatch.ComparisonOperatorGreaterThanThreshold: + case comparisonOperator(types.ComparisonOperatorGreaterThanThreshold): return ">" - case cloudwatch.ComparisonOperatorLessThanThreshold: + case comparisonOperator(types.ComparisonOperatorLessThanThreshold): return "<" - case cloudwatch.ComparisonOperatorLessThanOrEqualToThreshold: + case comparisonOperator(types.ComparisonOperatorLessThanOrEqualToThreshold): return "≤" - case cloudwatch.ComparisonOperatorLessThanLowerOrGreaterThanUpperThreshold: + case comparisonOperator(types.ComparisonOperatorLessThanLowerOrGreaterThanUpperThreshold): return "outside" - case cloudwatch.ComparisonOperatorLessThanLowerThreshold: + case comparisonOperator(types.ComparisonOperatorLessThanLowerThreshold): return "<" - case cloudwatch.ComparisonOperatorGreaterThanUpperThreshold: + case comparisonOperator(types.ComparisonOperatorGreaterThanUpperThreshold): return ">" default: return "" } } -type metricAlarm cloudwatch.MetricAlarm +type metricAlarm types.MetricAlarm func (a metricAlarm) condition() string { thresholdType := a.alarmThresholdType() - metricName := aws.StringValue(a.MetricName) - period := aws.Int64Value(a.Period) - evaluationPeriod := aws.Int64Value(a.EvaluationPeriods) - datapointsToAlarm := aws.Int64Value(a.DatapointsToAlarm) + metricName := awsv2.ToString(a.MetricName) + period := int64(awsv2.ToInt32(a.Period)) + evaluationPeriod := int64(awsv2.ToInt32(a.EvaluationPeriods)) + datapointsToAlarm := int64(awsv2.ToInt32(a.DatapointsToAlarm)) if datapointsToAlarm == 0 { // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cw-alarm.html#cfn-cloudwatch-alarm-datapointstoalarm datapointsToAlarm = evaluationPeriod } - operator := comparisonOperator(aws.StringValue(a.ComparisonOperator)) + operator := comparisonOperator(a.ComparisonOperator) switch thresholdType { case static: return fmt.Sprintf(fmtStaticMetricCondition, metricName, operator.humanString(), - aws.Float64Value(a.Threshold), datapointsToAlarm, humanizePeriod(evaluationPeriod, period)) + awsv2.ToFloat64(a.Threshold), datapointsToAlarm, humanizePeriod(evaluationPeriod, period)) default: return "-" } @@ -77,20 +77,20 @@ func (a metricAlarm) alarmThresholdType() alarmThresholdTypes { } thresholdMetric := a.thresholdMetric() if thresholdMetric != nil { - if strings.HasPrefix(aws.StringValue(thresholdMetric.Expression), anomalyDetectionBandExpression) { + if strings.HasPrefix(awsv2.ToString(thresholdMetric.Expression), anomalyDetectionBandExpression) { return predictive } } return dynamic } -func (a metricAlarm) thresholdMetric() *cloudwatch.MetricDataQuery { +func (a metricAlarm) thresholdMetric() *types.MetricDataQuery { if a.ThresholdMetricId == nil { return nil } - for _, m := range a.Metrics { - if aws.StringValue(m.Id) == aws.StringValue(a.ThresholdMetricId) { - return m + for idx := range a.Metrics { + if awsv2.ToString(a.Metrics[idx].Id) == awsv2.ToString(a.ThresholdMetricId) { + return &a.Metrics[idx] } } return nil diff --git a/internal/pkg/aws/cloudwatch/cloudwatch.go b/internal/pkg/aws/cloudwatch/cloudwatch.go index aa46ff0b94c..60facf1ebbf 100644 --- a/internal/pkg/aws/cloudwatch/cloudwatch.go +++ b/internal/pkg/aws/cloudwatch/cloudwatch.go @@ -5,6 +5,7 @@ package cloudwatch import ( + "context" "fmt" "strings" "time" @@ -12,10 +13,9 @@ import ( rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" "github.com/dustin/go-humanize" ) @@ -29,7 +29,7 @@ const ( var humanizeDuration = humanize.RelTime type api interface { - DescribeAlarms(input *cloudwatch.DescribeAlarmsInput) (*cloudwatch.DescribeAlarmsOutput, error) + DescribeAlarms(context.Context, *cloudwatch.DescribeAlarmsInput, ...func(*cloudwatch.Options)) (*cloudwatch.DescribeAlarmsOutput, error) } type resourceGetter interface { @@ -60,10 +60,10 @@ type AlarmDescription struct { Environment string `json:"environment"` } -// New returns a CloudWatch struct configured against the input session and SDK v2 Resource Groups config. -func New(s *session.Session, rgConfig awsv2.Config) *CloudWatch { +// New returns a CloudWatch struct configured against the input SDK v2 CloudWatch and Resource Groups configs. +func New(cwConfig awsv2.Config, rgConfig awsv2.Config) *CloudWatch { return &CloudWatch{ - client: cloudwatch.New(s), + client: cloudwatch.NewFromConfig(cwConfig), rgClient: rg.New(rgConfig), } } @@ -94,14 +94,14 @@ type DescribeAlarmOpts func(input *cloudwatch.DescribeAlarmsInput) // WithNames sets DescribeAlarms to filter on alarm names. func WithNames(names []string) DescribeAlarmOpts { return func(in *cloudwatch.DescribeAlarmsInput) { - in.AlarmNames = aws.StringSlice(names) + in.AlarmNames = names } } // WithPrefix sets DescribeAlarms to filter on a name prefix. func WithPrefix(prefix string) DescribeAlarmOpts { return func(in *cloudwatch.DescribeAlarmsInput) { - in.AlarmNamePrefix = aws.String(prefix) + in.AlarmNamePrefix = awsv2.String(prefix) } } @@ -117,7 +117,7 @@ func (cw *CloudWatch) AlarmStatuses(opts ...DescribeAlarmOpts) ([]AlarmStatus, e } } for { - alarmResp, err := cw.client.DescribeAlarms(in) + alarmResp, err := cw.client.DescribeAlarms(context.Background(), in) if err != nil { return nil, fmt.Errorf("describe CloudWatch alarms: %w", err) } @@ -141,10 +141,10 @@ func (cw *CloudWatch) AlarmDescriptions(alarmNames []string) ([]*AlarmDescriptio } var alarmDescriptions []*AlarmDescription in := &cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice(alarmNames), + AlarmNames: alarmNames, } for { - alarmResp, err := cw.client.DescribeAlarms(in) + alarmResp, err := cw.client.DescribeAlarms(context.Background(), in) if err != nil { return nil, fmt.Errorf("describe CloudWatch alarms: %w", err) } @@ -161,45 +161,36 @@ func (cw *CloudWatch) AlarmDescriptions(alarmNames []string) ([]*AlarmDescriptio return alarmDescriptions, nil } -func (cw *CloudWatch) compositeAlarmsDescriptions(alarms []*cloudwatch.CompositeAlarm) []*AlarmDescription { +func (cw *CloudWatch) compositeAlarmsDescriptions(alarms []types.CompositeAlarm) []*AlarmDescription { var alarmDescriptionList []*AlarmDescription for _, alarm := range alarms { - if alarm == nil { - continue - } alarmDescriptionList = append(alarmDescriptionList, &AlarmDescription{ - Name: aws.StringValue(alarm.AlarmName), - Description: aws.StringValue(alarm.AlarmDescription), + Name: awsv2.ToString(alarm.AlarmName), + Description: awsv2.ToString(alarm.AlarmDescription), }) } return alarmDescriptionList } -func (cw *CloudWatch) metricAlarmsDescriptions(alarms []*cloudwatch.MetricAlarm) []*AlarmDescription { +func (cw *CloudWatch) metricAlarmsDescriptions(alarms []types.MetricAlarm) []*AlarmDescription { var alarmDescriptionsList []*AlarmDescription for _, alarm := range alarms { - if alarm == nil { - continue - } alarmDescriptionsList = append(alarmDescriptionsList, &AlarmDescription{ - Name: aws.StringValue(alarm.AlarmName), - Description: aws.StringValue(alarm.AlarmDescription), + Name: awsv2.ToString(alarm.AlarmName), + Description: awsv2.ToString(alarm.AlarmDescription), }) } return alarmDescriptionsList } -func (cw *CloudWatch) compositeAlarmsStatus(alarms []*cloudwatch.CompositeAlarm) []AlarmStatus { +func (cw *CloudWatch) compositeAlarmsStatus(alarms []types.CompositeAlarm) []AlarmStatus { var alarmStatusList []AlarmStatus for _, alarm := range alarms { - if alarm == nil { - continue - } alarmStatusList = append(alarmStatusList, AlarmStatus{ - Arn: aws.StringValue(alarm.AlarmArn), - Name: aws.StringValue(alarm.AlarmName), - Condition: aws.StringValue(alarm.AlarmRule), - Status: aws.StringValue(alarm.StateValue), + Arn: awsv2.ToString(alarm.AlarmArn), + Name: awsv2.ToString(alarm.AlarmName), + Condition: awsv2.ToString(alarm.AlarmRule), + Status: string(alarm.StateValue), Type: compositeAlarmType, UpdatedTimes: *alarm.StateUpdatedTimestamp, }) @@ -207,18 +198,15 @@ func (cw *CloudWatch) compositeAlarmsStatus(alarms []*cloudwatch.CompositeAlarm) return alarmStatusList } -func (cw *CloudWatch) metricAlarmsStatus(alarms []*cloudwatch.MetricAlarm) []AlarmStatus { +func (cw *CloudWatch) metricAlarmsStatus(alarms []types.MetricAlarm) []AlarmStatus { var alarmStatusList []AlarmStatus for _, alarm := range alarms { - if alarm == nil { - continue - } - metricAlarm := metricAlarm(*alarm) + metricAlarm := metricAlarm(alarm) alarmStatusList = append(alarmStatusList, AlarmStatus{ - Arn: aws.StringValue(metricAlarm.AlarmArn), - Name: aws.StringValue(metricAlarm.AlarmName), + Arn: awsv2.ToString(metricAlarm.AlarmArn), + Name: awsv2.ToString(metricAlarm.AlarmName), Condition: metricAlarm.condition(), - Status: aws.StringValue(metricAlarm.StateValue), + Status: string(metricAlarm.StateValue), Type: metricAlarmType, UpdatedTimes: *metricAlarm.StateUpdatedTimestamp, }) diff --git a/internal/pkg/aws/cloudwatch/cloudwatch_test.go b/internal/pkg/aws/cloudwatch/cloudwatch_test.go index 96589eec61b..335cb2f33fc 100644 --- a/internal/pkg/aws/cloudwatch/cloudwatch_test.go +++ b/internal/pkg/aws/cloudwatch/cloudwatch_test.go @@ -11,8 +11,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch/mocks" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudwatch" + "github.com/aws/aws-sdk-go-v2/aws" + cwapi "github.com/aws/aws-sdk-go-v2/service/cloudwatch" + cwtypes "github.com/aws/aws-sdk-go-v2/service/cloudwatch/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -64,8 +65,8 @@ func TestCloudWatch_AlarmsWithTags(t *testing.T) { setupMocks: func(m cloudWatchMocks) { gomock.InOrder( m.rg.EXPECT().GetResourcesByTags(cloudwatchResourceType, gomock.Eq(testTags)).Return([]*rg.Resource{{ARN: mockAlarmArn}}, nil), - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice([]string{"mockAlarmName"}), + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: []string{"mockAlarmName"}, }).Return(nil, mockError), ) }, @@ -83,19 +84,19 @@ func TestCloudWatch_AlarmsWithTags(t *testing.T) { setupMocks: func(m cloudWatchMocks) { gomock.InOrder( m.rg.EXPECT().GetResourcesByTags(cloudwatchResourceType, gomock.Eq(testTags)).Return([]*rg.Resource{{ARN: mockAlarmArn}}, nil), - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice([]string{"mockAlarmName"}), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: []string{"mockAlarmName"}, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmArn: aws.String(mockAlarmArn), AlarmName: aws.String("mockAlarmName"), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorGreaterThanOrEqualToThreshold), - EvaluationPeriods: aws.Int64(int64(300)), - Period: aws.Int64(int64(5)), + ComparisonOperator: cwtypes.ComparisonOperatorGreaterThanOrEqualToThreshold, + EvaluationPeriods: aws.Int32(300), + Period: aws.Int32(5), Threshold: aws.Float64(float64(70)), MetricName: aws.String("mockMetricName"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, }, @@ -166,7 +167,7 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { "errors if fail to describe alarms": { in: WithPrefix(mockPrefix), setupMocks: func(m cloudWatchMocks) { - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ AlarmNamePrefix: aws.String(mockPrefix), }).Return(nil, mockError) }, @@ -175,7 +176,7 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { "return if no alarms with prefix found": { in: WithPrefix(mockPrefix), setupMocks: func(m cloudWatchMocks) { - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ AlarmNamePrefix: aws.String(mockPrefix), }).Return(nil, nil) }, @@ -183,19 +184,19 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { "success with prefix": { in: WithPrefix(mockPrefix), setupMocks: func(m cloudWatchMocks) { - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ AlarmNamePrefix: aws.String(mockPrefix), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmArn: aws.String(mockAlarmArn), AlarmName: aws.String(mockName), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorGreaterThanOrEqualToThreshold), - EvaluationPeriods: aws.Int64(int64(300)), - Period: aws.Int64(int64(5)), + ComparisonOperator: cwtypes.ComparisonOperatorGreaterThanOrEqualToThreshold, + EvaluationPeriods: aws.Int32(300), + Period: aws.Int32(5), Threshold: aws.Float64(float64(70)), MetricName: aws.String("mockMetricName"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, }, @@ -216,19 +217,19 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { in: WithNames([]string{mockName}), setupMocks: func(m cloudWatchMocks) { gomock.InOrder( - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice([]string{mockName}), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: []string{mockName}, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmArn: aws.String(mockAlarmArn), AlarmName: aws.String(mockName), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorGreaterThanOrEqualToThreshold), - EvaluationPeriods: aws.Int64(int64(300)), - Period: aws.Int64(int64(5)), + ComparisonOperator: cwtypes.ComparisonOperatorGreaterThanOrEqualToThreshold, + EvaluationPeriods: aws.Int32(300), + Period: aws.Int32(5), Threshold: aws.Float64(float64(70)), MetricName: aws.String("mockMetricName"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, }, @@ -251,20 +252,20 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { in: WithNames([]string{mockName}), setupMocks: func(m cloudWatchMocks) { gomock.InOrder( - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice([]string{mockName}), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: []string{mockName}, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmArn: aws.String(mockArn1), AlarmName: aws.String(mockName), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorLessThanLowerOrGreaterThanUpperThreshold), - Metrics: []*cloudwatch.MetricDataQuery{ + ComparisonOperator: cwtypes.ComparisonOperatorLessThanLowerOrGreaterThanUpperThreshold, + Metrics: []cwtypes.MetricDataQuery{ { Id: aws.String("m1"), - MetricStat: &cloudwatch.MetricStat{ - Period: aws.Int64(120), - Metric: &cloudwatch.Metric{ + MetricStat: &cwtypes.MetricStat{ + Period: aws.Int32(120), + Metric: &cwtypes.Metric{ MetricName: aws.String("mockMetricName"), }, }, @@ -277,7 +278,7 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { }, }, ThresholdMetricId: aws.String("m2"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, }, @@ -300,20 +301,20 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { in: WithNames([]string{mockName}), setupMocks: func(m cloudWatchMocks) { gomock.InOrder( - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice([]string{mockName}), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: []string{mockName}, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmArn: aws.String(mockArn1), AlarmName: aws.String(mockName), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorGreaterThanUpperThreshold), - Metrics: []*cloudwatch.MetricDataQuery{ + ComparisonOperator: cwtypes.ComparisonOperatorGreaterThanUpperThreshold, + Metrics: []cwtypes.MetricDataQuery{ { Id: aws.String("m1"), - MetricStat: &cloudwatch.MetricStat{ - Period: aws.Int64(120), - Metric: &cloudwatch.Metric{ + MetricStat: &cwtypes.MetricStat{ + Period: aws.Int32(120), + Metric: &cwtypes.Metric{ MetricName: aws.String("mockMetricName1"), }, }, @@ -326,19 +327,19 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { }, }, ThresholdMetricId: aws.String("m2"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, { AlarmArn: aws.String(mockArn2), AlarmName: aws.String("mockAlarmName2"), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorGreaterThanThreshold), - Metrics: []*cloudwatch.MetricDataQuery{ + ComparisonOperator: cwtypes.ComparisonOperatorGreaterThanThreshold, + Metrics: []cwtypes.MetricDataQuery{ { Id: aws.String("m1"), - MetricStat: &cloudwatch.MetricStat{ - Period: aws.Int64(120), - Metric: &cloudwatch.Metric{ + MetricStat: &cwtypes.MetricStat{ + Period: aws.Int32(120), + Metric: &cwtypes.Metric{ MetricName: aws.String("mockMetricName2"), }, }, @@ -351,7 +352,7 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { }, }, ThresholdMetricId: aws.String("m2"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, }, @@ -382,39 +383,37 @@ func TestCloudWatch_AlarmStatuses(t *testing.T) { in: WithNames([]string{"mockAlarmName1", "mockAlarmName2"}), setupMocks: func(m cloudWatchMocks) { gomock.InOrder( - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice([]string{"mockAlarmName1", "mockAlarmName2"}), - }).Return(&cloudwatch.DescribeAlarmsOutput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: []string{"mockAlarmName1", "mockAlarmName2"}, + }).Return(&cwapi.DescribeAlarmsOutput{ NextToken: aws.String("mockNextToken"), - CompositeAlarms: []*cloudwatch.CompositeAlarm{ + CompositeAlarms: []cwtypes.CompositeAlarm{ { AlarmArn: aws.String(mockArn1), AlarmName: aws.String("mockAlarmName1"), AlarmRule: aws.String("mockAlarmRule"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, - nil, }, }, nil), - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ NextToken: aws.String("mockNextToken"), - AlarmNames: aws.StringSlice([]string{"mockAlarmName1", "mockAlarmName2"}), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + AlarmNames: []string{"mockAlarmName1", "mockAlarmName2"}, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmArn: aws.String(mockArn2), AlarmName: aws.String("mockAlarmName2"), - ComparisonOperator: aws.String(cloudwatch.ComparisonOperatorLessThanThreshold), - EvaluationPeriods: aws.Int64(int64(60)), - Period: aws.Int64(int64(5)), - DatapointsToAlarm: aws.Int64(int64(3)), + ComparisonOperator: cwtypes.ComparisonOperatorLessThanThreshold, + EvaluationPeriods: aws.Int32(60), + Period: aws.Int32(5), + DatapointsToAlarm: aws.Int32(3), Threshold: aws.Float64(float64(63)), MetricName: aws.String("mockMetricName1"), - StateValue: aws.String("mockState"), + StateValue: cwtypes.StateValue("mockState"), StateUpdatedTimestamp: &mockTime, }, - nil, }, }, nil), ) @@ -487,8 +486,8 @@ func TestCloudWatch_AlarmDescriptions(t *testing.T) { "errors if fail to describe alarms": { in: mockNames, setupMocks: func(m cloudWatchMocks) { - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice(mockNames), + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: mockNames, }).Return(nil, mockError) }, wantedErr: errors.New("describe CloudWatch alarms: some error"), @@ -496,18 +495,18 @@ func TestCloudWatch_AlarmDescriptions(t *testing.T) { "return if no alarms with names": { in: mockNames, setupMocks: func(m cloudWatchMocks) { - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice(mockNames), + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: mockNames, }).Return(nil, nil) }, }, "success": { in: mockNames, setupMocks: func(m cloudWatchMocks) { - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice(mockNames), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: mockNames, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmName: aws.String(name1), AlarmDescription: aws.String(desc1), @@ -536,28 +535,26 @@ func TestCloudWatch_AlarmDescriptions(t *testing.T) { in: mockNames, setupMocks: func(m cloudWatchMocks) { gomock.InOrder( - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ - AlarmNames: aws.StringSlice(mockNames), - }).Return(&cloudwatch.DescribeAlarmsOutput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ + AlarmNames: mockNames, + }).Return(&cwapi.DescribeAlarmsOutput{ NextToken: aws.String("mockNextToken"), - CompositeAlarms: []*cloudwatch.CompositeAlarm{ + CompositeAlarms: []cwtypes.CompositeAlarm{ { AlarmName: aws.String(name1), AlarmDescription: aws.String(desc1), }, - nil, }, }, nil), - m.cw.EXPECT().DescribeAlarms(&cloudwatch.DescribeAlarmsInput{ + m.cw.EXPECT().DescribeAlarms(gomock.Any(), &cwapi.DescribeAlarmsInput{ NextToken: aws.String("mockNextToken"), - AlarmNames: aws.StringSlice(mockNames), - }).Return(&cloudwatch.DescribeAlarmsOutput{ - MetricAlarms: []*cloudwatch.MetricAlarm{ + AlarmNames: mockNames, + }).Return(&cwapi.DescribeAlarmsOutput{ + MetricAlarms: []cwtypes.MetricAlarm{ { AlarmName: aws.String(name2), AlarmDescription: aws.String(desc2), }, - nil, }, }, nil), ) diff --git a/internal/pkg/aws/cloudwatch/mocks/mock_cloudwatch.go b/internal/pkg/aws/cloudwatch/mocks/mock_cloudwatch.go index 69e3d9fc61d..243beecce19 100644 --- a/internal/pkg/aws/cloudwatch/mocks/mock_cloudwatch.go +++ b/internal/pkg/aws/cloudwatch/mocks/mock_cloudwatch.go @@ -5,10 +5,11 @@ package mocks import ( + context "context" reflect "reflect" resourcegroups "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" - cloudwatch "github.com/aws/aws-sdk-go/service/cloudwatch" + cloudwatch "github.com/aws/aws-sdk-go-v2/service/cloudwatch" gomock "github.com/golang/mock/gomock" ) @@ -36,18 +37,23 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeAlarms mocks base method. -func (m *Mockapi) DescribeAlarms(input *cloudwatch.DescribeAlarmsInput) (*cloudwatch.DescribeAlarmsOutput, error) { +func (m *Mockapi) DescribeAlarms(arg0 context.Context, arg1 *cloudwatch.DescribeAlarmsInput, arg2 ...func(*cloudwatch.Options)) (*cloudwatch.DescribeAlarmsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeAlarms", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeAlarms", varargs...) ret0, _ := ret[0].(*cloudwatch.DescribeAlarmsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeAlarms indicates an expected call of DescribeAlarms. -func (mr *MockapiMockRecorder) DescribeAlarms(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeAlarms(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAlarms", reflect.TypeOf((*Mockapi)(nil).DescribeAlarms), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAlarms", reflect.TypeOf((*Mockapi)(nil).DescribeAlarms), varargs...) } // MockresourceGetter is a mock of resourceGetter interface. diff --git a/internal/pkg/aws/ec2/ec2.go b/internal/pkg/aws/ec2/ec2.go index 091237262c0..8b5aeb74913 100644 --- a/internal/pkg/aws/ec2/ec2.go +++ b/internal/pkg/aws/ec2/ec2.go @@ -5,12 +5,13 @@ package ec2 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" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" ) const ( @@ -32,14 +33,14 @@ var ( ) type api interface { - DescribeSubnets(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) - DescribeSecurityGroups(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) - DescribeVpcs(input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) - DescribeVpcAttribute(input *ec2.DescribeVpcAttributeInput) (*ec2.DescribeVpcAttributeOutput, error) - DescribeNetworkInterfaces(input *ec2.DescribeNetworkInterfacesInput) (*ec2.DescribeNetworkInterfacesOutput, error) - DescribeRouteTables(input *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) - DescribeAvailabilityZones(input *ec2.DescribeAvailabilityZonesInput) (*ec2.DescribeAvailabilityZonesOutput, error) - DescribeManagedPrefixLists(input *ec2.DescribeManagedPrefixListsInput) (*ec2.DescribeManagedPrefixListsOutput, error) + DescribeSubnets(ctx context.Context, input *ec2.DescribeSubnetsInput, opts ...func(*ec2.Options)) (*ec2.DescribeSubnetsOutput, error) + DescribeSecurityGroups(ctx context.Context, input *ec2.DescribeSecurityGroupsInput, opts ...func(*ec2.Options)) (*ec2.DescribeSecurityGroupsOutput, error) + DescribeVpcs(ctx context.Context, input *ec2.DescribeVpcsInput, opts ...func(*ec2.Options)) (*ec2.DescribeVpcsOutput, error) + DescribeVpcAttribute(ctx context.Context, input *ec2.DescribeVpcAttributeInput, opts ...func(*ec2.Options)) (*ec2.DescribeVpcAttributeOutput, error) + DescribeNetworkInterfaces(ctx context.Context, input *ec2.DescribeNetworkInterfacesInput, opts ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) + DescribeRouteTables(ctx context.Context, input *ec2.DescribeRouteTablesInput, opts ...func(*ec2.Options)) (*ec2.DescribeRouteTablesOutput, error) + DescribeAvailabilityZones(ctx context.Context, input *ec2.DescribeAvailabilityZonesInput, opts ...func(*ec2.Options)) (*ec2.DescribeAvailabilityZonesOutput, error) + DescribeManagedPrefixLists(ctx context.Context, input *ec2.DescribeManagedPrefixListsInput, opts ...func(*ec2.Options)) (*ec2.DescribeManagedPrefixListsOutput, error) } // Filter contains the name and values of a filter. @@ -67,10 +68,10 @@ type EC2 struct { client api } -// New returns a EC2 configured against the input session. -func New(s *session.Session) *EC2 { +// New returns a EC2 configured against the input config. +func New(cfg awsv2.Config) *EC2 { return &EC2{ - client: ec2.New(s), + client: ec2.NewFromConfig(cfg), } } @@ -148,8 +149,8 @@ func extractResource(label string) (*Resource, error) { // PublicIP returns the public ip associated with the network interface. func (c *EC2) PublicIP(eni string) (string, error) { - response, err := c.client.DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: aws.StringSlice([]string{eni}), + response, err := c.client.DescribeNetworkInterfaces(context.Background(), &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []string{eni}, }) if err != nil { return "", fmt.Errorf("describe network interface with ENI %s: %w", eni, err) @@ -162,20 +163,20 @@ func (c *EC2) PublicIP(eni string) (string, error) { return "", fmt.Errorf("no association information found for ENI %s", eni) } - return aws.StringValue(association.PublicIp), nil + return awsv2.ToString(association.PublicIp), nil } // ListVPCs returns names and IDs (or just IDs, if Name tag does not exist) of all VPCs. func (c *EC2) ListVPCs() ([]VPC, error) { - var ec2vpcs []*ec2.Vpc - response, err := c.client.DescribeVpcs(&ec2.DescribeVpcsInput{}) + var ec2vpcs []types.Vpc + response, err := c.client.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{}) if err != nil { return nil, fmt.Errorf("describe VPCs: %w", err) } ec2vpcs = append(ec2vpcs, response.Vpcs...) for response.NextToken != nil { - response, err = c.client.DescribeVpcs(&ec2.DescribeVpcsInput{ + response, err = c.client.DescribeVpcs(context.Background(), &ec2.DescribeVpcsInput{ NextToken: response.NextToken, }) if err != nil { @@ -187,13 +188,13 @@ func (c *EC2) ListVPCs() ([]VPC, error) { for _, vpc := range ec2vpcs { var name string for _, tag := range vpc.Tags { - if aws.StringValue(tag.Key) == "Name" { - name = aws.StringValue(tag.Value) + if awsv2.ToString(tag.Key) == "Name" { + name = awsv2.ToString(tag.Value) } } vpcs = append(vpcs, VPC{ Resource: Resource{ - ID: aws.StringValue(vpc.VpcId), + ID: awsv2.ToString(vpc.VpcId), Name: name, }, }) @@ -203,15 +204,15 @@ func (c *EC2) ListVPCs() ([]VPC, error) { // ListAZs returns the list of opted-in and available availability zones. func (c *EC2) ListAZs() ([]AZ, error) { - resp, err := c.client.DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{ - Filters: []*ec2.Filter{ + resp, err := c.client.DescribeAvailabilityZones(context.Background(), &ec2.DescribeAvailabilityZonesInput{ + Filters: []types.Filter{ { - Name: aws.String("zone-type"), - Values: aws.StringSlice([]string{"availability-zone"}), + Name: awsv2.String("zone-type"), + Values: []string{"availability-zone"}, }, { - Name: aws.String("state"), - Values: aws.StringSlice([]string{"available"}), + Name: awsv2.String("state"), + Values: []string{"available"}, }, }, }) @@ -221,8 +222,8 @@ func (c *EC2) ListAZs() ([]AZ, error) { var out []AZ for _, az := range resp.AvailabilityZones { out = append(out, AZ{ - ID: aws.StringValue(az.ZoneId), - Name: aws.StringValue(az.ZoneName), + ID: awsv2.ToString(az.ZoneId), + Name: awsv2.ToString(az.ZoneName), }) } return out, nil @@ -230,14 +231,14 @@ func (c *EC2) ListAZs() ([]AZ, error) { // HasDNSSupport returns if DNS resolution is enabled for the VPC. func (c *EC2) HasDNSSupport(vpcID string) (bool, error) { - resp, err := c.client.DescribeVpcAttribute(&ec2.DescribeVpcAttributeInput{ - VpcId: aws.String(vpcID), - Attribute: aws.String(ec2.VpcAttributeNameEnableDnsSupport), + resp, err := c.client.DescribeVpcAttribute(context.Background(), &ec2.DescribeVpcAttributeInput{ + VpcId: awsv2.String(vpcID), + Attribute: types.VpcAttributeNameEnableDnsSupport, }) if err != nil { - return false, fmt.Errorf("describe %s attribute for VPC %s: %w", ec2.VpcAttributeNameEnableDnsSupport, vpcID, err) + return false, fmt.Errorf("describe %s attribute for VPC %s: %w", types.VpcAttributeNameEnableDnsSupport, vpcID, err) } - return aws.BoolValue(resp.EnableDnsSupport.Value), nil + return awsv2.ToBool(resp.EnableDnsSupport.Value), nil } // VPCSubnets are all subnets within a VPC. @@ -268,16 +269,16 @@ func (c *EC2) ListVPCSubnets(vpcID string) (*VPCSubnets, error) { for _, subnet := range respSubnets { var name string for _, tag := range subnet.Tags { - if aws.StringValue(tag.Key) == "Name" { - name = aws.StringValue(tag.Value) + if awsv2.ToString(tag.Key) == "Name" { + name = awsv2.ToString(tag.Value) } } s := Subnet{ Resource: Resource{ - ID: aws.StringValue(subnet.SubnetId), + ID: awsv2.ToString(subnet.SubnetId), Name: name, }, - CIDRBlock: aws.StringValue(subnet.CidrBlock), + CIDRBlock: awsv2.ToString(subnet.CidrBlock), } if rtIndex.IsPublicSubnet(s.ID) { publicSubnets = append(publicSubnets, s) @@ -300,7 +301,7 @@ func (c *EC2) SubnetIDs(filters ...Filter) ([]string, error) { subnetIDs := make([]string, len(subnets)) for idx, subnet := range subnets { - subnetIDs[idx] = aws.StringValue(subnet.SubnetId) + subnetIDs[idx] = awsv2.ToString(subnet.SubnetId) } return subnetIDs, nil } @@ -309,7 +310,7 @@ func (c *EC2) SubnetIDs(filters ...Filter) ([]string, error) { func (c *EC2) SecurityGroups(filters ...Filter) ([]string, error) { inputFilters := toEC2Filter(filters) - response, err := c.client.DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{ + response, err := c.client.DescribeSecurityGroups(context.Background(), &ec2.DescribeSecurityGroupsInput{ Filters: inputFilters, }) @@ -319,15 +320,15 @@ func (c *EC2) SecurityGroups(filters ...Filter) ([]string, error) { securityGroups := make([]string, len(response.SecurityGroups)) for idx, sg := range response.SecurityGroups { - securityGroups[idx] = aws.StringValue(sg.GroupId) + securityGroups[idx] = awsv2.ToString(sg.GroupId) } return securityGroups, nil } -func (c *EC2) subnets(filters ...Filter) ([]*ec2.Subnet, error) { +func (c *EC2) subnets(filters ...Filter) ([]types.Subnet, error) { inputFilters := toEC2Filter(filters) - var subnets []*ec2.Subnet - response, err := c.client.DescribeSubnets(&ec2.DescribeSubnetsInput{ + var subnets []types.Subnet + response, err := c.client.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{ Filters: inputFilters, }) if err != nil { @@ -335,7 +336,7 @@ func (c *EC2) subnets(filters ...Filter) ([]*ec2.Subnet, error) { } subnets = append(subnets, response.Subnets...) for response.NextToken != nil { - response, err = c.client.DescribeSubnets(&ec2.DescribeSubnetsInput{ + response, err = c.client.DescribeSubnets(context.Background(), &ec2.DescribeSubnetsInput{ Filters: inputFilters, NextToken: response.NextToken, }) @@ -350,13 +351,13 @@ func (c *EC2) subnets(filters ...Filter) ([]*ec2.Subnet, error) { return subnets, nil } -func (c *EC2) routeTables(filters ...Filter) ([]*ec2.RouteTable, error) { - var routeTables []*ec2.RouteTable +func (c *EC2) routeTables(filters ...Filter) ([]types.RouteTable, error) { + var routeTables []types.RouteTable input := &ec2.DescribeRouteTablesInput{ Filters: toEC2Filter(filters), } for { - resp, err := c.client.DescribeRouteTables(input) + resp, err := c.client.DescribeRouteTables(context.Background(), input) if err != nil { return nil, fmt.Errorf("describe route tables: %w", err) } @@ -369,24 +370,24 @@ func (c *EC2) routeTables(filters ...Filter) ([]*ec2.RouteTable, error) { return routeTables, nil } -func toEC2Filter(filters []Filter) []*ec2.Filter { - var ec2Filter []*ec2.Filter +func toEC2Filter(filters []Filter) []types.Filter { + var ec2Filter []types.Filter for _, filter := range filters { - ec2Filter = append(ec2Filter, &ec2.Filter{ - Name: aws.String(filter.Name), - Values: aws.StringSlice(filter.Values), + ec2Filter = append(ec2Filter, types.Filter{ + Name: awsv2.String(filter.Name), + Values: filter.Values, }) } return ec2Filter } -type routeTable ec2.RouteTable +type routeTable types.RouteTable // IsMain returns true if the route table is the default route table for the VPC. // If a subnet is not associated with a particular route table, then it will default to the main route table. func (rt *routeTable) IsMain() bool { for _, association := range rt.Associations { - if aws.BoolValue(association.Main) { + if awsv2.ToBool(association.Main) { return true } } @@ -396,7 +397,7 @@ func (rt *routeTable) IsMain() bool { // HasIGW returns true if the route table has a route to an internet gateway. func (rt *routeTable) HasIGW() bool { for _, route := range rt.Routes { - if strings.HasPrefix(aws.StringValue(route.GatewayId), internetGatewayIDPrefix) { + if strings.HasPrefix(awsv2.ToString(route.GatewayId), internetGatewayIDPrefix) { return true } } @@ -410,7 +411,7 @@ func (rt *routeTable) AssociatedSubnets() []string { if association.SubnetId == nil { continue } - subnetIDs = append(subnetIDs, aws.StringValue(association.SubnetId)) + subnetIDs = append(subnetIDs, awsv2.ToString(association.SubnetId)) } return subnetIDs } @@ -424,12 +425,12 @@ type routeTableIndex struct { routeTableForSubnet map[string]*routeTable } -func indexRouteTables(tables []*ec2.RouteTable) *routeTableIndex { +func indexRouteTables(tables []types.RouteTable) *routeTableIndex { index := &routeTableIndex{ routeTableForSubnet: make(map[string]*routeTable), } - for _, table := range tables { // Index all properties in a single pass. - table := (*routeTable)(table) + for i := range tables { // Index all properties in a single pass. + table := (*routeTable)(&tables[i]) for _, subnetID := range table.AssociatedSubnets() { index.routeTableForSubnet[subnetID] = table @@ -455,11 +456,11 @@ func (idx *routeTableIndex) IsPublicSubnet(subnetID string) bool { // managedPrefixList returns the DescribeManagedPrefixListsOutput of a query by name. func (c *EC2) managedPrefixList(prefixListName string) (*ec2.DescribeManagedPrefixListsOutput, error) { - prefixListOutput, err := c.client.DescribeManagedPrefixLists(&ec2.DescribeManagedPrefixListsInput{ - Filters: []*ec2.Filter{ + prefixListOutput, err := c.client.DescribeManagedPrefixLists(context.Background(), &ec2.DescribeManagedPrefixListsInput{ + Filters: []types.Filter{ { - Name: aws.String("prefix-list-name"), - Values: aws.StringSlice([]string{prefixListName}), + Name: awsv2.String("prefix-list-name"), + Values: []string{prefixListName}, }, }, }) diff --git a/internal/pkg/aws/ec2/ec2_test.go b/internal/pkg/aws/ec2/ec2_test.go index f67d60e243b..1c2225746a7 100644 --- a/internal/pkg/aws/ec2/ec2_test.go +++ b/internal/pkg/aws/ec2/ec2_test.go @@ -9,8 +9,9 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/ec2/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -27,17 +28,17 @@ var ( }, } - subnet1 = &ec2.Subnet{ - SubnetId: aws.String("subnet-1"), - MapPublicIpOnLaunch: aws.Bool(false), + subnet1 = types.Subnet{ + SubnetId: awsv2.String("subnet-1"), + MapPublicIpOnLaunch: awsv2.Bool(false), } - subnet2 = &ec2.Subnet{ - SubnetId: aws.String("subnet-2"), - MapPublicIpOnLaunch: aws.Bool(true), + subnet2 = types.Subnet{ + SubnetId: awsv2.String("subnet-2"), + MapPublicIpOnLaunch: awsv2.Bool(true), } - subnet3 = &ec2.Subnet{ - SubnetId: aws.String("subnet-3"), - MapPublicIpOnLaunch: aws.Bool(true), + subnet3 = types.Subnet{ + SubnetId: awsv2.String("subnet-3"), + MapPublicIpOnLaunch: awsv2.Bool(true), } ) @@ -116,30 +117,30 @@ func TestEC2_ListVPC(t *testing.T) { }{ "fail to describe vpcs": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeVpcs(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeVpcs(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("describe VPCs: some error"), }, "success": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeVpcs(&ec2.DescribeVpcsInput{}).Return(&ec2.DescribeVpcsOutput{ - Vpcs: []*ec2.Vpc{ + m.EXPECT().DescribeVpcs(gomock.Any(), &ec2.DescribeVpcsInput{}).Return(&ec2.DescribeVpcsOutput{ + Vpcs: []types.Vpc{ { - VpcId: aws.String("mockVPCID1"), + VpcId: awsv2.String("mockVPCID1"), }, }, - NextToken: aws.String("mockNextToken"), + NextToken: awsv2.String("mockNextToken"), }, nil) - m.EXPECT().DescribeVpcs(&ec2.DescribeVpcsInput{ - NextToken: aws.String("mockNextToken"), + m.EXPECT().DescribeVpcs(gomock.Any(), &ec2.DescribeVpcsInput{ + NextToken: awsv2.String("mockNextToken"), }).Return(&ec2.DescribeVpcsOutput{ - Vpcs: []*ec2.Vpc{ + Vpcs: []types.Vpc{ { - VpcId: aws.String("mockVPCID2"), - Tags: []*ec2.Tag{ + VpcId: awsv2.String("mockVPCID2"), + Tags: []types.Tag{ { - Key: aws.String("Name"), - Value: aws.String("mockVPC2Name"), + Key: awsv2.String("Name"), + Value: awsv2.String("mockVPC2Name"), }, }, }, @@ -193,44 +194,44 @@ func TestEC2_ListAZs(t *testing.T) { }{ "return wrapped error on unexpected call error": { mockClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeAvailabilityZones(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeAvailabilityZones(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) }, wantedErr: "describe availability zones: some error", }, "returns AZs that are available and opted-in": { mockClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeAvailabilityZones(&ec2.DescribeAvailabilityZonesInput{ - Filters: []*ec2.Filter{ + m.EXPECT().DescribeAvailabilityZones(gomock.Any(), &ec2.DescribeAvailabilityZonesInput{ + Filters: []types.Filter{ { - Name: aws.String("zone-type"), - Values: aws.StringSlice([]string{"availability-zone"}), + Name: awsv2.String("zone-type"), + Values: []string{"availability-zone"}, }, { - Name: aws.String("state"), - Values: aws.StringSlice([]string{"available"}), + Name: awsv2.String("state"), + Values: []string{"available"}, }, }, }).Return(&ec2.DescribeAvailabilityZonesOutput{ - AvailabilityZones: []*ec2.AvailabilityZone{ + AvailabilityZones: []types.AvailabilityZone{ { - GroupName: aws.String("us-west-2"), - NetworkBorderGroup: aws.String("us-west-2"), - OptInStatus: aws.String("opt-in-not-required"), - RegionName: aws.String("us-west-2"), - State: aws.String("available"), - ZoneId: aws.String("usw2-az1"), - ZoneName: aws.String("us-west-2a"), - ZoneType: aws.String("availability-zone"), + GroupName: awsv2.String("us-west-2"), + NetworkBorderGroup: awsv2.String("us-west-2"), + OptInStatus: types.AvailabilityZoneOptInStatusOptInNotRequired, + RegionName: awsv2.String("us-west-2"), + State: types.AvailabilityZoneStateAvailable, + ZoneId: awsv2.String("usw2-az1"), + ZoneName: awsv2.String("us-west-2a"), + ZoneType: awsv2.String("availability-zone"), }, { - GroupName: aws.String("us-west-2"), - NetworkBorderGroup: aws.String("us-west-2"), - OptInStatus: aws.String("opt-in-not-required"), - RegionName: aws.String("us-west-2"), - State: aws.String("available"), - ZoneId: aws.String("usw2-az2"), - ZoneName: aws.String("us-west-2b"), - ZoneType: aws.String("availability-zone"), + GroupName: awsv2.String("us-west-2"), + NetworkBorderGroup: awsv2.String("us-west-2"), + OptInStatus: types.AvailabilityZoneOptInStatusOptInNotRequired, + RegionName: awsv2.String("us-west-2"), + State: types.AvailabilityZoneStateAvailable, + ZoneId: awsv2.String("usw2-az2"), + ZoneName: awsv2.String("us-west-2b"), + ZoneType: awsv2.String("availability-zone"), }, }, }, nil) @@ -278,15 +279,15 @@ func TestEC2_managedPrefixList(t *testing.T) { mockNextToken = "mockNextToken" ) mockError := errors.New("some error") - mockFilter := []*ec2.Filter{ + mockFilter := []types.Filter{ { - Name: aws.String("prefix-list-name"), - Values: aws.StringSlice([]string{mockPrefixListName}), + Name: awsv2.String("prefix-list-name"), + Values: []string{mockPrefixListName}, }, } - mockPrefixList := []*ec2.ManagedPrefixList{ + mockPrefixList := []types.ManagedPrefixList{ { - PrefixListId: aws.String(mockPrefixListId), + PrefixListId: awsv2.String(mockPrefixListId), }, } @@ -299,25 +300,25 @@ func TestEC2_managedPrefixList(t *testing.T) { }{ "query returns error": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeManagedPrefixLists(gomock.Any()).Return(nil, mockError) + m.EXPECT().DescribeManagedPrefixLists(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantedError: fmt.Errorf("describe managed prefix list with name %s: %w", mockPrefixListName, mockError), }, "query returns Successfully": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeManagedPrefixLists(&ec2.DescribeManagedPrefixListsInput{ + m.EXPECT().DescribeManagedPrefixLists(gomock.Any(), &ec2.DescribeManagedPrefixListsInput{ Filters: mockFilter, }).Return(&ec2.DescribeManagedPrefixListsOutput{ - NextToken: aws.String(mockNextToken), - PrefixLists: []*ec2.ManagedPrefixList{ + NextToken: awsv2.String(mockNextToken), + PrefixLists: []types.ManagedPrefixList{ { - PrefixListId: aws.String(mockPrefixListId), + PrefixListId: awsv2.String(mockPrefixListId), }, }, }, nil) }, wantedList: &ec2.DescribeManagedPrefixListsOutput{ - NextToken: aws.String(mockNextToken), + NextToken: awsv2.String(mockNextToken), PrefixLists: mockPrefixList, }, }, @@ -356,10 +357,10 @@ func TestEC2_CloudFrontManagedPrefixListId(t *testing.T) { mockNextToken = "mockNextToken" ) mockError := errors.New("some error") - mockFilter := []*ec2.Filter{ + mockFilter := []types.Filter{ { - Name: aws.String("prefix-list-name"), - Values: aws.StringSlice([]string{mockPrefixListName}), + Name: awsv2.String("prefix-list-name"), + Values: []string{mockPrefixListName}, }, } @@ -372,33 +373,33 @@ func TestEC2_CloudFrontManagedPrefixListId(t *testing.T) { }{ "query returns error": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeManagedPrefixLists(gomock.Any()).Return(nil, mockError) + m.EXPECT().DescribeManagedPrefixLists(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantedError: fmt.Errorf("describe managed prefix list with name %s: %w", mockPrefixListName, mockError), }, "query returns no prefix list ids": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeManagedPrefixLists(&ec2.DescribeManagedPrefixListsInput{ + m.EXPECT().DescribeManagedPrefixLists(gomock.Any(), &ec2.DescribeManagedPrefixListsInput{ Filters: mockFilter, }).Return(&ec2.DescribeManagedPrefixListsOutput{ - NextToken: aws.String(mockNextToken), - PrefixLists: []*ec2.ManagedPrefixList{}, + NextToken: awsv2.String(mockNextToken), + PrefixLists: []types.ManagedPrefixList{}, }, nil) }, wantedError: fmt.Errorf("cannot find any prefix list with name: %s", mockPrefixListName), }, "query returns too many prefix list ids": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeManagedPrefixLists(&ec2.DescribeManagedPrefixListsInput{ + m.EXPECT().DescribeManagedPrefixLists(gomock.Any(), &ec2.DescribeManagedPrefixListsInput{ Filters: mockFilter, }).Return(&ec2.DescribeManagedPrefixListsOutput{ - NextToken: aws.String(mockNextToken), - PrefixLists: []*ec2.ManagedPrefixList{ + NextToken: awsv2.String(mockNextToken), + PrefixLists: []types.ManagedPrefixList{ { - PrefixListId: aws.String(mockPrefixListId), + PrefixListId: awsv2.String(mockPrefixListId), }, { - PrefixListId: aws.String(mockPrefixListId), + PrefixListId: awsv2.String(mockPrefixListId), }, }, }, nil) @@ -407,13 +408,13 @@ func TestEC2_CloudFrontManagedPrefixListId(t *testing.T) { }, "query returns Successfully": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeManagedPrefixLists(&ec2.DescribeManagedPrefixListsInput{ + m.EXPECT().DescribeManagedPrefixLists(gomock.Any(), &ec2.DescribeManagedPrefixListsInput{ Filters: mockFilter, }).Return(&ec2.DescribeManagedPrefixListsOutput{ - NextToken: aws.String(mockNextToken), - PrefixLists: []*ec2.ManagedPrefixList{ + NextToken: awsv2.String(mockNextToken), + PrefixLists: []types.ManagedPrefixList{ { - PrefixListId: aws.String(mockPrefixListId), + PrefixListId: awsv2.String(mockPrefixListId), }, }, }, nil) @@ -453,10 +454,10 @@ func TestEC2_ListVPCSubnets(t *testing.T) { mockVPCID = "mockVPC" mockNextToken = "mockNextToken" ) - mockfilter := []*ec2.Filter{ + mockfilter := []types.Filter{ { - Name: aws.String("vpc-id"), - Values: aws.StringSlice([]string{mockVPCID}), + Name: awsv2.String("vpc-id"), + Values: []string{mockVPCID}, }, } mockError := errors.New("some error") @@ -470,83 +471,83 @@ func TestEC2_ListVPCSubnets(t *testing.T) { }{ "fail to describe route tables": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRouteTables(gomock.Any()).Return(nil, mockError) + m.EXPECT().DescribeRouteTables(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantedError: fmt.Errorf("describe route tables: some error"), }, "fail to describe subnets": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRouteTables(&ec2.DescribeRouteTablesInput{ + m.EXPECT().DescribeRouteTables(gomock.Any(), &ec2.DescribeRouteTablesInput{ Filters: mockfilter, }).Return(&ec2.DescribeRouteTablesOutput{}, nil) - m.EXPECT().DescribeSubnets(gomock.Any()).Return(nil, mockError) + m.EXPECT().DescribeSubnets(gomock.Any(), gomock.Any()).Return(nil, mockError) }, wantedError: fmt.Errorf("describe subnets: some error"), }, "can retrieve subnets explicitly associated with an internet gateway": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRouteTables(&ec2.DescribeRouteTablesInput{ + m.EXPECT().DescribeRouteTables(gomock.Any(), &ec2.DescribeRouteTablesInput{ Filters: mockfilter, }).Return(&ec2.DescribeRouteTablesOutput{ - RouteTables: []*ec2.RouteTable{ + RouteTables: []types.RouteTable{ { - Associations: []*ec2.RouteTableAssociation{ + Associations: []types.RouteTableAssociation{ { - SubnetId: aws.String("subnet1"), + SubnetId: awsv2.String("subnet1"), }, }, - Routes: []*ec2.Route{ + Routes: []types.Route{ { - GatewayId: aws.String("local"), + GatewayId: awsv2.String("local"), }, }, }, }, - NextToken: aws.String(mockNextToken), + NextToken: awsv2.String(mockNextToken), }, nil) - m.EXPECT().DescribeRouteTables(&ec2.DescribeRouteTablesInput{ + m.EXPECT().DescribeRouteTables(gomock.Any(), &ec2.DescribeRouteTablesInput{ Filters: mockfilter, - NextToken: aws.String(mockNextToken), + NextToken: awsv2.String(mockNextToken), }).Return(&ec2.DescribeRouteTablesOutput{ - RouteTables: []*ec2.RouteTable{ + RouteTables: []types.RouteTable{ { - Associations: []*ec2.RouteTableAssociation{ + Associations: []types.RouteTableAssociation{ { - SubnetId: aws.String("subnet2"), + SubnetId: awsv2.String("subnet2"), }, { - SubnetId: aws.String("subnet3"), + SubnetId: awsv2.String("subnet3"), }, }, - Routes: []*ec2.Route{ + Routes: []types.Route{ { - GatewayId: aws.String("igw-0333791c413f9e2d8"), + GatewayId: awsv2.String("igw-0333791c413f9e2d8"), }, }, }, }, }, nil) - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: mockfilter, }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{ + Subnets: []types.Subnet{ { - SubnetId: aws.String("subnet1"), - CidrBlock: aws.String("10.0.0.0/24"), + SubnetId: awsv2.String("subnet1"), + CidrBlock: awsv2.String("10.0.0.0/24"), }, { - SubnetId: aws.String("subnet2"), - CidrBlock: aws.String("10.0.1.0/24"), + SubnetId: awsv2.String("subnet2"), + CidrBlock: awsv2.String("10.0.1.0/24"), }, { - SubnetId: aws.String("subnet3"), - Tags: []*ec2.Tag{ + SubnetId: awsv2.String("subnet3"), + Tags: []types.Tag{ { - Key: aws.String("Name"), - Value: aws.String("mySubnet"), + Key: awsv2.String("Name"), + Value: awsv2.String("mySubnet"), }, }, - CidrBlock: aws.String("10.0.2.0/24"), + CidrBlock: awsv2.String("10.0.2.0/24"), }, }, }, nil) @@ -577,45 +578,45 @@ func TestEC2_ListVPCSubnets(t *testing.T) { }, "can retrieve subnets that are implicitly associated with an internet gateway": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRouteTables(&ec2.DescribeRouteTablesInput{ + m.EXPECT().DescribeRouteTables(gomock.Any(), &ec2.DescribeRouteTablesInput{ Filters: mockfilter, }).Return(&ec2.DescribeRouteTablesOutput{ - RouteTables: []*ec2.RouteTable{ + RouteTables: []types.RouteTable{ { - Associations: []*ec2.RouteTableAssociation{ + Associations: []types.RouteTableAssociation{ { - Main: aws.Bool(true), + Main: awsv2.Bool(true), }, }, - Routes: []*ec2.Route{ + Routes: []types.Route{ { - GatewayId: aws.String("local"), - DestinationCidrBlock: aws.String("172.31.0.0/16"), + GatewayId: awsv2.String("local"), + DestinationCidrBlock: awsv2.String("172.31.0.0/16"), }, { - GatewayId: aws.String("igw-3542f24c"), - DestinationCidrBlock: aws.String("0.0.0.0/0"), + GatewayId: awsv2.String("igw-3542f24c"), + DestinationCidrBlock: awsv2.String("0.0.0.0/0"), }, }, }, }, }, nil) - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: mockfilter, }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{ + Subnets: []types.Subnet{ { - SubnetId: aws.String("subnet1"), - CidrBlock: aws.String("172.31.16.0/20"), + SubnetId: awsv2.String("subnet1"), + CidrBlock: awsv2.String("172.31.16.0/20"), }, { - SubnetId: aws.String("subnet2"), - CidrBlock: aws.String("172.31.48.0/20"), + SubnetId: awsv2.String("subnet2"), + CidrBlock: awsv2.String("172.31.48.0/20"), }, { - SubnetId: aws.String("subnet3"), - CidrBlock: aws.String("172.31.32.0/20"), + SubnetId: awsv2.String("subnet3"), + CidrBlock: awsv2.String("172.31.32.0/20"), }, }, }, nil) @@ -644,55 +645,55 @@ func TestEC2_ListVPCSubnets(t *testing.T) { }, "prioritizes explicit route table association over implicit while detecting public subnets": { mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeRouteTables(&ec2.DescribeRouteTablesInput{ + m.EXPECT().DescribeRouteTables(gomock.Any(), &ec2.DescribeRouteTablesInput{ Filters: mockfilter, }).Return(&ec2.DescribeRouteTablesOutput{ - RouteTables: []*ec2.RouteTable{ + RouteTables: []types.RouteTable{ { - Associations: []*ec2.RouteTableAssociation{ + Associations: []types.RouteTableAssociation{ { - Main: aws.Bool(false), - SubnetId: aws.String("subnet1"), + Main: awsv2.Bool(false), + SubnetId: awsv2.String("subnet1"), }, }, - Routes: []*ec2.Route{ + Routes: []types.Route{ { - GatewayId: aws.String("local"), - DestinationCidrBlock: aws.String("172.31.0.0/16"), + GatewayId: awsv2.String("local"), + DestinationCidrBlock: awsv2.String("172.31.0.0/16"), }, }, }, { - Associations: []*ec2.RouteTableAssociation{ + Associations: []types.RouteTableAssociation{ { - Main: aws.Bool(true), + Main: awsv2.Bool(true), }, }, - Routes: []*ec2.Route{ + Routes: []types.Route{ { - GatewayId: aws.String("local"), - DestinationCidrBlock: aws.String("172.31.0.0/16"), + GatewayId: awsv2.String("local"), + DestinationCidrBlock: awsv2.String("172.31.0.0/16"), }, { - GatewayId: aws.String("igw-3542f24c"), - DestinationCidrBlock: aws.String("0.0.0.0/0"), + GatewayId: awsv2.String("igw-3542f24c"), + DestinationCidrBlock: awsv2.String("0.0.0.0/0"), }, }, }, }, }, nil) - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: mockfilter, }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{ + Subnets: []types.Subnet{ { - SubnetId: aws.String("subnet1"), - CidrBlock: aws.String("172.31.16.0/20"), + SubnetId: awsv2.String("subnet1"), + CidrBlock: awsv2.String("172.31.16.0/20"), }, { - SubnetId: aws.String("subnet2"), - CidrBlock: aws.String("172.31.48.0/20"), + SubnetId: awsv2.String("subnet2"), + CidrBlock: awsv2.String("172.31.48.0/20"), }, }, }, nil) @@ -750,8 +751,8 @@ func TestEC2_PublicIP(t *testing.T) { "failed to describe network interfaces": { inENI: "eni-1", mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: aws.StringSlice([]string{"eni-1"}), + m.EXPECT().DescribeNetworkInterfaces(gomock.Any(), &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []string{"eni-1"}, }).Return(nil, errors.New("some error")) }, wantedErr: errors.New("describe network interface with ENI eni-1: some error"), @@ -759,10 +760,10 @@ func TestEC2_PublicIP(t *testing.T) { "no association information found": { inENI: "eni-1", mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: aws.StringSlice([]string{"eni-1"}), + m.EXPECT().DescribeNetworkInterfaces(gomock.Any(), &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []string{"eni-1"}, }).Return(&ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []types.NetworkInterface{ {}, }, }, nil) @@ -772,13 +773,13 @@ func TestEC2_PublicIP(t *testing.T) { "successfully get public ip": { inENI: "eni-1", mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeNetworkInterfaces(&ec2.DescribeNetworkInterfacesInput{ - NetworkInterfaceIds: aws.StringSlice([]string{"eni-1"}), + m.EXPECT().DescribeNetworkInterfaces(gomock.Any(), &ec2.DescribeNetworkInterfacesInput{ + NetworkInterfaceIds: []string{"eni-1"}, }).Return(&ec2.DescribeNetworkInterfacesOutput{ - NetworkInterfaces: []*ec2.NetworkInterface{ + NetworkInterfaces: []types.NetworkInterface{ { - Association: &ec2.NetworkInterfaceAssociation{ - PublicIp: aws.String("1.2.3"), + Association: &types.NetworkInterfaceAssociation{ + PublicIp: awsv2.String("1.2.3"), }, }, }, @@ -810,7 +811,7 @@ func TestEC2_PublicIP(t *testing.T) { } func TestEC2_SubnetIDs(t *testing.T) { - mockNextToken := aws.String("mockNextToken") + mockNextToken := awsv2.String("mockNextToken") testCases := map[string]struct { inFilter []Filter @@ -822,7 +823,7 @@ func TestEC2_SubnetIDs(t *testing.T) { "failed to get subnets": { inFilter: inAppEnvFilters, mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: toEC2Filter(inAppEnvFilters), }).Return(nil, errors.New("error describing subnets")) }, @@ -831,10 +832,10 @@ func TestEC2_SubnetIDs(t *testing.T) { "cannot get any subnets": { inFilter: inAppEnvFilters, mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: toEC2Filter(inAppEnvFilters), }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{}, + Subnets: []types.Subnet{}, }, nil) }, wantedError: fmt.Errorf("cannot find any subnets"), @@ -842,10 +843,10 @@ func TestEC2_SubnetIDs(t *testing.T) { "successfully get subnets": { inFilter: inAppEnvFilters, mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: toEC2Filter(inAppEnvFilters), }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{ + Subnets: []types.Subnet{ subnet1, subnet2, }, }, nil) @@ -855,19 +856,19 @@ func TestEC2_SubnetIDs(t *testing.T) { "successfully get subnets with pagination": { inFilter: inAppEnvFilters, mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: toEC2Filter(inAppEnvFilters), }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{ + Subnets: []types.Subnet{ subnet1, subnet2, }, NextToken: mockNextToken, }, nil) - m.EXPECT().DescribeSubnets(&ec2.DescribeSubnetsInput{ + m.EXPECT().DescribeSubnets(gomock.Any(), &ec2.DescribeSubnetsInput{ Filters: toEC2Filter(inAppEnvFilters), NextToken: mockNextToken, }).Return(&ec2.DescribeSubnetsOutput{ - Subnets: []*ec2.Subnet{ + Subnets: []types.Subnet{ subnet3, }, }, nil) @@ -910,7 +911,7 @@ func TestEC2_SecurityGroups(t *testing.T) { "failed to get security groups": { inFilter: inAppEnvFilters, mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{ + m.EXPECT().DescribeSecurityGroups(gomock.Any(), &ec2.DescribeSecurityGroupsInput{ Filters: toEC2Filter(inAppEnvFilters), }).Return(nil, errors.New("error getting security groups")) }, @@ -920,15 +921,15 @@ func TestEC2_SecurityGroups(t *testing.T) { "get security groups success": { inFilter: inAppEnvFilters, mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeSecurityGroups(&ec2.DescribeSecurityGroupsInput{ + m.EXPECT().DescribeSecurityGroups(gomock.Any(), &ec2.DescribeSecurityGroupsInput{ Filters: toEC2Filter(inAppEnvFilters), }).Return(&ec2.DescribeSecurityGroupsOutput{ - SecurityGroups: []*ec2.SecurityGroup{ + SecurityGroups: []types.SecurityGroup{ { - GroupId: aws.String("sg-1"), + GroupId: awsv2.String("sg-1"), }, { - GroupId: aws.String("sg-2"), + GroupId: awsv2.String("sg-2"), }, }, }, nil) @@ -971,19 +972,19 @@ func TestEC2_HasDNSSupport(t *testing.T) { "fail to descibe VPC attribute": { vpcID: "mockVPCID", mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeVpcAttribute(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeVpcAttribute(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("describe enableDnsSupport attribute for VPC mockVPCID: some error"), }, "success": { vpcID: "mockVPCID", mockEC2Client: func(m *mocks.Mockapi) { - m.EXPECT().DescribeVpcAttribute(&ec2.DescribeVpcAttributeInput{ - VpcId: aws.String("mockVPCID"), - Attribute: aws.String(ec2.VpcAttributeNameEnableDnsSupport), + m.EXPECT().DescribeVpcAttribute(gomock.Any(), &ec2.DescribeVpcAttributeInput{ + VpcId: awsv2.String("mockVPCID"), + Attribute: types.VpcAttributeNameEnableDnsSupport, }).Return(&ec2.DescribeVpcAttributeOutput{ - EnableDnsSupport: &ec2.AttributeBooleanValue{ - Value: aws.Bool(true), + EnableDnsSupport: &types.AttributeBooleanValue{ + Value: awsv2.Bool(true), }, }, nil) }, diff --git a/internal/pkg/aws/ec2/mocks/mock_ec2.go b/internal/pkg/aws/ec2/mocks/mock_ec2.go index 34963dc66cb..20f04ace4f9 100644 --- a/internal/pkg/aws/ec2/mocks/mock_ec2.go +++ b/internal/pkg/aws/ec2/mocks/mock_ec2.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - 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" ) @@ -35,121 +36,161 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeAvailabilityZones mocks base method. -func (m *Mockapi) DescribeAvailabilityZones(input *ec2.DescribeAvailabilityZonesInput) (*ec2.DescribeAvailabilityZonesOutput, error) { +func (m *Mockapi) DescribeAvailabilityZones(ctx context.Context, input *ec2.DescribeAvailabilityZonesInput, opts ...func(*ec2.Options)) (*ec2.DescribeAvailabilityZonesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeAvailabilityZones", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeAvailabilityZones", varargs...) ret0, _ := ret[0].(*ec2.DescribeAvailabilityZonesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeAvailabilityZones indicates an expected call of DescribeAvailabilityZones. -func (mr *MockapiMockRecorder) DescribeAvailabilityZones(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeAvailabilityZones(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAvailabilityZones", reflect.TypeOf((*Mockapi)(nil).DescribeAvailabilityZones), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAvailabilityZones", reflect.TypeOf((*Mockapi)(nil).DescribeAvailabilityZones), varargs...) } // DescribeManagedPrefixLists mocks base method. -func (m *Mockapi) DescribeManagedPrefixLists(input *ec2.DescribeManagedPrefixListsInput) (*ec2.DescribeManagedPrefixListsOutput, error) { +func (m *Mockapi) DescribeManagedPrefixLists(ctx context.Context, input *ec2.DescribeManagedPrefixListsInput, opts ...func(*ec2.Options)) (*ec2.DescribeManagedPrefixListsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeManagedPrefixLists", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeManagedPrefixLists", varargs...) ret0, _ := ret[0].(*ec2.DescribeManagedPrefixListsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeManagedPrefixLists indicates an expected call of DescribeManagedPrefixLists. -func (mr *MockapiMockRecorder) DescribeManagedPrefixLists(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeManagedPrefixLists(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeManagedPrefixLists", reflect.TypeOf((*Mockapi)(nil).DescribeManagedPrefixLists), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeManagedPrefixLists", reflect.TypeOf((*Mockapi)(nil).DescribeManagedPrefixLists), varargs...) } // DescribeNetworkInterfaces mocks base method. -func (m *Mockapi) DescribeNetworkInterfaces(input *ec2.DescribeNetworkInterfacesInput) (*ec2.DescribeNetworkInterfacesOutput, error) { +func (m *Mockapi) DescribeNetworkInterfaces(ctx context.Context, input *ec2.DescribeNetworkInterfacesInput, opts ...func(*ec2.Options)) (*ec2.DescribeNetworkInterfacesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeNetworkInterfaces", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeNetworkInterfaces", varargs...) ret0, _ := ret[0].(*ec2.DescribeNetworkInterfacesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeNetworkInterfaces indicates an expected call of DescribeNetworkInterfaces. -func (mr *MockapiMockRecorder) DescribeNetworkInterfaces(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeNetworkInterfaces(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNetworkInterfaces", reflect.TypeOf((*Mockapi)(nil).DescribeNetworkInterfaces), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeNetworkInterfaces", reflect.TypeOf((*Mockapi)(nil).DescribeNetworkInterfaces), varargs...) } // DescribeRouteTables mocks base method. -func (m *Mockapi) DescribeRouteTables(input *ec2.DescribeRouteTablesInput) (*ec2.DescribeRouteTablesOutput, error) { +func (m *Mockapi) DescribeRouteTables(ctx context.Context, input *ec2.DescribeRouteTablesInput, opts ...func(*ec2.Options)) (*ec2.DescribeRouteTablesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeRouteTables", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeRouteTables", varargs...) ret0, _ := ret[0].(*ec2.DescribeRouteTablesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeRouteTables indicates an expected call of DescribeRouteTables. -func (mr *MockapiMockRecorder) DescribeRouteTables(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeRouteTables(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRouteTables", reflect.TypeOf((*Mockapi)(nil).DescribeRouteTables), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRouteTables", reflect.TypeOf((*Mockapi)(nil).DescribeRouteTables), varargs...) } // DescribeSecurityGroups mocks base method. -func (m *Mockapi) DescribeSecurityGroups(arg0 *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { +func (m *Mockapi) DescribeSecurityGroups(ctx context.Context, input *ec2.DescribeSecurityGroupsInput, opts ...func(*ec2.Options)) (*ec2.DescribeSecurityGroupsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeSecurityGroups", arg0) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeSecurityGroups", varargs...) ret0, _ := ret[0].(*ec2.DescribeSecurityGroupsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeSecurityGroups indicates an expected call of DescribeSecurityGroups. -func (mr *MockapiMockRecorder) DescribeSecurityGroups(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeSecurityGroups(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSecurityGroups", reflect.TypeOf((*Mockapi)(nil).DescribeSecurityGroups), arg0) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSecurityGroups", reflect.TypeOf((*Mockapi)(nil).DescribeSecurityGroups), varargs...) } // DescribeSubnets mocks base method. -func (m *Mockapi) DescribeSubnets(arg0 *ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error) { +func (m *Mockapi) DescribeSubnets(ctx context.Context, input *ec2.DescribeSubnetsInput, opts ...func(*ec2.Options)) (*ec2.DescribeSubnetsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeSubnets", arg0) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeSubnets", varargs...) ret0, _ := ret[0].(*ec2.DescribeSubnetsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeSubnets indicates an expected call of DescribeSubnets. -func (mr *MockapiMockRecorder) DescribeSubnets(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeSubnets(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSubnets", reflect.TypeOf((*Mockapi)(nil).DescribeSubnets), arg0) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSubnets", reflect.TypeOf((*Mockapi)(nil).DescribeSubnets), varargs...) } // DescribeVpcAttribute mocks base method. -func (m *Mockapi) DescribeVpcAttribute(input *ec2.DescribeVpcAttributeInput) (*ec2.DescribeVpcAttributeOutput, error) { +func (m *Mockapi) DescribeVpcAttribute(ctx context.Context, input *ec2.DescribeVpcAttributeInput, opts ...func(*ec2.Options)) (*ec2.DescribeVpcAttributeOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeVpcAttribute", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeVpcAttribute", varargs...) ret0, _ := ret[0].(*ec2.DescribeVpcAttributeOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeVpcAttribute indicates an expected call of DescribeVpcAttribute. -func (mr *MockapiMockRecorder) DescribeVpcAttribute(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeVpcAttribute(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeVpcAttribute", reflect.TypeOf((*Mockapi)(nil).DescribeVpcAttribute), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeVpcAttribute", reflect.TypeOf((*Mockapi)(nil).DescribeVpcAttribute), varargs...) } // DescribeVpcs mocks base method. -func (m *Mockapi) DescribeVpcs(input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) { +func (m *Mockapi) DescribeVpcs(ctx context.Context, input *ec2.DescribeVpcsInput, opts ...func(*ec2.Options)) (*ec2.DescribeVpcsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeVpcs", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeVpcs", varargs...) ret0, _ := ret[0].(*ec2.DescribeVpcsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeVpcs indicates an expected call of DescribeVpcs. -func (mr *MockapiMockRecorder) DescribeVpcs(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeVpcs(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeVpcs", reflect.TypeOf((*Mockapi)(nil).DescribeVpcs), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeVpcs", reflect.TypeOf((*Mockapi)(nil).DescribeVpcs), varargs...) } diff --git a/internal/pkg/aws/ecs/ecs.go b/internal/pkg/aws/ecs/ecs.go index eb2fdbc301f..a9f8b2bb19e 100644 --- a/internal/pkg/aws/ecs/ecs.go +++ b/internal/pkg/aws/ecs/ecs.go @@ -5,17 +5,16 @@ package ecs import ( + "context" "errors" "fmt" + "strings" "time" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aproint/copilot-cli/internal/pkg/exec" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" ) const ( @@ -25,25 +24,33 @@ const ( stableServiceDeploymentNum = 1 // EndpointsID is the ID to look up the ECS service endpoint. - EndpointsID = ecs.EndpointsID + EndpointsID = "ecs" ) type api interface { - DescribeClusters(input *ecs.DescribeClustersInput) (*ecs.DescribeClustersOutput, error) - DescribeServices(input *ecs.DescribeServicesInput) (*ecs.DescribeServicesOutput, error) - DescribeTasks(input *ecs.DescribeTasksInput) (*ecs.DescribeTasksOutput, error) - DescribeTaskDefinition(input *ecs.DescribeTaskDefinitionInput) (*ecs.DescribeTaskDefinitionOutput, error) - ExecuteCommand(input *ecs.ExecuteCommandInput) (*ecs.ExecuteCommandOutput, error) - ListTasks(input *ecs.ListTasksInput) (*ecs.ListTasksOutput, error) - RunTask(input *ecs.RunTaskInput) (*ecs.RunTaskOutput, error) - StopTask(input *ecs.StopTaskInput) (*ecs.StopTaskOutput, error) - UpdateService(input *ecs.UpdateServiceInput) (*ecs.UpdateServiceOutput, error) - WaitUntilTasksRunning(input *ecs.DescribeTasksInput) error - ListServicesByNamespacePages(input *ecs.ListServicesByNamespaceInput, fn func(*ecs.ListServicesByNamespaceOutput, bool) bool) error + DescribeClusters(ctx context.Context, input *ecs.DescribeClustersInput, opts ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error) + DescribeServices(ctx context.Context, input *ecs.DescribeServicesInput, opts ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error) + DescribeTasks(ctx context.Context, input *ecs.DescribeTasksInput, opts ...func(*ecs.Options)) (*ecs.DescribeTasksOutput, error) + DescribeTaskDefinition(ctx context.Context, input *ecs.DescribeTaskDefinitionInput, opts ...func(*ecs.Options)) (*ecs.DescribeTaskDefinitionOutput, error) + ExecuteCommand(ctx context.Context, input *ecs.ExecuteCommandInput, opts ...func(*ecs.Options)) (*ecs.ExecuteCommandOutput, error) + ListServicesByNamespace(ctx context.Context, input *ecs.ListServicesByNamespaceInput, opts ...func(*ecs.Options)) (*ecs.ListServicesByNamespaceOutput, error) + ListTasks(ctx context.Context, input *ecs.ListTasksInput, opts ...func(*ecs.Options)) (*ecs.ListTasksOutput, error) + RunTask(ctx context.Context, input *ecs.RunTaskInput, opts ...func(*ecs.Options)) (*ecs.RunTaskOutput, error) + StopTask(ctx context.Context, input *ecs.StopTaskInput, opts ...func(*ecs.Options)) (*ecs.StopTaskOutput, error) + UpdateService(ctx context.Context, input *ecs.UpdateServiceInput, opts ...func(*ecs.Options)) (*ecs.UpdateServiceOutput, error) + WaitUntilTasksRunning(ctx context.Context, input *ecs.DescribeTasksInput, maxWaitDur time.Duration, opts ...func(*ecs.TasksRunningWaiterOptions)) error } type ssmSessionStarter interface { - StartSession(ssmSession *ecs.Session) error + StartSession(ssmSession *types.Session) error +} + +type clientWithWaiter struct { + *ecs.Client +} + +func (c clientWithWaiter) WaitUntilTasksRunning(ctx context.Context, input *ecs.DescribeTasksInput, maxWaitDur time.Duration, opts ...func(*ecs.TasksRunningWaiterOptions)) error { + return ecs.NewTasksRunningWaiter(c.Client).Wait(ctx, input, maxWaitDur, opts...) } // ECS wraps an AWS ECS client. @@ -75,12 +82,13 @@ type ExecuteCommandInput struct { Container string } -// New returns a Service configured against the input session. -func New(s *session.Session) *ECS { +// New returns a Service configured against the input config. +func New(cfg awsv2.Config) *ECS { + client := ecs.NewFromConfig(cfg) return &ECS{ - client: ecs.New(s), + client: clientWithWaiter{Client: client}, newSessStarter: func() ssmSessionStarter { - return exec.NewSSMPluginCommand(s) + return exec.NewSSMPluginCommand(cfg.Region) }, maxServiceStableTries: waitServiceStableMaxTry, pollIntervalDuration: waitServiceStablePollingInterval, @@ -89,8 +97,8 @@ func New(s *session.Session) *ECS { // TaskDefinition calls ECS API and returns the task definition. func (e *ECS) TaskDefinition(taskDefName string) (*TaskDefinition, error) { - resp, err := e.client.DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{ - TaskDefinition: aws.String(taskDefName), + resp, err := e.client.DescribeTaskDefinition(context.Background(), &ecs.DescribeTaskDefinitionInput{ + TaskDefinition: awsv2.String(taskDefName), }) if err != nil { return nil, fmt.Errorf("describe task definition %s: %w", taskDefName, err) @@ -105,7 +113,7 @@ func (e *ECS) Service(clusterName, serviceName string) (*Service, error) { if err != nil { return nil, err } - if aws.StringValue(svcs[0].ServiceName) != serviceName { + if awsv2.ToString(svcs[0].ServiceName) != serviceName { return nil, fmt.Errorf("cannot find service %s", serviceName) } @@ -119,21 +127,21 @@ func (e *ECS) Services(cluster string, services ...string) ([]*Service, error) { for i := 0; i < len(services); i += 10 { split := services[i:min(10+i, len(services))] - resp, err := e.client.DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(cluster), - Services: aws.StringSlice(split), + resp, err := e.client.DescribeServices(context.Background(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(cluster), + Services: split, }) switch { case err != nil: return nil, fmt.Errorf("describe services: %w", err) case len(resp.Failures) > 0: - return nil, fmt.Errorf("describe services: %s", resp.Failures[0].String()) + return nil, fmt.Errorf("describe services: %s", failureString(resp.Failures[0])) case len(resp.Services) != len(split): return nil, fmt.Errorf("describe services: got %v services, but expected %v", len(resp.Services), len(split)) } for j := range resp.Services { - svc := Service(*resp.Services[j]) + svc := Service(resp.Services[j]) svcs = append(svcs, &svc) } } @@ -145,14 +153,19 @@ func (e *ECS) Services(cluster string, services ...string) ([]*Service, error) { // are in the given namespace. func (e *ECS) ListServicesByNamespace(namespace string) ([]string, error) { var arns []string - err := e.client.ListServicesByNamespacePages(&ecs.ListServicesByNamespaceInput{ - Namespace: aws.String(namespace), - }, func(resp *ecs.ListServicesByNamespaceOutput, b bool) bool { - arns = append(arns, aws.StringValueSlice(resp.ServiceArns)...) - return true - }) - if err != nil { - return nil, err + in := &ecs.ListServicesByNamespaceInput{ + Namespace: awsv2.String(namespace), + } + for { + resp, err := e.client.ListServicesByNamespace(context.Background(), in) + if err != nil { + return nil, err + } + arns = append(arns, resp.ServiceArns...) + if resp.NextToken == nil { + break + } + in.NextToken = resp.NextToken } return arns, nil } @@ -163,20 +176,20 @@ type UpdateServiceOpts func(*ecs.UpdateServiceInput) // WithForceUpdate sets ForceNewDeployment to force an update. func WithForceUpdate() UpdateServiceOpts { return func(in *ecs.UpdateServiceInput) { - in.ForceNewDeployment = aws.Bool(true) + in.ForceNewDeployment = true } } // UpdateService calls ECS API and updates the specific service running in the cluster. func (e *ECS) UpdateService(clusterName, serviceName string, opts ...UpdateServiceOpts) error { in := &ecs.UpdateServiceInput{ - Cluster: aws.String(clusterName), - Service: aws.String(serviceName), + Cluster: awsv2.String(clusterName), + Service: awsv2.String(serviceName), } for _, opt := range opts { opt(in) } - svc, err := e.client.UpdateService(in) + svc, err := e.client.UpdateService(context.Background(), in) if err != nil { return fmt.Errorf("update service %s from cluster %s: %w", serviceName, clusterName, err) } @@ -194,7 +207,7 @@ func (e *ECS) waitUntilServiceStable(svc *Service) error { var tryNum int for { if len(svc.Deployments) == stableServiceDeploymentNum && - aws.Int64Value(svc.DesiredCount) == aws.Int64Value(svc.RunningCount) { + svc.DesiredCount == svc.RunningCount { // This conditional is sufficient to determine that the service is stable AND has successfully updated (hence not rolled-back). // The stable service cannot be a rolled-back service because a rollback can only be triggered by circuit breaker after ~1hr, // by which time we would have already timed out. @@ -205,7 +218,7 @@ func (e *ECS) waitUntilServiceStable(svc *Service) error { maxRetries: e.maxServiceStableTries, } } - svc, err = e.Service(aws.StringValue(svc.ClusterArn), aws.StringValue(svc.ServiceName)) + svc, err = e.Service(awsv2.ToString(svc.ClusterArn), awsv2.ToString(svc.ServiceName)) if err != nil { return err } @@ -239,54 +252,54 @@ type listTasksOpts func(*ecs.ListTasksInput) func withService(svcName string) listTasksOpts { return func(in *ecs.ListTasksInput) { - in.ServiceName = aws.String(svcName) + in.ServiceName = awsv2.String(svcName) } } func withFamily(family string) listTasksOpts { return func(in *ecs.ListTasksInput) { - in.Family = aws.String(family) + in.Family = awsv2.String(family) } } func withRunningTasks() listTasksOpts { return func(in *ecs.ListTasksInput) { - in.DesiredStatus = aws.String(ecs.DesiredStatusRunning) + in.DesiredStatus = types.DesiredStatusRunning } } func withStoppedTasks() listTasksOpts { return func(in *ecs.ListTasksInput) { - in.DesiredStatus = aws.String(ecs.DesiredStatusStopped) + in.DesiredStatus = types.DesiredStatusStopped } } func (e *ECS) listTasks(cluster string, opts ...listTasksOpts) ([]*Task, error) { var tasks []*Task in := &ecs.ListTasksInput{ - Cluster: aws.String(cluster), + Cluster: awsv2.String(cluster), } for _, opt := range opts { opt(in) } for { - listTaskResp, err := e.client.ListTasks(in) + listTaskResp, err := e.client.ListTasks(context.Background(), in) if err != nil { return nil, fmt.Errorf("list running tasks: %w", err) } if len(listTaskResp.TaskArns) == 0 { return tasks, nil } - descTaskResp, err := e.client.DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String(cluster), + descTaskResp, err := e.client.DescribeTasks(context.Background(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String(cluster), Tasks: listTaskResp.TaskArns, - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + Include: []types.TaskField{types.TaskFieldTags}, }) if err != nil { return nil, fmt.Errorf("describe running tasks in cluster %s: %w", cluster, err) } for _, task := range descTaskResp.Tasks { - t := Task(*task) + t := Task(task) tasks = append(tasks, &t) } if listTaskResp.NextToken == nil { @@ -303,14 +316,14 @@ type StopTasksOpts func(*ecs.StopTaskInput) // WithStopTaskReason sets an optional message specified when a task is stopped. func WithStopTaskReason(reason string) StopTasksOpts { return func(in *ecs.StopTaskInput) { - in.Reason = aws.String(reason) + in.Reason = awsv2.String(reason) } } // WithStopTaskCluster sets the cluster that hosts the task to stop. func WithStopTaskCluster(cluster string) StopTasksOpts { return func(in *ecs.StopTaskInput) { - in.Cluster = aws.String(cluster) + in.Cluster = awsv2.String(cluster) } } @@ -321,8 +334,8 @@ func (e *ECS) StopTasks(tasks []string, opts ...StopTasksOpts) error { opt(in) } for _, task := range tasks { - in.Task = aws.String(task) - if _, err := e.client.StopTask(in); err != nil { + in.Task = awsv2.String(task) + if _, err := e.client.StopTask(context.Background(), in); err != nil { return fmt.Errorf("stop task %s: %w", task, err) } } @@ -331,7 +344,7 @@ func (e *ECS) StopTasks(tasks []string, opts ...StopTasksOpts) error { // DefaultCluster returns the default cluster ARN in the account and region. func (e *ECS) DefaultCluster() (string, error) { - resp, err := e.client.DescribeClusters(&ecs.DescribeClustersInput{}) + resp, err := e.client.DescribeClusters(context.Background(), &ecs.DescribeClustersInput{}) if err != nil { return "", fmt.Errorf("get default cluster: %w", err) } @@ -342,11 +355,11 @@ func (e *ECS) DefaultCluster() (string, error) { // NOTE: right now at most 1 default cluster is possible, so cluster[0] must be the default cluster cluster := resp.Clusters[0] - if aws.StringValue(cluster.Status) != statusActive { + if awsv2.ToString(cluster.Status) != statusActive { return "", ErrNoDefaultCluster } - return aws.StringValue(cluster.ClusterArn), nil + return awsv2.ToString(cluster.ClusterArn), nil } // HasDefaultCluster tries to find the default cluster and returns true if there is one. @@ -362,20 +375,20 @@ func (e *ECS) HasDefaultCluster() (bool, error) { // ActiveClusters returns the subset of cluster arns that have an ACTIVE status. func (e *ECS) ActiveClusters(arns ...string) ([]string, error) { - resp, err := e.client.DescribeClusters(&ecs.DescribeClustersInput{ - Clusters: aws.StringSlice(arns), + resp, err := e.client.DescribeClusters(context.Background(), &ecs.DescribeClustersInput{ + Clusters: arns, }) switch { case err != nil: return nil, fmt.Errorf("describe clusters: %w", err) case len(resp.Failures) > 0: - return nil, fmt.Errorf("describe clusters: %s", resp.Failures[0].GoString()) + return nil, fmt.Errorf("describe clusters: %s", failureString(resp.Failures[0])) } var active []string for _, cluster := range resp.Clusters { - if aws.StringValue(cluster.Status) == statusActive { - active = append(active, aws.StringValue(cluster.ClusterArn)) + if awsv2.ToString(cluster.Status) == statusActive { + active = append(active, awsv2.ToString(cluster.ClusterArn)) } } @@ -389,21 +402,21 @@ func (e *ECS) ActiveServices(clusterARN string, serviceARNs ...string) ([]string if err != nil { return nil, err } - resp, err := e.client.DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(clusterARN), - Services: aws.StringSlice(filteredSvcARNS), + resp, err := e.client.DescribeServices(context.Background(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(clusterARN), + Services: filteredSvcARNS, }) switch { case err != nil: return nil, fmt.Errorf("describe services: %w", err) case len(resp.Failures) > 0: - return nil, fmt.Errorf("describe services: %s", resp.Failures[0].GoString()) + return nil, fmt.Errorf("describe services: %s", failureString(resp.Failures[0])) } var active []string for _, svc := range resp.Services { - if aws.StringValue(svc.Status) == statusActive { - active = append(active, aws.StringValue(svc.ServiceArn)) + if awsv2.ToString(svc.Status) == statusActive { + active = append(active, awsv2.ToString(svc.ServiceArn)) } } @@ -413,22 +426,22 @@ func (e *ECS) ActiveServices(clusterARN string, serviceARNs ...string) ([]string // RunTask runs a number of tasks with the task definition and network configurations in a cluster, and returns after // the task(s) is running or fails to run, along with task ARNs if possible. func (e *ECS) RunTask(input RunTaskInput) ([]*Task, error) { - resp, err := e.client.RunTask(&ecs.RunTaskInput{ - Cluster: aws.String(input.Cluster), - Count: aws.Int64(int64(input.Count)), - LaunchType: aws.String(ecs.LaunchTypeFargate), - StartedBy: aws.String(input.StartedBy), - TaskDefinition: aws.String(input.TaskFamilyName), - NetworkConfiguration: &ecs.NetworkConfiguration{ - AwsvpcConfiguration: &ecs.AwsVpcConfiguration{ - AssignPublicIp: aws.String(ecs.AssignPublicIpEnabled), - Subnets: aws.StringSlice(input.Subnets), - SecurityGroups: aws.StringSlice(input.SecurityGroups), + resp, err := e.client.RunTask(context.Background(), &ecs.RunTaskInput{ + Cluster: awsv2.String(input.Cluster), + Count: awsv2.Int32(int32(input.Count)), + LaunchType: types.LaunchTypeFargate, + StartedBy: awsv2.String(input.StartedBy), + TaskDefinition: awsv2.String(input.TaskFamilyName), + NetworkConfiguration: &types.NetworkConfiguration{ + AwsvpcConfiguration: &types.AwsVpcConfiguration{ + AssignPublicIp: types.AssignPublicIpEnabled, + Subnets: input.Subnets, + SecurityGroups: input.SecurityGroups, }, }, - EnableExecuteCommand: aws.Bool(input.EnableExec), - PlatformVersion: aws.String(input.PlatformVersion), - PropagateTags: aws.String(ecs.PropagateTagsTaskDefinition), + EnableExecuteCommand: input.EnableExec, + PlatformVersion: awsv2.String(input.PlatformVersion), + PropagateTags: types.PropagateTagsTaskDefinition, }) if err != nil { return nil, fmt.Errorf("run task(s) %s: %w", input.TaskFamilyName, err) @@ -436,14 +449,14 @@ func (e *ECS) RunTask(input RunTaskInput) ([]*Task, error) { taskARNs := make([]string, len(resp.Tasks)) for idx, task := range resp.Tasks { - taskARNs[idx] = aws.StringValue(task.TaskArn) + taskARNs[idx] = awsv2.ToString(task.TaskArn) } - waitErr := e.client.WaitUntilTasksRunning(&ecs.DescribeTasksInput{ - Cluster: aws.String(input.Cluster), - Tasks: aws.StringSlice(taskARNs), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), - }) + waitErr := e.client.WaitUntilTasksRunning(context.Background(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String(input.Cluster), + Tasks: taskARNs, + Include: []types.TaskField{types.TaskFieldTags}, + }, 10*time.Minute) if waitErr != nil && !isRequestTimeoutErr(waitErr) { return nil, fmt.Errorf("wait for tasks to be running: %w", waitErr) @@ -463,10 +476,10 @@ func (e *ECS) RunTask(input RunTaskInput) ([]*Task, error) { // DescribeTasks returns the tasks with the taskARNs in the cluster. func (e *ECS) DescribeTasks(cluster string, taskARNs []string) ([]*Task, error) { - resp, err := e.client.DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String(cluster), - Tasks: aws.StringSlice(taskARNs), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + resp, err := e.client.DescribeTasks(context.Background(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String(cluster), + Tasks: taskARNs, + Include: []types.TaskField{types.TaskFieldTags}, }) if err != nil { return nil, fmt.Errorf("describe tasks: %w", err) @@ -474,7 +487,7 @@ func (e *ECS) DescribeTasks(cluster string, taskARNs []string) ([]*Task, error) tasks := make([]*Task, len(resp.Tasks)) for idx, task := range resp.Tasks { - t := Task(*task) + t := Task(task) tasks[idx] = &t } return tasks, nil @@ -482,17 +495,17 @@ func (e *ECS) DescribeTasks(cluster string, taskARNs []string) ([]*Task, error) // ExecuteCommand executes commands in a running container, and then terminate the session. func (e *ECS) ExecuteCommand(in ExecuteCommandInput) (err error) { - execCmdresp, err := e.client.ExecuteCommand(&ecs.ExecuteCommandInput{ - Cluster: aws.String(in.Cluster), - Command: aws.String(in.Command), - Container: aws.String(in.Container), - Interactive: aws.Bool(true), - Task: aws.String(in.Task), + execCmdresp, err := e.client.ExecuteCommand(context.Background(), &ecs.ExecuteCommandInput{ + Cluster: awsv2.String(in.Cluster), + Command: awsv2.String(in.Command), + Container: awsv2.String(in.Container), + Interactive: true, + Task: awsv2.String(in.Task), }) if err != nil { return &ErrExecuteCommand{err: err} } - sessID := aws.StringValue(execCmdresp.Session.SessionId) + sessID := awsv2.ToString(execCmdresp.Session.SessionId) if err = e.newSessStarter().StartSession(execCmdresp.Session); err != nil { err = fmt.Errorf("start session %s using ssm plugin: %w", sessID, err) } @@ -512,23 +525,23 @@ func (e *ECS) NetworkConfiguration(cluster, serviceName string) (*NetworkConfigu } return &NetworkConfiguration{ - AssignPublicIp: aws.StringValue(networkConfig.AwsvpcConfiguration.AssignPublicIp), - SecurityGroups: aws.StringValueSlice(networkConfig.AwsvpcConfiguration.SecurityGroups), - Subnets: aws.StringValueSlice(networkConfig.AwsvpcConfiguration.Subnets), + AssignPublicIp: string(networkConfig.AwsvpcConfiguration.AssignPublicIp), + SecurityGroups: networkConfig.AwsvpcConfiguration.SecurityGroups, + Subnets: networkConfig.AwsvpcConfiguration.Subnets, }, nil } func (e *ECS) service(clusterName, serviceName string) (*Service, error) { - resp, err := e.client.DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(clusterName), - Services: aws.StringSlice([]string{serviceName}), + resp, err := e.client.DescribeServices(context.Background(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(clusterName), + Services: []string{serviceName}, }) if err != nil { return nil, fmt.Errorf("describe service %s: %w", serviceName, err) } for _, service := range resp.Services { - if aws.StringValue(service.ServiceName) == serviceName { - svc := Service(*service) + if awsv2.ToString(service.ServiceName) == serviceName { + svc := Service(service) return &svc, nil } } @@ -551,8 +564,22 @@ func (e *ECS) filterServiceARNs(clusterARN string, serviceARNs ...string) ([]str } func isRequestTimeoutErr(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - return aerr.Code() == request.WaiterResourceNotReadyErrorCode + return strings.Contains(err.Error(), "exceeded max wait time for TasksRunning waiter") +} + +func failureString(f types.Failure) string { + var fields []string + if f.Arn != nil { + fields = append(fields, fmt.Sprintf(" Arn: %q", awsv2.ToString(f.Arn))) + } + if f.Detail != nil { + fields = append(fields, fmt.Sprintf(" Detail: %q", awsv2.ToString(f.Detail))) + } + if f.Reason != nil { + fields = append(fields, fmt.Sprintf(" Reason: %q", awsv2.ToString(f.Reason))) + } + if len(fields) == 0 { + return "{}" } - return false + return fmt.Sprintf("{\n%s\n}", strings.Join(fields, ",\n")) } diff --git a/internal/pkg/aws/ecs/ecs_test.go b/internal/pkg/aws/ecs/ecs_test.go index 450463a0fc6..6bbf9748bfd 100644 --- a/internal/pkg/aws/ecs/ecs_test.go +++ b/internal/pkg/aws/ecs/ecs_test.go @@ -9,10 +9,9 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -30,8 +29,8 @@ func TestECS_TaskDefinition(t *testing.T) { "should return wrapped error given error": { taskDefinitionName: "task-def", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{ - TaskDefinition: aws.String("task-def"), + m.EXPECT().DescribeTaskDefinition(gomock.Any(), &ecs.DescribeTaskDefinitionInput{ + TaskDefinition: awsv2.String("task-def"), }).Return(nil, mockError) }, wantErr: fmt.Errorf("describe task definition %s: %w", "task-def", mockError), @@ -39,20 +38,20 @@ func TestECS_TaskDefinition(t *testing.T) { "returns task definition given a task definition name": { taskDefinitionName: "task-def", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeTaskDefinition(&ecs.DescribeTaskDefinitionInput{ - TaskDefinition: aws.String("task-def"), + m.EXPECT().DescribeTaskDefinition(gomock.Any(), &ecs.DescribeTaskDefinitionInput{ + TaskDefinition: awsv2.String("task-def"), }).Return(&ecs.DescribeTaskDefinitionOutput{ - TaskDefinition: &ecs.TaskDefinition{ - ContainerDefinitions: []*ecs.ContainerDefinition{ + TaskDefinition: &types.TaskDefinition{ + ContainerDefinitions: []types.ContainerDefinition{ { - Environment: []*ecs.KeyValuePair{ + Environment: []types.KeyValuePair{ { - Name: aws.String("COPILOT_SERVICE_NAME"), - Value: aws.String("my-app"), + Name: awsv2.String("COPILOT_SERVICE_NAME"), + Value: awsv2.String("my-app"), }, { - Name: aws.String("COPILOT_ENVIRONMENT_NAME"), - Value: aws.String("prod"), + Name: awsv2.String("COPILOT_ENVIRONMENT_NAME"), + Value: awsv2.String("prod"), }, }, }, @@ -61,16 +60,16 @@ func TestECS_TaskDefinition(t *testing.T) { }, nil) }, wantTaskDef: &TaskDefinition{ - ContainerDefinitions: []*ecs.ContainerDefinition{ + ContainerDefinitions: []types.ContainerDefinition{ { - Environment: []*ecs.KeyValuePair{ + Environment: []types.KeyValuePair{ { - Name: aws.String("COPILOT_SERVICE_NAME"), - Value: aws.String("my-app"), + Name: awsv2.String("COPILOT_SERVICE_NAME"), + Value: awsv2.String("my-app"), }, { - Name: aws.String("COPILOT_ENVIRONMENT_NAME"), - Value: aws.String("prod"), + Name: awsv2.String("COPILOT_ENVIRONMENT_NAME"), + Value: awsv2.String("prod"), }, }, }, @@ -117,28 +116,28 @@ func TestECS_Service(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"mockService"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"mockService"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("mockService"), + ServiceName: awsv2.String("mockService"), }, }, }, nil) }, wantSvc: &Service{ - ServiceName: aws.String("mockService"), + ServiceName: awsv2.String("mockService"), }, }, "errors if failed to describe service": { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"mockService"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"mockService"}, }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("describe services: some error"), @@ -147,13 +146,13 @@ func TestECS_Service(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"mockService"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"mockService"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("badMockService"), + ServiceName: awsv2.String("badMockService"), }, }, }, nil) @@ -200,9 +199,9 @@ func TestECS_Services(t *testing.T) { clusterName: "mockCluster", services: []string{"1"}, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"1"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"1"}, }).Return(nil, errors.New("some error")) }, wantErr: "describe services: some error", @@ -211,14 +210,14 @@ func TestECS_Services(t *testing.T) { clusterName: "mockCluster", services: []string{"1"}, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"1"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"1"}, }).Return(&ecs.DescribeServicesOutput{ - Failures: []*ecs.Failure{ + Failures: []types.Failure{ { - Arn: aws.String("arn:1"), - Reason: aws.String("some error"), + Arn: awsv2.String("arn:1"), + Reason: awsv2.String("some error"), }, }, }, nil) @@ -232,13 +231,13 @@ func TestECS_Services(t *testing.T) { clusterName: "mockCluster", services: []string{"1", "2"}, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"1", "2"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"1", "2"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("1"), + ServiceName: awsv2.String("1"), }, }, }, nil) @@ -252,87 +251,87 @@ func TestECS_Services(t *testing.T) { "11", }, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"1", "2", "3", "4", "5", "6", "7", "8", "9", "10"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("1"), + ServiceName: awsv2.String("1"), }, { - ServiceName: aws.String("2"), + ServiceName: awsv2.String("2"), }, { - ServiceName: aws.String("3"), + ServiceName: awsv2.String("3"), }, { - ServiceName: aws.String("4"), + ServiceName: awsv2.String("4"), }, { - ServiceName: aws.String("5"), + ServiceName: awsv2.String("5"), }, { - ServiceName: aws.String("6"), + ServiceName: awsv2.String("6"), }, { - ServiceName: aws.String("7"), + ServiceName: awsv2.String("7"), }, { - ServiceName: aws.String("8"), + ServiceName: awsv2.String("8"), }, { - ServiceName: aws.String("9"), + ServiceName: awsv2.String("9"), }, { - ServiceName: aws.String("10"), + ServiceName: awsv2.String("10"), }, }, }, nil) - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("mockCluster"), - Services: aws.StringSlice([]string{"11"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("mockCluster"), + Services: []string{"11"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("11"), + ServiceName: awsv2.String("11"), }, }, }, nil) }, wantSvcs: []*Service{ { - ServiceName: aws.String("1"), + ServiceName: awsv2.String("1"), }, { - ServiceName: aws.String("2"), + ServiceName: awsv2.String("2"), }, { - ServiceName: aws.String("3"), + ServiceName: awsv2.String("3"), }, { - ServiceName: aws.String("4"), + ServiceName: awsv2.String("4"), }, { - ServiceName: aws.String("5"), + ServiceName: awsv2.String("5"), }, { - ServiceName: aws.String("6"), + ServiceName: awsv2.String("6"), }, { - ServiceName: aws.String("7"), + ServiceName: awsv2.String("7"), }, { - ServiceName: aws.String("8"), + ServiceName: awsv2.String("8"), }, { - ServiceName: aws.String("9"), + ServiceName: awsv2.String("9"), }, { - ServiceName: aws.String("10"), + ServiceName: awsv2.String("10"), }, { - ServiceName: aws.String("11"), + ServiceName: awsv2.String("11"), }, }, }, @@ -374,23 +373,20 @@ func TestECS_ListServicesByNamespace(t *testing.T) { "error if api call error": { namespace: "mockNamespace", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListServicesByNamespacePages(&ecs.ListServicesByNamespaceInput{ - Namespace: aws.String("mockNamespace"), - }, gomock.Any()).Return(errors.New("some error")) + m.EXPECT().ListServicesByNamespace(gomock.Any(), &ecs.ListServicesByNamespaceInput{ + Namespace: awsv2.String("mockNamespace"), + }).Return(nil, errors.New("some error")) }, wantErr: "some error", }, "success": { namespace: "mockNamespace", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListServicesByNamespacePages(&ecs.ListServicesByNamespaceInput{ - Namespace: aws.String("mockNamespace"), - }, gomock.Any()).DoAndReturn(func(in *ecs.ListServicesByNamespaceInput, fn func(*ecs.ListServicesByNamespaceOutput, bool) bool) error { - fn(&ecs.ListServicesByNamespaceOutput{ - ServiceArns: []*string{aws.String("svc1"), aws.String("svc2"), aws.String("svc3")}, - }, true) - return nil - }) + m.EXPECT().ListServicesByNamespace(gomock.Any(), &ecs.ListServicesByNamespaceInput{ + Namespace: awsv2.String("mockNamespace"), + }).Return(&ecs.ListServicesByNamespaceOutput{ + ServiceArns: []string{"svc1", "svc2", "svc3"}, + }, nil) }, wantARNs: []string{"svc1", "svc2", "svc3"}, }, @@ -437,38 +433,38 @@ func TestECS_UpdateService(t *testing.T) { "errors if failed to update service": { mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().UpdateService(&ecs.UpdateServiceInput{ - Cluster: aws.String(clusterName), - Service: aws.String(serviceName), + m.EXPECT().UpdateService(gomock.Any(), &ecs.UpdateServiceInput{ + Cluster: awsv2.String(clusterName), + Service: awsv2.String(serviceName), }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("update service mockService from cluster mockCluster: some error"), }, "errors if max retries exceeded": { mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().UpdateService(&ecs.UpdateServiceInput{ - Cluster: aws.String(clusterName), - Service: aws.String(serviceName), + m.EXPECT().UpdateService(gomock.Any(), &ecs.UpdateServiceInput{ + Cluster: awsv2.String(clusterName), + Service: awsv2.String(serviceName), }).Return(&ecs.UpdateServiceOutput{ - Service: &ecs.Service{ - Deployments: []*ecs.Deployment{{}, {}}, - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(2), - ClusterArn: aws.String(clusterName), - ServiceName: aws.String(serviceName), + Service: &types.Service{ + Deployments: []types.Deployment{{}, {}}, + DesiredCount: 1, + RunningCount: 2, + ClusterArn: awsv2.String(clusterName), + ServiceName: awsv2.String(serviceName), }, }, nil) - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(clusterName), - Services: aws.StringSlice([]string{serviceName}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(clusterName), + Services: []string{serviceName}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - Deployments: []*ecs.Deployment{{}}, - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(2), - ClusterArn: aws.String(clusterName), - ServiceName: aws.String(serviceName), + Deployments: []types.Deployment{{}}, + DesiredCount: 1, + RunningCount: 2, + ClusterArn: awsv2.String(clusterName), + ServiceName: awsv2.String(serviceName), }, }, }, nil).Times(2) @@ -477,21 +473,21 @@ func TestECS_UpdateService(t *testing.T) { }, "errors if failed to describe service": { mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().UpdateService(&ecs.UpdateServiceInput{ - Cluster: aws.String(clusterName), - Service: aws.String(serviceName), + m.EXPECT().UpdateService(gomock.Any(), &ecs.UpdateServiceInput{ + Cluster: awsv2.String(clusterName), + Service: awsv2.String(serviceName), }).Return(&ecs.UpdateServiceOutput{ - Service: &ecs.Service{ - Deployments: []*ecs.Deployment{{}, {}}, - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(2), - ClusterArn: aws.String(clusterName), - ServiceName: aws.String(serviceName), + Service: &types.Service{ + Deployments: []types.Deployment{{}, {}}, + DesiredCount: 1, + RunningCount: 2, + ClusterArn: awsv2.String(clusterName), + ServiceName: awsv2.String(serviceName), }, }, nil) - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(clusterName), - Services: aws.StringSlice([]string{serviceName}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(clusterName), + Services: []string{serviceName}, }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("wait until service mockService becomes stable: describe services: some error"), @@ -499,44 +495,44 @@ func TestECS_UpdateService(t *testing.T) { "success": { forceUpdate: true, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().UpdateService(&ecs.UpdateServiceInput{ - Cluster: aws.String(clusterName), - Service: aws.String(serviceName), - ForceNewDeployment: aws.Bool(true), + m.EXPECT().UpdateService(gomock.Any(), &ecs.UpdateServiceInput{ + Cluster: awsv2.String(clusterName), + Service: awsv2.String(serviceName), + ForceNewDeployment: true, }).Return(&ecs.UpdateServiceOutput{ - Service: &ecs.Service{ - Deployments: []*ecs.Deployment{{}, {}}, - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(2), - ClusterArn: aws.String(clusterName), - ServiceName: aws.String(serviceName), + Service: &types.Service{ + Deployments: []types.Deployment{{}, {}}, + DesiredCount: 1, + RunningCount: 2, + ClusterArn: awsv2.String(clusterName), + ServiceName: awsv2.String(serviceName), }, }, nil) - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(clusterName), - Services: aws.StringSlice([]string{serviceName}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(clusterName), + Services: []string{serviceName}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - Deployments: []*ecs.Deployment{{}}, - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(2), - ClusterArn: aws.String(clusterName), - ServiceName: aws.String(serviceName), + Deployments: []types.Deployment{{}}, + DesiredCount: 1, + RunningCount: 2, + ClusterArn: awsv2.String(clusterName), + ServiceName: awsv2.String(serviceName), }, }, }, nil) - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String(clusterName), - Services: aws.StringSlice([]string{serviceName}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String(clusterName), + Services: []string{serviceName}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - Deployments: []*ecs.Deployment{{}}, - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(1), - ClusterArn: aws.String(clusterName), - ServiceName: aws.String(serviceName), + Deployments: []types.Deployment{{}}, + DesiredCount: 1, + RunningCount: 1, + ClusterArn: awsv2.String(clusterName), + ServiceName: awsv2.String(serviceName), }, }, }, nil) @@ -588,10 +584,10 @@ func TestECS_Tasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String("RUNNING"), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusRunning, }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("list running tasks: some error"), @@ -600,18 +596,18 @@ func TestECS_Tasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String("RUNNING"), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusRunning, }).Return(&ecs.ListTasksOutput{ NextToken: nil, - TaskArns: aws.StringSlice([]string{"mockTaskArn"}), + TaskArns: []string{"mockTaskArn"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("describe running tasks in cluster mockCluster: some error"), @@ -620,29 +616,29 @@ func TestECS_Tasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String("RUNNING"), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusRunning, }).Return(&ecs.ListTasksOutput{ NextToken: nil, - TaskArns: aws.StringSlice([]string{"mockTaskArn"}), + TaskArns: []string{"mockTaskArn"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("mockTaskArn"), + TaskArn: awsv2.String("mockTaskArn"), }, }, }, nil) }, wantTasks: []*Task{ { - TaskArn: aws.String("mockTaskArn"), + TaskArn: awsv2.String("mockTaskArn"), }, }, }, @@ -650,52 +646,52 @@ func TestECS_Tasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String("RUNNING"), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusRunning, }).Return(&ecs.ListTasksOutput{ - NextToken: aws.String("mockNextToken"), - TaskArns: aws.StringSlice([]string{"mockTaskArn1"}), + NextToken: awsv2.String("mockNextToken"), + TaskArns: []string{"mockTaskArn1"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn1"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn1"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("mockTaskArn1"), + TaskArn: awsv2.String("mockTaskArn1"), }, }, }, nil) - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String("RUNNING"), - NextToken: aws.String("mockNextToken"), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusRunning, + NextToken: awsv2.String("mockNextToken"), }).Return(&ecs.ListTasksOutput{ NextToken: nil, - TaskArns: aws.StringSlice([]string{"mockTaskArn2"}), + TaskArns: []string{"mockTaskArn2"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn2"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn2"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("mockTaskArn2"), + TaskArn: awsv2.String("mockTaskArn2"), }, }, }, nil) }, wantTasks: []*Task{ { - TaskArn: aws.String("mockTaskArn1"), + TaskArn: awsv2.String("mockTaskArn1"), }, { - TaskArn: aws.String("mockTaskArn2"), + TaskArn: awsv2.String("mockTaskArn2"), }, }, }, @@ -739,10 +735,10 @@ func TestECS_StoppedServiceTasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String(ecs.DesiredStatusStopped), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusStopped, }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("list running tasks: some error"), @@ -751,18 +747,18 @@ func TestECS_StoppedServiceTasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String(ecs.DesiredStatusStopped), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusStopped, }).Return(&ecs.ListTasksOutput{ NextToken: nil, - TaskArns: aws.StringSlice([]string{"mockTaskArn"}), + TaskArns: []string{"mockTaskArn"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(nil, errors.New("some error")) }, wantErr: fmt.Errorf("describe running tasks in cluster mockCluster: some error"), @@ -771,29 +767,29 @@ func TestECS_StoppedServiceTasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String(ecs.DesiredStatusStopped), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusStopped, }).Return(&ecs.ListTasksOutput{ NextToken: nil, - TaskArns: aws.StringSlice([]string{"mockTaskArn"}), + TaskArns: []string{"mockTaskArn"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("mockTaskArn"), + TaskArn: awsv2.String("mockTaskArn"), }, }, }, nil) }, wantTasks: []*Task{ { - TaskArn: aws.String("mockTaskArn"), + TaskArn: awsv2.String("mockTaskArn"), }, }, }, @@ -801,52 +797,52 @@ func TestECS_StoppedServiceTasks(t *testing.T) { clusterName: "mockCluster", serviceName: "mockService", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String(ecs.DesiredStatusStopped), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusStopped, }).Return(&ecs.ListTasksOutput{ - NextToken: aws.String("mockNextToken"), - TaskArns: aws.StringSlice([]string{"mockTaskArn1"}), + NextToken: awsv2.String("mockNextToken"), + TaskArns: []string{"mockTaskArn1"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn1"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn1"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("mockTaskArn1"), + TaskArn: awsv2.String("mockTaskArn1"), }, }, }, nil) - m.EXPECT().ListTasks(&ecs.ListTasksInput{ - Cluster: aws.String("mockCluster"), - ServiceName: aws.String("mockService"), - DesiredStatus: aws.String(ecs.DesiredStatusStopped), - NextToken: aws.String("mockNextToken"), + m.EXPECT().ListTasks(gomock.Any(), &ecs.ListTasksInput{ + Cluster: awsv2.String("mockCluster"), + ServiceName: awsv2.String("mockService"), + DesiredStatus: types.DesiredStatusStopped, + NextToken: awsv2.String("mockNextToken"), }).Return(&ecs.ListTasksOutput{ NextToken: nil, - TaskArns: aws.StringSlice([]string{"mockTaskArn2"}), + TaskArns: []string{"mockTaskArn2"}, }, nil) - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String("mockCluster"), - Tasks: aws.StringSlice([]string{"mockTaskArn2"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String("mockCluster"), + Tasks: []string{"mockTaskArn2"}, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("mockTaskArn2"), + TaskArn: awsv2.String("mockTaskArn2"), }, }, }, nil) }, wantTasks: []*Task{ { - TaskArn: aws.String("mockTaskArn1"), + TaskArn: awsv2.String("mockTaskArn1"), }, { - TaskArn: aws.String("mockTaskArn2"), + TaskArn: awsv2.String("mockTaskArn2"), }, }, }, @@ -891,11 +887,11 @@ func TestECS_StopTasks(t *testing.T) { "errors if failed to stop tasks in default cluster": { tasks: mockTasks, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().StopTask(&ecs.StopTaskInput{ - Task: aws.String("mockTask1"), + m.EXPECT().StopTask(gomock.Any(), &ecs.StopTaskInput{ + Task: awsv2.String("mockTask1"), }).Return(&ecs.StopTaskOutput{}, nil) - m.EXPECT().StopTask(&ecs.StopTaskInput{ - Task: aws.String("mockTask2"), + m.EXPECT().StopTask(gomock.Any(), &ecs.StopTaskInput{ + Task: awsv2.String("mockTask2"), }).Return(&ecs.StopTaskOutput{}, mockError) }, wantErr: fmt.Errorf("stop task mockTask2: some error"), @@ -905,15 +901,15 @@ func TestECS_StopTasks(t *testing.T) { cluster: "mockCluster", stopTasksReason: "some reason", mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().StopTask(&ecs.StopTaskInput{ - Cluster: aws.String("mockCluster"), - Reason: aws.String("some reason"), - Task: aws.String("mockTask1"), + m.EXPECT().StopTask(gomock.Any(), &ecs.StopTaskInput{ + Cluster: awsv2.String("mockCluster"), + Reason: awsv2.String("some reason"), + Task: awsv2.String("mockTask1"), }).Return(&ecs.StopTaskOutput{}, nil) - m.EXPECT().StopTask(&ecs.StopTaskInput{ - Cluster: aws.String("mockCluster"), - Reason: aws.String("some reason"), - Task: aws.String("mockTask2"), + m.EXPECT().StopTask(gomock.Any(), &ecs.StopTaskInput{ + Cluster: awsv2.String("mockCluster"), + Reason: awsv2.String("some reason"), + Task: awsv2.String("mockTask2"), }).Return(&ecs.StopTaskOutput{}, nil) }, }, @@ -960,18 +956,18 @@ func TestECS_DefaultCluster(t *testing.T) { "get default clusters success": { mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeClusters(&ecs.DescribeClustersInput{}). + DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{}). Return(&ecs.DescribeClustersOutput{ - Clusters: []*ecs.Cluster{ + Clusters: []types.Cluster{ { - ClusterArn: aws.String("arn:aws:ecs:us-east-1:0123456:cluster/cluster1"), - ClusterName: aws.String("cluster1"), - Status: aws.String(statusActive), + ClusterArn: awsv2.String("arn:aws:ecs:us-east-1:0123456:cluster/cluster1"), + ClusterName: awsv2.String("cluster1"), + Status: awsv2.String(statusActive), }, { - ClusterArn: aws.String("arn:aws:ecs:us-east-1:0123456:cluster/cluster2"), - ClusterName: aws.String("cluster2"), - Status: aws.String(statusActive), + ClusterArn: awsv2.String("arn:aws:ecs:us-east-1:0123456:cluster/cluster2"), + ClusterName: awsv2.String("cluster2"), + Status: awsv2.String(statusActive), }, }, }, nil) @@ -982,13 +978,13 @@ func TestECS_DefaultCluster(t *testing.T) { "ignore inactive cluster": { mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeClusters(&ecs.DescribeClustersInput{}). + DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{}). Return(&ecs.DescribeClustersOutput{ - Clusters: []*ecs.Cluster{ + Clusters: []types.Cluster{ { - ClusterArn: aws.String("arn:aws:ecs:us-east-1:0123456:cluster/cluster1"), - ClusterName: aws.String("cluster1"), - Status: aws.String("INACTIVE"), + ClusterArn: awsv2.String("arn:aws:ecs:us-east-1:0123456:cluster/cluster1"), + ClusterName: awsv2.String("cluster1"), + Status: awsv2.String("INACTIVE"), }, }, }, nil) @@ -998,7 +994,7 @@ func TestECS_DefaultCluster(t *testing.T) { "failed to get default clusters": { mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeClusters(&ecs.DescribeClustersInput{}). + DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{}). Return(nil, errors.New("error")) }, wantedError: fmt.Errorf("get default cluster: %s", "error"), @@ -1035,28 +1031,28 @@ func TestECS_HasDefaultCluster(t *testing.T) { }{ "no default cluster": { mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeClusters(&ecs.DescribeClustersInput{}). + m.EXPECT().DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{}). Return(&ecs.DescribeClustersOutput{ - Clusters: []*ecs.Cluster{}, + Clusters: []types.Cluster{}, }, nil) }, wantedHasDefaultCluster: false, }, "error getting default cluster": { mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeClusters(&ecs.DescribeClustersInput{}). + m.EXPECT().DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{}). Return(nil, errors.New("other error")) }, wantedErr: fmt.Errorf("get default cluster: other error"), }, "has default cluster": { mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().DescribeClusters(&ecs.DescribeClustersInput{}). + m.EXPECT().DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{}). Return(&ecs.DescribeClustersOutput{ - Clusters: []*ecs.Cluster{ + Clusters: []types.Cluster{ { - ClusterArn: aws.String("cluster"), - Status: aws.String(statusActive), + ClusterArn: awsv2.String("cluster"), + Status: awsv2.String(statusActive), }, }, }, nil) @@ -1101,7 +1097,7 @@ func TestECS_ActiveClusters(t *testing.T) { inArns: []string{"arn1"}, mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeClusters(gomock.Any()). + DescribeClusters(gomock.Any(), gomock.Any()). Return(nil, fmt.Errorf("some error")) }, wantedError: fmt.Errorf("describe clusters: some error"), @@ -1110,26 +1106,26 @@ func TestECS_ActiveClusters(t *testing.T) { inArns: []string{"arn1", "arn2"}, mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeClusters(&ecs.DescribeClustersInput{ - Clusters: aws.StringSlice([]string{"arn1", "arn2"}), + DescribeClusters(gomock.Any(), &ecs.DescribeClustersInput{ + Clusters: []string{"arn1", "arn2"}, }). Return(&ecs.DescribeClustersOutput{ - Clusters: []*ecs.Cluster{ + Clusters: []types.Cluster{ { - ClusterArn: aws.String("cluster1"), - Status: aws.String(statusActive), + ClusterArn: awsv2.String("cluster1"), + Status: awsv2.String(statusActive), }, { - ClusterArn: aws.String("cluster2"), - Status: aws.String("INACTIVE"), + ClusterArn: awsv2.String("cluster2"), + Status: awsv2.String("INACTIVE"), }, { - ClusterArn: aws.String("cluster3"), - Status: aws.String(statusActive), + ClusterArn: awsv2.String("cluster3"), + Status: awsv2.String(statusActive), }, { - ClusterArn: aws.String("cluster4"), - Status: aws.String("random"), + ClusterArn: awsv2.String("cluster4"), + Status: awsv2.String("random"), }, }, }, nil) @@ -1177,7 +1173,7 @@ func TestECS_ActiveServices(t *testing.T) { inArns: []string{"arn:aws:ecs:us-west-2:1234567890:service/cluster1/svc1", "arn:aws:ecs:us-west-2:1234567890:service/cluster2/svc2"}, mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeServices(gomock.Any()). + DescribeServices(gomock.Any(), gomock.Any()). Return(nil, fmt.Errorf("some error")) }, wantedError: fmt.Errorf("describe services: some error"), @@ -1187,16 +1183,16 @@ func TestECS_ActiveServices(t *testing.T) { inArns: []string{"arn:aws:ecs:us-west-2:1234567890:service/cluster1/svc1", "arn:aws:ecs:us-west-2:1234567890:service/cluster1/svc2"}, mockECSClient: func(m *mocks.Mockapi) { m.EXPECT(). - DescribeServices(gomock.Any()). + DescribeServices(gomock.Any(), gomock.Any()). Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceArn: aws.String("service1"), - Status: aws.String(statusActive), + ServiceArn: awsv2.String("service1"), + Status: awsv2.String(statusActive), }, { - ServiceArn: aws.String("service2"), - Status: aws.String("random"), + ServiceArn: awsv2.String("service2"), + Status: awsv2.String("random"), }, }, }, nil) @@ -1250,21 +1246,21 @@ func TestECS_RunTask(t *testing.T) { platformVersion: "LATEST", enableExec: true, } - ecsTasks := []*ecs.Task{ + ecsTasks := []types.Task{ { - TaskArn: aws.String("task-1"), + TaskArn: awsv2.String("task-1"), }, { - TaskArn: aws.String("task-2"), + TaskArn: awsv2.String("task-2"), }, { - TaskArn: aws.String("task-3"), + TaskArn: awsv2.String("task-3"), }, } describeTasksInput := ecs.DescribeTasksInput{ - Cluster: aws.String("my-cluster"), - Tasks: aws.StringSlice([]string{"task-1", "task-2", "task-3"}), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + Cluster: awsv2.String("my-cluster"), + Tasks: []string{"task-1", "task-2", "task-3"}, + Include: []types.TaskField{types.TaskFieldTags}, } testCases := map[string]struct { input @@ -1277,39 +1273,39 @@ func TestECS_RunTask(t *testing.T) { "run task success": { input: runTaskInput, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().RunTask(&ecs.RunTaskInput{ - Cluster: aws.String("my-cluster"), - Count: aws.Int64(3), - LaunchType: aws.String(ecs.LaunchTypeFargate), - StartedBy: aws.String("task"), - TaskDefinition: aws.String("my-task"), - NetworkConfiguration: &ecs.NetworkConfiguration{ - AwsvpcConfiguration: &ecs.AwsVpcConfiguration{ - AssignPublicIp: aws.String(ecs.AssignPublicIpEnabled), - Subnets: aws.StringSlice([]string{"subnet-1", "subnet-2"}), - SecurityGroups: aws.StringSlice([]string{"sg-1", "sg-2"}), + m.EXPECT().RunTask(gomock.Any(), &ecs.RunTaskInput{ + Cluster: awsv2.String("my-cluster"), + Count: awsv2.Int32(int32(3)), + LaunchType: types.LaunchTypeFargate, + StartedBy: awsv2.String("task"), + TaskDefinition: awsv2.String("my-task"), + NetworkConfiguration: &types.NetworkConfiguration{ + AwsvpcConfiguration: &types.AwsVpcConfiguration{ + AssignPublicIp: types.AssignPublicIpEnabled, + Subnets: []string{"subnet-1", "subnet-2"}, + SecurityGroups: []string{"sg-1", "sg-2"}, }, }, - EnableExecuteCommand: aws.Bool(true), - PlatformVersion: aws.String("LATEST"), - PropagateTags: aws.String(ecs.PropagateTagsTaskDefinition), + EnableExecuteCommand: true, + PlatformVersion: awsv2.String("LATEST"), + PropagateTags: types.PropagateTagsTaskDefinition, }).Return(&ecs.RunTaskOutput{ Tasks: ecsTasks, }, nil) - m.EXPECT().WaitUntilTasksRunning(&describeTasksInput).Times(1) - m.EXPECT().DescribeTasks(&describeTasksInput).Return(&ecs.DescribeTasksOutput{ + m.EXPECT().WaitUntilTasksRunning(gomock.Any(), &describeTasksInput, gomock.Any()).Times(1) + m.EXPECT().DescribeTasks(gomock.Any(), &describeTasksInput).Return(&ecs.DescribeTasksOutput{ Tasks: ecsTasks, }, nil) }, wantedTasks: []*Task{ { - TaskArn: aws.String("task-1"), + TaskArn: awsv2.String("task-1"), }, { - TaskArn: aws.String("task-2"), + TaskArn: awsv2.String("task-2"), }, { - TaskArn: aws.String("task-3"), + TaskArn: awsv2.String("task-3"), }, }, }, @@ -1317,22 +1313,22 @@ func TestECS_RunTask(t *testing.T) { input: runTaskInput, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().RunTask(&ecs.RunTaskInput{ - Cluster: aws.String("my-cluster"), - Count: aws.Int64(3), - LaunchType: aws.String(ecs.LaunchTypeFargate), - StartedBy: aws.String("task"), - TaskDefinition: aws.String("my-task"), - NetworkConfiguration: &ecs.NetworkConfiguration{ - AwsvpcConfiguration: &ecs.AwsVpcConfiguration{ - AssignPublicIp: aws.String(ecs.AssignPublicIpEnabled), - Subnets: aws.StringSlice([]string{"subnet-1", "subnet-2"}), - SecurityGroups: aws.StringSlice([]string{"sg-1", "sg-2"}), + m.EXPECT().RunTask(gomock.Any(), &ecs.RunTaskInput{ + Cluster: awsv2.String("my-cluster"), + Count: awsv2.Int32(int32(3)), + LaunchType: types.LaunchTypeFargate, + StartedBy: awsv2.String("task"), + TaskDefinition: awsv2.String("my-task"), + NetworkConfiguration: &types.NetworkConfiguration{ + AwsvpcConfiguration: &types.AwsVpcConfiguration{ + AssignPublicIp: types.AssignPublicIpEnabled, + Subnets: []string{"subnet-1", "subnet-2"}, + SecurityGroups: []string{"sg-1", "sg-2"}, }, }, - EnableExecuteCommand: aws.Bool(true), - PlatformVersion: aws.String("LATEST"), - PropagateTags: aws.String(ecs.PropagateTagsTaskDefinition), + EnableExecuteCommand: true, + PlatformVersion: awsv2.String("LATEST"), + PropagateTags: types.PropagateTagsTaskDefinition, }). Return(&ecs.RunTaskOutput{}, errors.New("error")) }, @@ -1342,27 +1338,27 @@ func TestECS_RunTask(t *testing.T) { input: runTaskInput, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().RunTask(&ecs.RunTaskInput{ - Cluster: aws.String("my-cluster"), - Count: aws.Int64(3), - LaunchType: aws.String(ecs.LaunchTypeFargate), - StartedBy: aws.String("task"), - TaskDefinition: aws.String("my-task"), - NetworkConfiguration: &ecs.NetworkConfiguration{ - AwsvpcConfiguration: &ecs.AwsVpcConfiguration{ - AssignPublicIp: aws.String(ecs.AssignPublicIpEnabled), - Subnets: aws.StringSlice([]string{"subnet-1", "subnet-2"}), - SecurityGroups: aws.StringSlice([]string{"sg-1", "sg-2"}), + m.EXPECT().RunTask(gomock.Any(), &ecs.RunTaskInput{ + Cluster: awsv2.String("my-cluster"), + Count: awsv2.Int32(int32(3)), + LaunchType: types.LaunchTypeFargate, + StartedBy: awsv2.String("task"), + TaskDefinition: awsv2.String("my-task"), + NetworkConfiguration: &types.NetworkConfiguration{ + AwsvpcConfiguration: &types.AwsVpcConfiguration{ + AssignPublicIp: types.AssignPublicIpEnabled, + Subnets: []string{"subnet-1", "subnet-2"}, + SecurityGroups: []string{"sg-1", "sg-2"}, }, }, - EnableExecuteCommand: aws.Bool(true), - PlatformVersion: aws.String("LATEST"), - PropagateTags: aws.String(ecs.PropagateTagsTaskDefinition), + EnableExecuteCommand: true, + PlatformVersion: awsv2.String("LATEST"), + PropagateTags: types.PropagateTagsTaskDefinition, }). Return(&ecs.RunTaskOutput{ Tasks: ecsTasks, }, nil) - m.EXPECT().WaitUntilTasksRunning(&describeTasksInput).Return(errors.New("some error")) + m.EXPECT().WaitUntilTasksRunning(gomock.Any(), &describeTasksInput, gomock.Any()).Return(errors.New("some error")) }, wantedError: errors.New("wait for tasks to be running: some error"), }, @@ -1370,45 +1366,45 @@ func TestECS_RunTask(t *testing.T) { input: runTaskInput, mockECSClient: func(m *mocks.Mockapi) { - m.EXPECT().RunTask(&ecs.RunTaskInput{ - Cluster: aws.String("my-cluster"), - Count: aws.Int64(3), - LaunchType: aws.String(ecs.LaunchTypeFargate), - StartedBy: aws.String("task"), - TaskDefinition: aws.String("my-task"), - NetworkConfiguration: &ecs.NetworkConfiguration{ - AwsvpcConfiguration: &ecs.AwsVpcConfiguration{ - AssignPublicIp: aws.String(ecs.AssignPublicIpEnabled), - Subnets: aws.StringSlice([]string{"subnet-1", "subnet-2"}), - SecurityGroups: aws.StringSlice([]string{"sg-1", "sg-2"}), + m.EXPECT().RunTask(gomock.Any(), &ecs.RunTaskInput{ + Cluster: awsv2.String("my-cluster"), + Count: awsv2.Int32(int32(3)), + LaunchType: types.LaunchTypeFargate, + StartedBy: awsv2.String("task"), + TaskDefinition: awsv2.String("my-task"), + NetworkConfiguration: &types.NetworkConfiguration{ + AwsvpcConfiguration: &types.AwsVpcConfiguration{ + AssignPublicIp: types.AssignPublicIpEnabled, + Subnets: []string{"subnet-1", "subnet-2"}, + SecurityGroups: []string{"sg-1", "sg-2"}, }, }, - EnableExecuteCommand: aws.Bool(true), - PlatformVersion: aws.String("LATEST"), - PropagateTags: aws.String(ecs.PropagateTagsTaskDefinition), + EnableExecuteCommand: true, + PlatformVersion: awsv2.String("LATEST"), + PropagateTags: types.PropagateTagsTaskDefinition, }). Return(&ecs.RunTaskOutput{ Tasks: ecsTasks}, nil) - m.EXPECT().WaitUntilTasksRunning(&describeTasksInput). - Return(awserr.New(request.WaiterResourceNotReadyErrorCode, "some error", errors.New("some error"))) - m.EXPECT().DescribeTasks(&describeTasksInput).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + m.EXPECT().WaitUntilTasksRunning(gomock.Any(), &describeTasksInput, gomock.Any()). + Return(errors.New("exceeded max wait time for TasksRunning waiter")) + m.EXPECT().DescribeTasks(gomock.Any(), &describeTasksInput).Return(&ecs.DescribeTasksOutput{ + Tasks: []types.Task{ { - TaskArn: aws.String("task-1"), + TaskArn: awsv2.String("task-1"), }, { - TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/4082490ee6c245e09d2145010aa1ba8d"), - StoppedReason: aws.String("Task failed to start"), - LastStatus: aws.String("STOPPED"), - Containers: []*ecs.Container{ + TaskArn: awsv2.String("arn:aws:ecs:us-west-2:123456789:task/4082490ee6c245e09d2145010aa1ba8d"), + StoppedReason: awsv2.String("Task failed to start"), + LastStatus: awsv2.String("STOPPED"), + Containers: []types.Container{ { - Reason: aws.String("CannotPullContainerError: inspect image has been retried 1 time(s)"), - LastStatus: aws.String("STOPPED"), + Reason: awsv2.String("CannotPullContainerError: inspect image has been retried 1 time(s)"), + LastStatus: awsv2.String("STOPPED"), }, }, }, { - TaskArn: aws.String("task-3"), + TaskArn: awsv2.String("task-3"), }, }, }, nil) @@ -1459,43 +1455,43 @@ func TestECS_DescribeTasks(t *testing.T) { }{ "error describing tasks": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String(inCluster), - Tasks: aws.StringSlice(inTaskARNs), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String(inCluster), + Tasks: inTaskARNs, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(nil, errors.New("error describing tasks")) }, wantedError: fmt.Errorf("describe tasks: %w", errors.New("error describing tasks")), }, "successfully described tasks": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().DescribeTasks(&ecs.DescribeTasksInput{ - Cluster: aws.String(inCluster), - Tasks: aws.StringSlice(inTaskARNs), - Include: aws.StringSlice([]string{ecs.TaskFieldTags}), + m.EXPECT().DescribeTasks(gomock.Any(), &ecs.DescribeTasksInput{ + Cluster: awsv2.String(inCluster), + Tasks: inTaskARNs, + Include: []types.TaskField{types.TaskFieldTags}, }).Return(&ecs.DescribeTasksOutput{ - Tasks: []*ecs.Task{ + Tasks: []types.Task{ { - TaskArn: aws.String("task-1"), + TaskArn: awsv2.String("task-1"), }, { - TaskArn: aws.String("task-2"), + TaskArn: awsv2.String("task-2"), }, { - TaskArn: aws.String("task-3"), + TaskArn: awsv2.String("task-3"), }, }, }, nil) }, wantedTasks: []*Task{ { - TaskArn: aws.String("task-1"), + TaskArn: awsv2.String("task-1"), }, { - TaskArn: aws.String("task-2"), + TaskArn: awsv2.String("task-2"), }, { - TaskArn: aws.String("task-3"), + TaskArn: awsv2.String("task-3"), }, }, }, @@ -1526,14 +1522,14 @@ func TestECS_DescribeTasks(t *testing.T) { func TestECS_ExecuteCommand(t *testing.T) { mockExecCmdIn := &ecs.ExecuteCommandInput{ - Cluster: aws.String("mockCluster"), - Command: aws.String("mockCommand"), - Interactive: aws.Bool(true), - Container: aws.String("mockContainer"), - Task: aws.String("mockTask"), + Cluster: awsv2.String("mockCluster"), + Command: awsv2.String("mockCommand"), + Interactive: true, + Container: awsv2.String("mockContainer"), + Task: awsv2.String("mockTask"), } - mockSess := &ecs.Session{ - SessionId: aws.String("mockSessID"), + mockSess := &types.Session{ + SessionId: awsv2.String("mockSessID"), } mockErr := errors.New("some error") testCases := map[string]struct { @@ -1543,19 +1539,19 @@ func TestECS_ExecuteCommand(t *testing.T) { }{ "return error if fail to call ExecuteCommand": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().ExecuteCommand(mockExecCmdIn).Return(nil, mockErr) + m.EXPECT().ExecuteCommand(gomock.Any(), mockExecCmdIn).Return(nil, mockErr) }, mockSessStarter: func(m *mocks.MockssmSessionStarter) {}, wantedError: &ErrExecuteCommand{err: mockErr}, }, "return error if fail to start the session": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().ExecuteCommand(&ecs.ExecuteCommandInput{ - Cluster: aws.String("mockCluster"), - Command: aws.String("mockCommand"), - Interactive: aws.Bool(true), - Container: aws.String("mockContainer"), - Task: aws.String("mockTask"), + m.EXPECT().ExecuteCommand(gomock.Any(), &ecs.ExecuteCommandInput{ + Cluster: awsv2.String("mockCluster"), + Command: awsv2.String("mockCommand"), + Interactive: true, + Container: awsv2.String("mockContainer"), + Task: awsv2.String("mockTask"), }).Return(&ecs.ExecuteCommandOutput{ Session: mockSess, }, nil) @@ -1567,7 +1563,7 @@ func TestECS_ExecuteCommand(t *testing.T) { }, "success": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().ExecuteCommand(mockExecCmdIn).Return(&ecs.ExecuteCommandOutput{ + m.EXPECT().ExecuteCommand(gomock.Any(), mockExecCmdIn).Return(&ecs.ExecuteCommandOutput{ Session: mockSess, }, nil) }, @@ -1618,18 +1614,18 @@ func TestECS_NetworkConfiguration(t *testing.T) { }{ "success": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("crowded-cluster"), - Services: aws.StringSlice([]string{"cool-service"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("crowded-cluster"), + Services: []string{"cool-service"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("cool-service"), - NetworkConfiguration: &ecs.NetworkConfiguration{ - AwsvpcConfiguration: &ecs.AwsVpcConfiguration{ - AssignPublicIp: aws.String("1.2.3.4"), - SecurityGroups: aws.StringSlice([]string{"sg-1", "sg-2"}), - Subnets: aws.StringSlice([]string{"sbn-1", "sbn-2"}), + ServiceName: awsv2.String("cool-service"), + NetworkConfiguration: &types.NetworkConfiguration{ + AwsvpcConfiguration: &types.AwsVpcConfiguration{ + AssignPublicIp: types.AssignPublicIp("1.2.3.4"), + SecurityGroups: []string{"sg-1", "sg-2"}, + Subnets: []string{"sbn-1", "sbn-2"}, }, }, }, @@ -1644,22 +1640,22 @@ func TestECS_NetworkConfiguration(t *testing.T) { }, "fail to describe service": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("crowded-cluster"), - Services: aws.StringSlice([]string{"cool-service"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("crowded-cluster"), + Services: []string{"cool-service"}, }).Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("describe service cool-service: some error"), }, "fail to find awsvpc configuration": { mockAPI: func(m *mocks.Mockapi) { - m.EXPECT().DescribeServices(&ecs.DescribeServicesInput{ - Cluster: aws.String("crowded-cluster"), - Services: aws.StringSlice([]string{"cool-service"}), + m.EXPECT().DescribeServices(gomock.Any(), &ecs.DescribeServicesInput{ + Cluster: awsv2.String("crowded-cluster"), + Services: []string{"cool-service"}, }).Return(&ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { - ServiceName: aws.String("cool-service"), + ServiceName: awsv2.String("cool-service"), }, }, }, nil) diff --git a/internal/pkg/aws/ecs/errors.go b/internal/pkg/aws/ecs/errors.go index 8544fb54327..415de24851d 100644 --- a/internal/pkg/aws/ecs/errors.go +++ b/internal/pkg/aws/ecs/errors.go @@ -7,13 +7,13 @@ import ( "errors" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" ) const ( // DesiredStatusStopped represents the desired status "STOPPED" for a task. - DesiredStatusStopped = ecs.DesiredStatusStopped + DesiredStatusStopped = string(types.DesiredStatusStopped) fmtErrTaskStopped = "task %s: %s" ) @@ -43,23 +43,23 @@ type ErrWaiterResourceNotReadyForTasks struct { func (e *ErrWaiterResourceNotReadyForTasks) Error() string { for _, task := range e.tasks { - if aws.StringValue(task.LastStatus) != DesiredStatusStopped { + if awsv2.ToString(task.LastStatus) != DesiredStatusStopped { continue } - taskID, err := TaskID(aws.StringValue(task.TaskArn)) + taskID, err := TaskID(awsv2.ToString(task.TaskArn)) if err != nil { return err.Error() } // Combine both task stop reason and container stop reason. var errMsg string if task.StoppedReason != nil { - errMsg = aws.StringValue(task.StoppedReason) + errMsg = awsv2.ToString(task.StoppedReason) } // TODO: generalize this to be any essential container. container := task.Containers[0] // NOTE: right now we only support one container per task - if aws.StringValue(container.LastStatus) == DesiredStatusStopped { + if awsv2.ToString(container.LastStatus) == DesiredStatusStopped { if container.Reason != nil { - errMsg = fmt.Sprintf("%s: %s", errMsg, aws.StringValue(container.Reason)) + errMsg = fmt.Sprintf("%s: %s", errMsg, awsv2.ToString(container.Reason)) } } if errMsg != "" { diff --git a/internal/pkg/aws/ecs/mocks/mock_ecs.go b/internal/pkg/aws/ecs/mocks/mock_ecs.go index cd63d4c4f8b..c173cbf78fd 100644 --- a/internal/pkg/aws/ecs/mocks/mock_ecs.go +++ b/internal/pkg/aws/ecs/mocks/mock_ecs.go @@ -5,9 +5,12 @@ package mocks import ( + context "context" reflect "reflect" + time "time" - ecs "github.com/aws/aws-sdk-go/service/ecs" + ecs "github.com/aws/aws-sdk-go-v2/service/ecs" + types "github.com/aws/aws-sdk-go-v2/service/ecs/types" gomock "github.com/golang/mock/gomock" ) @@ -35,166 +38,222 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // DescribeClusters mocks base method. -func (m *Mockapi) DescribeClusters(input *ecs.DescribeClustersInput) (*ecs.DescribeClustersOutput, error) { +func (m *Mockapi) DescribeClusters(ctx context.Context, input *ecs.DescribeClustersInput, opts ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeClusters", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeClusters", varargs...) ret0, _ := ret[0].(*ecs.DescribeClustersOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeClusters indicates an expected call of DescribeClusters. -func (mr *MockapiMockRecorder) DescribeClusters(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeClusters(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeClusters", reflect.TypeOf((*Mockapi)(nil).DescribeClusters), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeClusters", reflect.TypeOf((*Mockapi)(nil).DescribeClusters), varargs...) } // DescribeServices mocks base method. -func (m *Mockapi) DescribeServices(input *ecs.DescribeServicesInput) (*ecs.DescribeServicesOutput, error) { +func (m *Mockapi) DescribeServices(ctx context.Context, input *ecs.DescribeServicesInput, opts ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeServices", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeServices", varargs...) ret0, _ := ret[0].(*ecs.DescribeServicesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeServices indicates an expected call of DescribeServices. -func (mr *MockapiMockRecorder) DescribeServices(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeServices(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeServices", reflect.TypeOf((*Mockapi)(nil).DescribeServices), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeServices", reflect.TypeOf((*Mockapi)(nil).DescribeServices), varargs...) } // DescribeTaskDefinition mocks base method. -func (m *Mockapi) DescribeTaskDefinition(input *ecs.DescribeTaskDefinitionInput) (*ecs.DescribeTaskDefinitionOutput, error) { +func (m *Mockapi) DescribeTaskDefinition(ctx context.Context, input *ecs.DescribeTaskDefinitionInput, opts ...func(*ecs.Options)) (*ecs.DescribeTaskDefinitionOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeTaskDefinition", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeTaskDefinition", varargs...) ret0, _ := ret[0].(*ecs.DescribeTaskDefinitionOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeTaskDefinition indicates an expected call of DescribeTaskDefinition. -func (mr *MockapiMockRecorder) DescribeTaskDefinition(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeTaskDefinition(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTaskDefinition", reflect.TypeOf((*Mockapi)(nil).DescribeTaskDefinition), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTaskDefinition", reflect.TypeOf((*Mockapi)(nil).DescribeTaskDefinition), varargs...) } // DescribeTasks mocks base method. -func (m *Mockapi) DescribeTasks(input *ecs.DescribeTasksInput) (*ecs.DescribeTasksOutput, error) { +func (m *Mockapi) DescribeTasks(ctx context.Context, input *ecs.DescribeTasksInput, opts ...func(*ecs.Options)) (*ecs.DescribeTasksOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeTasks", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeTasks", varargs...) ret0, _ := ret[0].(*ecs.DescribeTasksOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeTasks indicates an expected call of DescribeTasks. -func (mr *MockapiMockRecorder) DescribeTasks(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeTasks(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTasks", reflect.TypeOf((*Mockapi)(nil).DescribeTasks), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeTasks", reflect.TypeOf((*Mockapi)(nil).DescribeTasks), varargs...) } // ExecuteCommand mocks base method. -func (m *Mockapi) ExecuteCommand(input *ecs.ExecuteCommandInput) (*ecs.ExecuteCommandOutput, error) { +func (m *Mockapi) ExecuteCommand(ctx context.Context, input *ecs.ExecuteCommandInput, opts ...func(*ecs.Options)) (*ecs.ExecuteCommandOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExecuteCommand", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExecuteCommand", varargs...) ret0, _ := ret[0].(*ecs.ExecuteCommandOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ExecuteCommand indicates an expected call of ExecuteCommand. -func (mr *MockapiMockRecorder) ExecuteCommand(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ExecuteCommand(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteCommand", reflect.TypeOf((*Mockapi)(nil).ExecuteCommand), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteCommand", reflect.TypeOf((*Mockapi)(nil).ExecuteCommand), varargs...) } -// ListServicesByNamespacePages mocks base method. -func (m *Mockapi) ListServicesByNamespacePages(input *ecs.ListServicesByNamespaceInput, fn func(*ecs.ListServicesByNamespaceOutput, bool) bool) error { +// ListServicesByNamespace mocks base method. +func (m *Mockapi) ListServicesByNamespace(ctx context.Context, input *ecs.ListServicesByNamespaceInput, opts ...func(*ecs.Options)) (*ecs.ListServicesByNamespaceOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListServicesByNamespacePages", input, fn) - ret0, _ := ret[0].(error) - return ret0 + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListServicesByNamespace", varargs...) + ret0, _ := ret[0].(*ecs.ListServicesByNamespaceOutput) + ret1, _ := ret[1].(error) + return ret0, ret1 } -// ListServicesByNamespacePages indicates an expected call of ListServicesByNamespacePages. -func (mr *MockapiMockRecorder) ListServicesByNamespacePages(input, fn interface{}) *gomock.Call { +// ListServicesByNamespace indicates an expected call of ListServicesByNamespace. +func (mr *MockapiMockRecorder) ListServicesByNamespace(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServicesByNamespacePages", reflect.TypeOf((*Mockapi)(nil).ListServicesByNamespacePages), input, fn) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListServicesByNamespace", reflect.TypeOf((*Mockapi)(nil).ListServicesByNamespace), varargs...) } // ListTasks mocks base method. -func (m *Mockapi) ListTasks(input *ecs.ListTasksInput) (*ecs.ListTasksOutput, error) { +func (m *Mockapi) ListTasks(ctx context.Context, input *ecs.ListTasksInput, opts ...func(*ecs.Options)) (*ecs.ListTasksOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListTasks", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListTasks", varargs...) ret0, _ := ret[0].(*ecs.ListTasksOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListTasks indicates an expected call of ListTasks. -func (mr *MockapiMockRecorder) ListTasks(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListTasks(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTasks", reflect.TypeOf((*Mockapi)(nil).ListTasks), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTasks", reflect.TypeOf((*Mockapi)(nil).ListTasks), varargs...) } // RunTask mocks base method. -func (m *Mockapi) RunTask(input *ecs.RunTaskInput) (*ecs.RunTaskOutput, error) { +func (m *Mockapi) RunTask(ctx context.Context, input *ecs.RunTaskInput, opts ...func(*ecs.Options)) (*ecs.RunTaskOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RunTask", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "RunTask", varargs...) ret0, _ := ret[0].(*ecs.RunTaskOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // RunTask indicates an expected call of RunTask. -func (mr *MockapiMockRecorder) RunTask(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) RunTask(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunTask", reflect.TypeOf((*Mockapi)(nil).RunTask), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunTask", reflect.TypeOf((*Mockapi)(nil).RunTask), varargs...) } // StopTask mocks base method. -func (m *Mockapi) StopTask(input *ecs.StopTaskInput) (*ecs.StopTaskOutput, error) { +func (m *Mockapi) StopTask(ctx context.Context, input *ecs.StopTaskInput, opts ...func(*ecs.Options)) (*ecs.StopTaskOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "StopTask", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "StopTask", varargs...) ret0, _ := ret[0].(*ecs.StopTaskOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // StopTask indicates an expected call of StopTask. -func (mr *MockapiMockRecorder) StopTask(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) StopTask(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopTask", reflect.TypeOf((*Mockapi)(nil).StopTask), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopTask", reflect.TypeOf((*Mockapi)(nil).StopTask), varargs...) } // UpdateService mocks base method. -func (m *Mockapi) UpdateService(input *ecs.UpdateServiceInput) (*ecs.UpdateServiceOutput, error) { +func (m *Mockapi) UpdateService(ctx context.Context, input *ecs.UpdateServiceInput, opts ...func(*ecs.Options)) (*ecs.UpdateServiceOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateService", input) + varargs := []interface{}{ctx, input} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "UpdateService", varargs...) ret0, _ := ret[0].(*ecs.UpdateServiceOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // UpdateService indicates an expected call of UpdateService. -func (mr *MockapiMockRecorder) UpdateService(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) UpdateService(ctx, input interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateService", reflect.TypeOf((*Mockapi)(nil).UpdateService), input) + varargs := append([]interface{}{ctx, input}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateService", reflect.TypeOf((*Mockapi)(nil).UpdateService), varargs...) } // WaitUntilTasksRunning mocks base method. -func (m *Mockapi) WaitUntilTasksRunning(input *ecs.DescribeTasksInput) error { +func (m *Mockapi) WaitUntilTasksRunning(ctx context.Context, input *ecs.DescribeTasksInput, maxWaitDur time.Duration, opts ...func(*ecs.TasksRunningWaiterOptions)) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "WaitUntilTasksRunning", input) + varargs := []interface{}{ctx, input, maxWaitDur} + for _, a := range opts { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "WaitUntilTasksRunning", varargs...) ret0, _ := ret[0].(error) return ret0 } // WaitUntilTasksRunning indicates an expected call of WaitUntilTasksRunning. -func (mr *MockapiMockRecorder) WaitUntilTasksRunning(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) WaitUntilTasksRunning(ctx, input, maxWaitDur interface{}, opts ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilTasksRunning", reflect.TypeOf((*Mockapi)(nil).WaitUntilTasksRunning), input) + varargs := append([]interface{}{ctx, input, maxWaitDur}, opts...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilTasksRunning", reflect.TypeOf((*Mockapi)(nil).WaitUntilTasksRunning), varargs...) } // MockssmSessionStarter is a mock of ssmSessionStarter interface. @@ -221,7 +280,7 @@ func (m *MockssmSessionStarter) EXPECT() *MockssmSessionStarterMockRecorder { } // StartSession mocks base method. -func (m *MockssmSessionStarter) StartSession(ssmSession *ecs.Session) error { +func (m *MockssmSessionStarter) StartSession(ssmSession *types.Session) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "StartSession", ssmSession) ret0, _ := ret[0].(error) diff --git a/internal/pkg/aws/ecs/service.go b/internal/pkg/aws/ecs/service.go index ecab627aad5..69b0247faa3 100644 --- a/internal/pkg/aws/ecs/service.go +++ b/internal/pkg/aws/ecs/service.go @@ -9,9 +9,9 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" ) const ( @@ -22,7 +22,7 @@ const ( ) // Service wraps up ECS Service struct. -type Service ecs.Service +type Service types.Service // Deployment contains information of a ECS service Deployment. type Deployment struct { @@ -50,23 +50,23 @@ func (s *Service) ServiceStatus() ServiceStatus { var deployments []Deployment for _, dp := range s.Deployments { deployments = append(deployments, Deployment{ - Id: aws.StringValue(dp.Id), - DesiredCount: aws.Int64Value(dp.DesiredCount), - RunningCount: aws.Int64Value(dp.RunningCount), - UpdatedAt: aws.TimeValue(dp.UpdatedAt), - LaunchType: aws.StringValue(dp.LaunchType), - TaskDefinition: aws.StringValue(dp.TaskDefinition), - Status: aws.StringValue(dp.Status), + Id: awsv2.ToString(dp.Id), + DesiredCount: int64(dp.DesiredCount), + RunningCount: int64(dp.RunningCount), + UpdatedAt: awsv2.ToTime(dp.UpdatedAt), + LaunchType: string(dp.LaunchType), + TaskDefinition: awsv2.ToString(dp.TaskDefinition), + Status: awsv2.ToString(dp.Status), }) } return ServiceStatus{ - Status: aws.StringValue(s.Status), - DesiredCount: aws.Int64Value(s.DesiredCount), - RunningCount: aws.Int64Value(s.RunningCount), + Status: awsv2.ToString(s.Status), + DesiredCount: int64(s.DesiredCount), + RunningCount: int64(s.RunningCount), Deployments: deployments, - LastDeploymentAt: aws.TimeValue(s.Deployments[0].UpdatedAt), // FIXME Service assumed to have at least one deployment - TaskDefinition: aws.StringValue(s.Deployments[0].TaskDefinition), + LastDeploymentAt: awsv2.ToTime(s.Deployments[0].UpdatedAt), // FIXME Service assumed to have at least one deployment + TaskDefinition: awsv2.ToString(s.Deployments[0].TaskDefinition), } } @@ -77,26 +77,26 @@ func (s *Service) ServiceConnectAliases() []string { } lastDeployment := s.Deployments[0] scConfig := lastDeployment.ServiceConnectConfiguration - if scConfig == nil || !aws.BoolValue(scConfig.Enabled) { + if scConfig == nil || !scConfig.Enabled { return nil } var aliases []string for _, service := range scConfig.Services { - defaultName := aws.StringValue(service.PortName) - if aws.StringValue(service.DiscoveryName) != "" { - defaultName = aws.StringValue(service.DiscoveryName) + defaultName := awsv2.ToString(service.PortName) + if awsv2.ToString(service.DiscoveryName) != "" { + defaultName = awsv2.ToString(service.DiscoveryName) } - defaultAlias := fmt.Sprintf("%s.%s", defaultName, aws.StringValue(scConfig.Namespace)) + defaultAlias := fmt.Sprintf("%s.%s", defaultName, awsv2.ToString(scConfig.Namespace)) if len(service.ClientAliases) == 0 { aliases = append(aliases, defaultAlias) continue } for _, clientAlias := range service.ClientAliases { alias := defaultAlias - if aws.StringValue(clientAlias.DnsName) != "" { - alias = aws.StringValue(clientAlias.DnsName) + if awsv2.ToString(clientAlias.DnsName) != "" { + alias = awsv2.ToString(clientAlias.DnsName) } - aliases = append(aliases, fmt.Sprintf("%s:%v", alias, aws.Int64Value(clientAlias.Port))) + aliases = append(aliases, fmt.Sprintf("%s:%v", alias, awsv2.ToInt32(clientAlias.Port))) } } return aliases @@ -104,14 +104,14 @@ func (s *Service) ServiceConnectAliases() []string { // LastUpdatedAt returns the last updated time of the ECS service. func (s *Service) LastUpdatedAt() time.Time { - return aws.TimeValue(s.Deployments[0].UpdatedAt) + return awsv2.ToTime(s.Deployments[0].UpdatedAt) } // TargetGroups returns the ARNs of target groups attached to the service. func (s *Service) TargetGroups() []string { var targetGroupARNs []string for _, lb := range s.LoadBalancers { - targetGroupARNs = append(targetGroupARNs, aws.StringValue(lb.TargetGroupArn)) + targetGroupARNs = append(targetGroupARNs, awsv2.ToString(lb.TargetGroupArn)) } return targetGroupARNs } diff --git a/internal/pkg/aws/ecs/service_test.go b/internal/pkg/aws/ecs/service_test.go index cb6eef49de1..c0fc7437899 100644 --- a/internal/pkg/aws/ecs/service_test.go +++ b/internal/pkg/aws/ecs/service_test.go @@ -8,20 +8,20 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/stretchr/testify/require" ) func TestService_TargetGroups(t *testing.T) { t.Run("should return correct ARNs", func(t *testing.T) { s := Service{ - LoadBalancers: []*ecs.LoadBalancer{ + LoadBalancers: []types.LoadBalancer{ { - TargetGroupArn: aws.String("group-1"), + TargetGroupArn: awsv2.String("group-1"), }, { - TargetGroupArn: aws.String("group-2"), + TargetGroupArn: awsv2.String("group-2"), }, }, } @@ -34,28 +34,28 @@ func TestService_TargetGroups(t *testing.T) { func TestService_ServiceStatus(t *testing.T) { t.Run("should include active and primary deployments in status", func(t *testing.T) { inService := Service{ - Deployments: []*ecs.Deployment{ + Deployments: []types.Deployment{ { - Status: aws.String("ACTIVE"), - Id: aws.String("id-1"), - DesiredCount: aws.Int64(3), - RunningCount: aws.Int64(3), + Status: awsv2.String("ACTIVE"), + Id: awsv2.String("id-1"), + DesiredCount: 3, + RunningCount: 3, }, { - Status: aws.String("ACTIVE"), - Id: aws.String("id-3"), - DesiredCount: aws.Int64(4), - RunningCount: aws.Int64(2), + Status: awsv2.String("ACTIVE"), + Id: awsv2.String("id-3"), + DesiredCount: 4, + RunningCount: 2, }, { - Status: aws.String("PRIMARY"), - Id: aws.String("id-4"), - DesiredCount: aws.Int64(10), - RunningCount: aws.Int64(1), + Status: awsv2.String("PRIMARY"), + Id: awsv2.String("id-4"), + DesiredCount: 10, + RunningCount: 1, }, { - Status: aws.String("INACTIVE"), - Id: aws.String("id-5"), + Status: awsv2.String("INACTIVE"), + Id: awsv2.String("id-5"), }, }, } @@ -100,7 +100,7 @@ func TestService_LastUpdatedAt(t *testing.T) { mockTime2 := time.Unix(14945059, 0) t.Run("should return correct last updated value", func(t *testing.T) { s := Service{ - Deployments: []*ecs.Deployment{ + Deployments: []types.Deployment{ { UpdatedAt: &mockTime1, }, @@ -123,10 +123,10 @@ func TestService_ServiceConnectAliases(t *testing.T) { }{ "quit early if not enabled": { inService: &Service{ - Deployments: []*ecs.Deployment{ + Deployments: []types.Deployment{ { - ServiceConnectConfiguration: &ecs.ServiceConnectConfiguration{ - Enabled: aws.Bool(false), + ServiceConnectConfiguration: &types.ServiceConnectConfiguration{ + Enabled: false, }, }, }, @@ -135,28 +135,28 @@ func TestService_ServiceConnectAliases(t *testing.T) { }, "success": { inService: &Service{ - Deployments: []*ecs.Deployment{ + Deployments: []types.Deployment{ { - ServiceConnectConfiguration: &ecs.ServiceConnectConfiguration{ - Enabled: aws.Bool(true), - Namespace: aws.String("foobar.local"), - Services: []*ecs.ServiceConnectService{ + ServiceConnectConfiguration: &types.ServiceConnectConfiguration{ + Enabled: true, + Namespace: awsv2.String("foobar.local"), + Services: []types.ServiceConnectService{ { - PortName: aws.String("frontend"), - DiscoveryName: aws.String("front"), + PortName: awsv2.String("frontend"), + DiscoveryName: awsv2.String("front"), }, { - PortName: aws.String("frontend"), + PortName: awsv2.String("frontend"), }, { - PortName: aws.String("frontend"), - ClientAliases: []*ecs.ServiceConnectClientAlias{ + PortName: awsv2.String("frontend"), + ClientAliases: []types.ServiceConnectClientAlias{ { - Port: aws.Int64(5000), + Port: awsv2.Int32(5000), }, { - DnsName: aws.String("api"), - Port: aws.Int64(80), + DnsName: awsv2.String("api"), + Port: awsv2.Int32(80), }, }, }, diff --git a/internal/pkg/aws/ecs/task.go b/internal/pkg/aws/ecs/task.go index 4a982cf315f..b792e3ee555 100644 --- a/internal/pkg/aws/ecs/task.go +++ b/internal/pkg/aws/ecs/task.go @@ -10,9 +10,9 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" ) const ( @@ -26,11 +26,11 @@ const ( networkInterfaceAttachmentType = "ElasticNetworkInterface" // TaskContainerHealthStatusUnknown wraps the ECS health status UNKNOWN. - TaskContainerHealthStatusUnknown = ecs.HealthStatusUnknown + TaskContainerHealthStatusUnknown = string(types.HealthStatusUnknown) // TaskContainerHealthStatusHealthy wraps the ECS health status HEALTHY. - TaskContainerHealthStatusHealthy = ecs.HealthStatusHealthy + TaskContainerHealthStatusHealthy = string(types.HealthStatusHealthy) // TaskContainerHealthStatusUnhealthy wraps the ECS health status UNHEALTHY. - TaskContainerHealthStatusUnhealthy = ecs.HealthStatusUnhealthy + TaskContainerHealthStatusUnhealthy = string(types.HealthStatusUnhealthy) // TaskCapacityProviderFargate is the capacity provider name for FARGATE. TaskCapacityProviderFargate = "FARGATE" @@ -47,22 +47,22 @@ type Image struct { } // Task wraps up ECS Task struct. -type Task ecs.Task +type Task types.Task // String returns the human readable format of an ECS task. // For example, a task with ARN arn:aws:ecs:us-west-2:123456789:task/4082490ee6c245e09d2145010aa1ba8d // and task definition ARN arn:aws:ecs:us-west-2:123456789012:task-definition/sample-fargate:2 // becomes "4082490e (sample-fargate:2)" func (t Task) String() string { - taskID, _ := TaskID(aws.StringValue(t.TaskArn)) + taskID, _ := TaskID(awsv2.ToString(t.TaskArn)) taskID = ShortTaskID(taskID) - taskDefName, _ := taskDefinitionName(aws.StringValue(t.TaskDefinitionArn)) + taskDefName, _ := taskDefinitionName(awsv2.ToString(t.TaskDefinitionArn)) return fmt.Sprintf("%s (%s)", taskID, taskDefName) } // TaskStatus returns the status of the running task. func (t *Task) TaskStatus() (*TaskStatus, error) { - taskID, err := TaskID(aws.StringValue(t.TaskArn)) + taskID, err := TaskID(awsv2.ToString(t.TaskArn)) if err != nil { return nil, err } @@ -76,25 +76,25 @@ func (t *Task) TaskStatus() (*TaskStatus, error) { startedAt = *t.StartedAt } if t.StoppedReason != nil { - stoppedReason = aws.StringValue(t.StoppedReason) + stoppedReason = awsv2.ToString(t.StoppedReason) } var images []Image for _, container := range t.Containers { images = append(images, Image{ - ID: aws.StringValue(container.Image), - Digest: imageDigestValue(aws.StringValue(container.ImageDigest)), + ID: awsv2.ToString(container.Image), + Digest: imageDigestValue(awsv2.ToString(container.ImageDigest)), }) } return &TaskStatus{ - Health: aws.StringValue(t.HealthStatus), + Health: string(t.HealthStatus), ID: taskID, Images: images, - LastStatus: aws.StringValue(t.LastStatus), + LastStatus: awsv2.ToString(t.LastStatus), StartedAt: startedAt, StoppedAt: stoppedAt, StoppedReason: stoppedReason, - CapacityProvider: aws.StringValue(t.CapacityProviderName), - TaskDefinition: aws.StringValue(t.TaskDefinitionArn), + CapacityProvider: awsv2.ToString(t.CapacityProviderName), + TaskDefinition: awsv2.ToString(t.TaskDefinitionArn), }, nil } @@ -107,13 +107,13 @@ func (t *Task) ENI() (string, error) { } for _, detail := range attachmentENI.Details { - if aws.StringValue(detail.Name) == networkInterfaceIDKey { - return aws.StringValue(detail.Value), nil + if awsv2.ToString(detail.Name) == networkInterfaceIDKey { + return awsv2.ToString(detail.Value), nil } } return "", &ErrTaskENIInfoNotFound{ MissingField: missingFieldDetailENIID, - TaskARN: aws.StringValue(t.TaskArn), + TaskARN: awsv2.ToString(t.TaskArn), } } @@ -124,30 +124,30 @@ func (t *Task) PrivateIP() (string, error) { return "", err } for _, detail := range attachmentENI.Details { - if aws.StringValue(detail.Name) == privateIPv4AddressKey { - return aws.StringValue(detail.Value), nil + if awsv2.ToString(detail.Name) == privateIPv4AddressKey { + return awsv2.ToString(detail.Value), nil } } return "", &ErrTaskENIInfoNotFound{ MissingField: missingFieldPrivateIPv4Address, - TaskARN: aws.StringValue(t.TaskArn), + TaskARN: awsv2.ToString(t.TaskArn), } } -func (t *Task) attachmentENI() (*ecs.Attachment, error) { +func (t *Task) attachmentENI() (*types.Attachment, error) { // Every Fargate task is provided with an ENI by default (https://docs.aws.amazon.com/AmazonECS/latest/userguide/fargate-task-networking.html). // So an error is warranted if there is no ENI found. - var attachmentENI *ecs.Attachment - for _, attachment := range t.Attachments { - if aws.StringValue(attachment.Type) == networkInterfaceAttachmentType { - attachmentENI = attachment + var attachmentENI *types.Attachment + for i := range t.Attachments { + if awsv2.ToString(t.Attachments[i].Type) == networkInterfaceAttachmentType { + attachmentENI = &t.Attachments[i] break } } if attachmentENI == nil { return nil, &ErrTaskENIInfoNotFound{ MissingField: missingFieldAttachment, - TaskARN: aws.StringValue(t.TaskArn), + TaskARN: awsv2.ToString(t.TaskArn), } } return attachmentENI, nil @@ -167,7 +167,7 @@ type TaskStatus struct { } // TaskDefinition wraps up ECS TaskDefinition struct. -type TaskDefinition ecs.TaskDefinition +type TaskDefinition types.TaskDefinition // ContainerPlatform holds basic info of a container's platform. type ContainerPlatform struct { @@ -181,8 +181,8 @@ func (t *TaskDefinition) Platform() *ContainerPlatform { return nil } return &ContainerPlatform{ - OperatingSystem: aws.StringValue(t.RuntimePlatform.OperatingSystemFamily), - Architecture: aws.StringValue(t.RuntimePlatform.CpuArchitecture), + OperatingSystem: string(t.RuntimePlatform.OperatingSystemFamily), + Architecture: string(t.RuntimePlatform.CpuArchitecture), } } @@ -199,9 +199,9 @@ func (t *TaskDefinition) EnvironmentVariables() []*ContainerEnvVar { for _, container := range t.ContainerDefinitions { for _, env := range container.Environment { envs = append(envs, &ContainerEnvVar{ - aws.StringValue(env.Name), - aws.StringValue(container.Name), - aws.StringValue(env.Value), + awsv2.ToString(env.Name), + awsv2.ToString(container.Name), + awsv2.ToString(env.Value), }) } } @@ -221,9 +221,9 @@ func (t *TaskDefinition) Secrets() []*ContainerSecret { for _, container := range t.ContainerDefinitions { for _, secret := range container.Secrets { secrets = append(secrets, &ContainerSecret{ - aws.StringValue(secret.Name), - aws.StringValue(container.Name), - aws.StringValue(secret.ValueFrom), + awsv2.ToString(secret.Name), + awsv2.ToString(container.Name), + awsv2.ToString(secret.ValueFrom), }) } } @@ -233,8 +233,8 @@ func (t *TaskDefinition) Secrets() []*ContainerSecret { // Image returns the container's image of the task definition. func (t *TaskDefinition) Image(containerName string) (string, error) { for _, container := range t.ContainerDefinitions { - if aws.StringValue(container.Name) == containerName { - return aws.StringValue(container.Image), nil + if awsv2.ToString(container.Name) == containerName { + return awsv2.ToString(container.Image), nil } } return "", fmt.Errorf("container %s not found", containerName) @@ -243,8 +243,8 @@ func (t *TaskDefinition) Image(containerName string) (string, error) { // Command returns the container's command overrides of the task definition. func (t *TaskDefinition) Command(containerName string) ([]string, error) { for _, container := range t.ContainerDefinitions { - if aws.StringValue(container.Name) == containerName { - return aws.StringValueSlice(container.Command), nil + if awsv2.ToString(container.Name) == containerName { + return container.Command, nil } } return nil, fmt.Errorf("container %s not found", containerName) @@ -253,8 +253,8 @@ func (t *TaskDefinition) Command(containerName string) ([]string, error) { // EntryPoint returns the container's entrypoint overrides of the task definition. func (t *TaskDefinition) EntryPoint(containerName string) ([]string, error) { for _, container := range t.ContainerDefinitions { - if aws.StringValue(container.Name) == containerName { - return aws.StringValueSlice(container.EntryPoint), nil + if awsv2.ToString(container.Name) == containerName { + return container.EntryPoint, nil } } return nil, fmt.Errorf("container %s not found", containerName) @@ -304,7 +304,7 @@ func ShortTaskID(id string) string { func FilterRunningTasks(tasks []*Task) []*Task { var filtered []*Task for _, task := range tasks { - if aws.StringValue(task.LastStatus) == lastStatusRunning { + if awsv2.ToString(task.LastStatus) == lastStatusRunning { filtered = append(filtered, task) } } diff --git a/internal/pkg/aws/ecs/task_test.go b/internal/pkg/aws/ecs/task_test.go index 3bbd75e46f2..bb2cafe3daa 100644 --- a/internal/pkg/aws/ecs/task_test.go +++ b/internal/pkg/aws/ecs/task_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -20,9 +20,9 @@ func TestTask_TaskStatus(t *testing.T) { stopTime, _ := time.Parse(time.RFC3339, "2006-01-02T16:04:05+00:00") mockImageDigest := "18f7eb6cff6e63e5f5273fb53f672975fe6044580f66c354f55d2de8dd28aec7" testCases := map[string]struct { - health *string + health types.HealthStatus taskArn *string - containers []*ecs.Container + containers []types.Container lastStatus *string startedAt time.Time stoppedAt time.Time @@ -32,19 +32,19 @@ func TestTask_TaskStatus(t *testing.T) { wantErr error }{ "errors if failed to parse task ID": { - taskArn: aws.String("badTaskArn"), + taskArn: awsv2.String("badTaskArn"), wantErr: fmt.Errorf("parse ECS task ARN: arn: invalid prefix"), }, "success with a provisioning task": { - taskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d"), - containers: []*ecs.Container{ + taskArn: awsv2.String("arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d"), + containers: []types.Container{ { - Image: aws.String("mockImageArn"), - ImageDigest: aws.String("sha256:" + mockImageDigest), + Image: awsv2.String("mockImageArn"), + ImageDigest: awsv2.String("sha256:" + mockImageDigest), }, }, - health: aws.String("HEALTHY"), - lastStatus: aws.String("UNKNOWN"), + health: types.HealthStatusHealthy, + lastStatus: awsv2.String("UNKNOWN"), wantTaskStatus: &TaskStatus{ Health: "HEALTHY", @@ -59,15 +59,15 @@ func TestTask_TaskStatus(t *testing.T) { }, }, "success with a running task": { - taskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d"), - containers: []*ecs.Container{ + taskArn: awsv2.String("arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d"), + containers: []types.Container{ { - Image: aws.String("mockImageArn"), - ImageDigest: aws.String("sha256:" + mockImageDigest), + Image: awsv2.String("mockImageArn"), + ImageDigest: awsv2.String("sha256:" + mockImageDigest), }, }, - health: aws.String("HEALTHY"), - lastStatus: aws.String("UNKNOWN"), + health: types.HealthStatusHealthy, + lastStatus: awsv2.String("UNKNOWN"), startedAt: startTime, wantTaskStatus: &TaskStatus{ @@ -84,18 +84,18 @@ func TestTask_TaskStatus(t *testing.T) { }, }, "success with a stopped task": { - taskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d"), - containers: []*ecs.Container{ + taskArn: awsv2.String("arn:aws:ecs:us-west-2:123456789:task/my-project-test-Cluster-9F7Y0RLP60R7/4082490ee6c245e09d2145010aa1ba8d"), + containers: []types.Container{ { - Image: aws.String("mockImageArn"), - ImageDigest: aws.String("sha256:" + mockImageDigest), + Image: awsv2.String("mockImageArn"), + ImageDigest: awsv2.String("sha256:" + mockImageDigest), }, }, - health: aws.String("HEALTHY"), - lastStatus: aws.String("UNKNOWN"), + health: types.HealthStatusHealthy, + lastStatus: awsv2.String("UNKNOWN"), startedAt: startTime, stoppedAt: stopTime, - stoppedReason: aws.String("some reason"), + stoppedReason: awsv2.String("some reason"), wantTaskStatus: &TaskStatus{ Health: "HEALTHY", @@ -145,15 +145,15 @@ func TestTask_TaskStatus(t *testing.T) { func TestTask_ENI(t *testing.T) { testCases := map[string]struct { taskARN *string - attachments []*ecs.Attachment + attachments []types.Attachment wantedENI string wantedErr error }{ "no matching attachment": { - taskARN: aws.String("1"), - attachments: []*ecs.Attachment{ + taskARN: awsv2.String("1"), + attachments: []types.Attachment{ { - Type: aws.String("not ElasticNetworkInterface"), + Type: awsv2.String("not ElasticNetworkInterface"), }, }, wantedErr: &ErrTaskENIInfoNotFound{ @@ -162,17 +162,17 @@ func TestTask_ENI(t *testing.T) { }, }, "no matching detail in network interface attachment": { - taskARN: aws.String("1"), - attachments: []*ecs.Attachment{ + taskARN: awsv2.String("1"), + attachments: []types.Attachment{ { - Type: aws.String("not ElasticNetworkInterface"), + Type: awsv2.String("not ElasticNetworkInterface"), }, { - Type: aws.String("ElasticNetworkInterface"), - Details: []*ecs.KeyValuePair{ + Type: awsv2.String("ElasticNetworkInterface"), + Details: []types.KeyValuePair{ { - Name: aws.String("not networkInterfaceId"), - Value: aws.String("val"), + Name: awsv2.String("not networkInterfaceId"), + Value: awsv2.String("val"), }, }, }, @@ -183,21 +183,21 @@ func TestTask_ENI(t *testing.T) { }, }, "successfully retrieve eni id": { - taskARN: aws.String("1"), - attachments: []*ecs.Attachment{ + taskARN: awsv2.String("1"), + attachments: []types.Attachment{ { - Type: aws.String("not ElasticNetworkInterface"), + Type: awsv2.String("not ElasticNetworkInterface"), }, { - Type: aws.String("ElasticNetworkInterface"), - Details: []*ecs.KeyValuePair{ + Type: awsv2.String("ElasticNetworkInterface"), + Details: []types.KeyValuePair{ { - Name: aws.String("not networkInterfaceId"), - Value: aws.String("val"), + Name: awsv2.String("not networkInterfaceId"), + Value: awsv2.String("val"), }, { - Name: aws.String("networkInterfaceId"), - Value: aws.String("eni-123"), + Name: awsv2.String("networkInterfaceId"), + Value: awsv2.String("eni-123"), }, }, }, @@ -227,15 +227,15 @@ func TestTask_ENI(t *testing.T) { func TestTask_PrivateIP(t *testing.T) { testCases := map[string]struct { taskARN *string - attachments []*ecs.Attachment + attachments []types.Attachment wantedENI string wantedErr error }{ "no matching attachment": { - taskARN: aws.String("1"), - attachments: []*ecs.Attachment{ + taskARN: awsv2.String("1"), + attachments: []types.Attachment{ { - Type: aws.String("not ElasticNetworkInterface"), + Type: awsv2.String("not ElasticNetworkInterface"), }, }, wantedErr: &ErrTaskENIInfoNotFound{ @@ -244,17 +244,17 @@ func TestTask_PrivateIP(t *testing.T) { }, }, "no matching detail in network interface attachment": { - taskARN: aws.String("1"), - attachments: []*ecs.Attachment{ + taskARN: awsv2.String("1"), + attachments: []types.Attachment{ { - Type: aws.String("not ElasticNetworkInterface"), + Type: awsv2.String("not ElasticNetworkInterface"), }, { - Type: aws.String("ElasticNetworkInterface"), - Details: []*ecs.KeyValuePair{ + Type: awsv2.String("ElasticNetworkInterface"), + Details: []types.KeyValuePair{ { - Name: aws.String("not privateIPv4Address"), - Value: aws.String("val"), + Name: awsv2.String("not privateIPv4Address"), + Value: awsv2.String("val"), }, }, }, @@ -265,21 +265,21 @@ func TestTask_PrivateIP(t *testing.T) { }, }, "successfully retrieve eni id": { - taskARN: aws.String("1"), - attachments: []*ecs.Attachment{ + taskARN: awsv2.String("1"), + attachments: []types.Attachment{ { - Type: aws.String("not ElasticNetworkInterface"), + Type: awsv2.String("not ElasticNetworkInterface"), }, { - Type: aws.String("ElasticNetworkInterface"), - Details: []*ecs.KeyValuePair{ + Type: awsv2.String("ElasticNetworkInterface"), + Details: []types.KeyValuePair{ { - Name: aws.String("not networkInterfaceId"), - Value: aws.String("val"), + Name: awsv2.String("not networkInterfaceId"), + Value: awsv2.String("val"), }, { - Name: aws.String("privateIPv4Address"), - Value: aws.String("eni-123"), + Name: awsv2.String("privateIPv4Address"), + Value: awsv2.String("eni-123"), }, }, }, @@ -338,24 +338,24 @@ func Test_TaskID(t *testing.T) { func TestTaskDefinition_EnvVars(t *testing.T) { testCases := map[string]struct { - inContainers []*ecs.ContainerDefinition + inContainers []types.ContainerDefinition wantEnvVars []*ContainerEnvVar }{ "should return wrapped error given error; otherwise should return list of ContainerEnvVar objects": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Environment: []*ecs.KeyValuePair{ + Environment: []types.KeyValuePair{ { - Name: aws.String("COPILOT_SERVICE_NAME"), - Value: aws.String("my-svc"), + Name: awsv2.String("COPILOT_SERVICE_NAME"), + Value: awsv2.String("my-svc"), }, { - Name: aws.String("COPILOT_ENVIRONMENT_NAME"), - Value: aws.String("prod"), + Name: awsv2.String("COPILOT_ENVIRONMENT_NAME"), + Value: awsv2.String("prod"), }, }, - Name: aws.String("container"), + Name: awsv2.String("container"), }, }, @@ -394,22 +394,22 @@ func TestTaskDefinition_EnvVars(t *testing.T) { func TestTaskDefinition_Secrets(t *testing.T) { testCases := map[string]struct { - inContainers []*ecs.ContainerDefinition + inContainers []types.ContainerDefinition wantedSecrets []*ContainerSecret }{ "should return secrets of the task definition as a list of ContainerSecret objects": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container"), - Secrets: []*ecs.Secret{ + Name: awsv2.String("container"), + Secrets: []types.Secret{ { - Name: aws.String("GITHUB_WEBHOOK_SECRET"), - ValueFrom: aws.String("GH_WEBHOOK_SECRET"), + Name: awsv2.String("GITHUB_WEBHOOK_SECRET"), + ValueFrom: awsv2.String("GH_WEBHOOK_SECRET"), }, { - Name: aws.String("SOME_OTHER_SECRET"), - ValueFrom: aws.String("SHHHHHHHH"), + Name: awsv2.String("SOME_OTHER_SECRET"), + ValueFrom: awsv2.String("SHHHHHHHH"), }, }, }, @@ -450,35 +450,35 @@ func TestTaskDefinition_Secrets(t *testing.T) { func TestTaskDefinition_Image(t *testing.T) { testCases := map[string]struct { - inContainers []*ecs.ContainerDefinition + inContainers []types.ContainerDefinition inContainerName string wantedImage string wantedError error }{ "should return the container's image": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container-1"), - Image: aws.String("image-1"), + Name: awsv2.String("container-1"), + Image: awsv2.String("image-1"), }, { - Name: aws.String("container-2"), - Image: aws.String("image-2"), + Name: awsv2.String("container-2"), + Image: awsv2.String("image-2"), }, }, inContainerName: "container-2", wantedImage: "image-2", }, "container not found": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container-1"), - Image: aws.String("image-1"), + Name: awsv2.String("container-1"), + Image: awsv2.String("image-1"), }, { - Name: aws.String("container-2"), - Image: aws.String("image-2"), + Name: awsv2.String("container-2"), + Image: awsv2.String("image-2"), }, }, inContainerName: "container-3", @@ -509,38 +509,38 @@ func TestTaskDefinition_Image(t *testing.T) { func TestTaskDefinition_Command(t *testing.T) { testCases := map[string]struct { - inContainers []*ecs.ContainerDefinition + inContainers []types.ContainerDefinition inContainerName string wantedCommand []string wantedError error }{ "should return command overrides of the task definition as a list of ContainerCommand": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container-1"), - Command: aws.StringSlice([]string{"echo", "strikes", "three"}), + Name: awsv2.String("container-1"), + Command: []string{"echo", "strikes", "three"}, }, { - Name: aws.String("container-2"), - Command: aws.StringSlice([]string{"echo", "ball", "four"}), + Name: awsv2.String("container-2"), + Command: []string{"echo", "ball", "four"}, }, { - Name: aws.String("container-3"), + Name: awsv2.String("container-3"), }, }, inContainerName: "container-1", wantedCommand: []string{"echo", "strikes", "three"}, }, "container not found": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container-1"), - Command: aws.StringSlice([]string{"echo", "strikes", "three"}), + Name: awsv2.String("container-1"), + Command: []string{"echo", "strikes", "three"}, }, { - Name: aws.String("container-2"), - Command: aws.StringSlice([]string{"echo", "ball", "four"}), + Name: awsv2.String("container-2"), + Command: []string{"echo", "ball", "four"}, }, }, inContainerName: "container-3", @@ -571,20 +571,20 @@ func TestTaskDefinition_Command(t *testing.T) { func TestTaskDefinition_EntryPoint(t *testing.T) { testCases := map[string]struct { - inContainers []*ecs.ContainerDefinition + inContainers []types.ContainerDefinition inContainerName string wantedEntryPoints []string wantedError error }{ "should return command overrides of the task definition as a list of ContainerCommand": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container-1"), - EntryPoint: aws.StringSlice([]string{"echo", "strikes", "three"}), + Name: awsv2.String("container-1"), + EntryPoint: []string{"echo", "strikes", "three"}, }, { - Name: aws.String("container-2"), + Name: awsv2.String("container-2"), }, }, @@ -592,14 +592,14 @@ func TestTaskDefinition_EntryPoint(t *testing.T) { wantedEntryPoints: []string{"echo", "strikes", "three"}, }, "container not found": { - inContainers: []*ecs.ContainerDefinition{ + inContainers: []types.ContainerDefinition{ { - Name: aws.String("container-1"), - Command: aws.StringSlice([]string{"echo", "strikes", "three"}), + Name: awsv2.String("container-1"), + Command: []string{"echo", "strikes", "three"}, }, { - Name: aws.String("container-2"), - Command: aws.StringSlice([]string{"echo", "ball", "four"}), + Name: awsv2.String("container-2"), + Command: []string{"echo", "ball", "four"}, }, }, inContainerName: "container-3", @@ -665,18 +665,18 @@ func TestFilterRunningTasks(t *testing.T) { "should return only running tasks": { inTasks: []*Task{ { - TaskArn: aws.String("mockTask1"), - LastStatus: aws.String("STOPPED"), + TaskArn: awsv2.String("mockTask1"), + LastStatus: awsv2.String("STOPPED"), }, { - TaskArn: aws.String("mockTask2"), - LastStatus: aws.String("RUNNING"), + TaskArn: awsv2.String("mockTask2"), + LastStatus: awsv2.String("RUNNING"), }, }, wantedTasks: []*Task{ { - TaskArn: aws.String("mockTask2"), - LastStatus: aws.String("RUNNING"), + TaskArn: awsv2.String("mockTask2"), + LastStatus: awsv2.String("RUNNING"), }, }, }, diff --git a/internal/pkg/aws/s3/mocks/mock_s3.go b/internal/pkg/aws/s3/mocks/mock_s3.go index 5361e364c5c..9e80af23018 100644 --- a/internal/pkg/aws/s3/mocks/mock_s3.go +++ b/internal/pkg/aws/s3/mocks/mock_s3.go @@ -5,10 +5,11 @@ package mocks import ( + context "context" reflect "reflect" - s3 "github.com/aws/aws-sdk-go/service/s3" - s3manager "github.com/aws/aws-sdk-go/service/s3/s3manager" + manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager" + s3 "github.com/aws/aws-sdk-go-v2/service/s3" gomock "github.com/golang/mock/gomock" ) @@ -36,22 +37,22 @@ func (m *Mocks3ManagerAPI) EXPECT() *Mocks3ManagerAPIMockRecorder { } // Upload mocks base method. -func (m *Mocks3ManagerAPI) Upload(input *s3manager.UploadInput, options ...func(*s3manager.Uploader)) (*s3manager.UploadOutput, error) { +func (m *Mocks3ManagerAPI) Upload(arg0 context.Context, arg1 *s3.PutObjectInput, arg2 ...func(*manager.Uploader)) (*manager.UploadOutput, error) { m.ctrl.T.Helper() - varargs := []interface{}{input} - for _, a := range options { + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "Upload", varargs...) - ret0, _ := ret[0].(*s3manager.UploadOutput) + ret0, _ := ret[0].(*manager.UploadOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // Upload indicates an expected call of Upload. -func (mr *Mocks3ManagerAPIMockRecorder) Upload(input interface{}, options ...interface{}) *gomock.Call { +func (mr *Mocks3ManagerAPIMockRecorder) Upload(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{input}, options...) + varargs := append([]interface{}{arg0, arg1}, arg2...) return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Upload", reflect.TypeOf((*Mocks3ManagerAPI)(nil).Upload), varargs...) } @@ -79,63 +80,83 @@ func (m *Mocks3API) EXPECT() *Mocks3APIMockRecorder { } // DeleteObjects mocks base method. -func (m *Mocks3API) DeleteObjects(input *s3.DeleteObjectsInput) (*s3.DeleteObjectsOutput, error) { +func (m *Mocks3API) DeleteObjects(arg0 context.Context, arg1 *s3.DeleteObjectsInput, arg2 ...func(*s3.Options)) (*s3.DeleteObjectsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteObjects", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteObjects", varargs...) ret0, _ := ret[0].(*s3.DeleteObjectsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteObjects indicates an expected call of DeleteObjects. -func (mr *Mocks3APIMockRecorder) DeleteObjects(input interface{}) *gomock.Call { +func (mr *Mocks3APIMockRecorder) DeleteObjects(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObjects", reflect.TypeOf((*Mocks3API)(nil).DeleteObjects), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteObjects", reflect.TypeOf((*Mocks3API)(nil).DeleteObjects), varargs...) } // HeadBucket mocks base method. -func (m *Mocks3API) HeadBucket(input *s3.HeadBucketInput) (*s3.HeadBucketOutput, error) { +func (m *Mocks3API) HeadBucket(arg0 context.Context, arg1 *s3.HeadBucketInput, arg2 ...func(*s3.Options)) (*s3.HeadBucketOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HeadBucket", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "HeadBucket", varargs...) ret0, _ := ret[0].(*s3.HeadBucketOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // HeadBucket indicates an expected call of HeadBucket. -func (mr *Mocks3APIMockRecorder) HeadBucket(input interface{}) *gomock.Call { +func (mr *Mocks3APIMockRecorder) HeadBucket(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadBucket", reflect.TypeOf((*Mocks3API)(nil).HeadBucket), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HeadBucket", reflect.TypeOf((*Mocks3API)(nil).HeadBucket), varargs...) } // ListObjectVersions mocks base method. -func (m *Mocks3API) ListObjectVersions(input *s3.ListObjectVersionsInput) (*s3.ListObjectVersionsOutput, error) { +func (m *Mocks3API) ListObjectVersions(arg0 context.Context, arg1 *s3.ListObjectVersionsInput, arg2 ...func(*s3.Options)) (*s3.ListObjectVersionsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListObjectVersions", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListObjectVersions", varargs...) ret0, _ := ret[0].(*s3.ListObjectVersionsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListObjectVersions indicates an expected call of ListObjectVersions. -func (mr *Mocks3APIMockRecorder) ListObjectVersions(input interface{}) *gomock.Call { +func (mr *Mocks3APIMockRecorder) ListObjectVersions(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectVersions", reflect.TypeOf((*Mocks3API)(nil).ListObjectVersions), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectVersions", reflect.TypeOf((*Mocks3API)(nil).ListObjectVersions), varargs...) } // ListObjectsV2 mocks base method. -func (m *Mocks3API) ListObjectsV2(input *s3.ListObjectsV2Input) (*s3.ListObjectsV2Output, error) { +func (m *Mocks3API) ListObjectsV2(arg0 context.Context, arg1 *s3.ListObjectsV2Input, arg2 ...func(*s3.Options)) (*s3.ListObjectsV2Output, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListObjectsV2", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListObjectsV2", varargs...) ret0, _ := ret[0].(*s3.ListObjectsV2Output) ret1, _ := ret[1].(error) return ret0, ret1 } // ListObjectsV2 indicates an expected call of ListObjectsV2. -func (mr *Mocks3APIMockRecorder) ListObjectsV2(input interface{}) *gomock.Call { +func (mr *Mocks3APIMockRecorder) ListObjectsV2(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectsV2", reflect.TypeOf((*Mocks3API)(nil).ListObjectsV2), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListObjectsV2", reflect.TypeOf((*Mocks3API)(nil).ListObjectsV2), varargs...) } // MockNamedBinary is a mock of NamedBinary interface. diff --git a/internal/pkg/aws/s3/s3.go b/internal/pkg/aws/s3/s3.go index 5db761192cc..7265ef76368 100644 --- a/internal/pkg/aws/s3/s3.go +++ b/internal/pkg/aws/s3/s3.go @@ -5,6 +5,7 @@ package s3 import ( + "context" "errors" "fmt" "io" @@ -12,20 +13,19 @@ import ( "path/filepath" "strings" - "github.com/aws/aws-sdk-go/aws" - awsarn "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/endpoints" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" + "github.com/aws/aws-sdk-go-v2/aws" + awsarn "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/feature/s3/manager" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/smithy-go" "github.com/dustin/go-humanize" "github.com/xlab/treeprint" ) const ( // EndpointsID is the ID to look up the S3 service endpoint. - EndpointsID = s3.EndpointsID + EndpointsID = "s3" // Error codes. errCodeNotFound = "NotFound" @@ -38,14 +38,14 @@ const ( ) type s3ManagerAPI interface { - Upload(input *s3manager.UploadInput, options ...func(*s3manager.Uploader)) (*s3manager.UploadOutput, error) + Upload(context.Context, *s3.PutObjectInput, ...func(*manager.Uploader)) (*manager.UploadOutput, error) } type s3API interface { - ListObjectVersions(input *s3.ListObjectVersionsInput) (*s3.ListObjectVersionsOutput, error) - ListObjectsV2(input *s3.ListObjectsV2Input) (*s3.ListObjectsV2Output, error) - DeleteObjects(input *s3.DeleteObjectsInput) (*s3.DeleteObjectsOutput, error) - HeadBucket(input *s3.HeadBucketInput) (*s3.HeadBucketOutput, error) + ListObjectVersions(context.Context, *s3.ListObjectVersionsInput, ...func(*s3.Options)) (*s3.ListObjectVersionsOutput, error) + ListObjectsV2(context.Context, *s3.ListObjectsV2Input, ...func(*s3.Options)) (*s3.ListObjectsV2Output, error) + DeleteObjects(context.Context, *s3.DeleteObjectsInput, ...func(*s3.Options)) (*s3.DeleteObjectsOutput, error) + HeadBucket(context.Context, *s3.HeadBucketInput, ...func(*s3.Options)) (*s3.HeadBucketOutput, error) } // NamedBinary is a named binary to be uploaded. @@ -63,11 +63,12 @@ type S3 struct { s3Client s3API } -// New returns an S3 client configured against the input session. -func New(s *session.Session) *S3 { +// New returns an S3 client configured against the input SDK v2 config. +func New(cfg aws.Config) *S3 { + client := s3.NewFromConfig(cfg) return &S3{ - s3Manager: s3manager.NewUploader(s), - s3Client: s3.New(s), + s3Manager: manager.NewUploader(client), + s3Client: client, } } @@ -97,13 +98,13 @@ func (s *S3) EmptyBucket(bucket string) error { } // Remove all versions of all objects. for { - listResp, err = s.s3Client.ListObjectVersions(listParams) + listResp, err = s.s3Client.ListObjectVersions(context.Background(), listParams) if err != nil { return fmt.Errorf("list objects for bucket %s: %w", bucket, err) } - var objectsToDelete []*s3.ObjectIdentifier + var objectsToDelete []types.ObjectIdentifier for _, object := range listResp.Versions { - objectsToDelete = append(objectsToDelete, &s3.ObjectIdentifier{ + objectsToDelete = append(objectsToDelete, types.ObjectIdentifier{ Key: object.Key, VersionId: object.VersionId, }) @@ -111,7 +112,7 @@ func (s *S3) EmptyBucket(bucket string) error { // After deleting other versions, remove delete markers version. // For info on "delete marker": https://docs.aws.amazon.com/AmazonS3/latest/dev/DeleteMarker.html for _, deleteMarker := range listResp.DeleteMarkers { - objectsToDelete = append(objectsToDelete, &s3.ObjectIdentifier{ + objectsToDelete = append(objectsToDelete, types.ObjectIdentifier{ Key: deleteMarker.Key, VersionId: deleteMarker.VersionId, }) @@ -119,9 +120,9 @@ func (s *S3) EmptyBucket(bucket string) error { if len(objectsToDelete) == 0 { return nil } - delResp, err := s.s3Client.DeleteObjects(&s3.DeleteObjectsInput{ + delResp, err := s.s3Client.DeleteObjects(context.Background(), &s3.DeleteObjectsInput{ Bucket: aws.String(bucket), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: objectsToDelete, Quiet: aws.Bool(true), // we don't care about success values }, @@ -132,10 +133,10 @@ func (s *S3) EmptyBucket(bucket string) error { case len(delResp.Errors) > 0: return errors.Join( fmt.Errorf("%d/%d objects failed to delete", len(delResp.Errors), len(objectsToDelete)), - fmt.Errorf("first failed on key %q: %s", aws.StringValue(delResp.Errors[0].Key), aws.StringValue(delResp.Errors[0].Message)), + fmt.Errorf("first failed on key %q: %s", aws.ToString(delResp.Errors[0].Key), aws.ToString(delResp.Errors[0].Message)), ) } - if !aws.BoolValue(listResp.IsTruncated) { + if !aws.ToBool(listResp.IsTruncated) { return nil } listParams.KeyMarker = listResp.NextKeyMarker @@ -172,11 +173,8 @@ func ParseARN(arn string) (bucket, key string, err error) { // URL returns a virtual-hosted–style S3 url for the object stored at key in a bucket created in the specified region. func URL(region, bucket, key string) string { tld := "com" - for cn := range endpoints.AwsCnPartition().Regions() { - if cn == region { - tld = "cn" - break - } + if strings.HasPrefix(region, "cn-") { + tld = "cn" } if key != "" { return fmt.Sprintf("https://%s.s3.%s.amazonaws.%s/%s", bucket, region, tld, key) @@ -201,8 +199,8 @@ func (s *S3) BucketTree(bucket string) (string, error) { if err != nil || outputs == nil { return "", err } - var contents []*s3.Object - var prefixes []*s3.CommonPrefix + var contents []types.Object + var prefixes []types.CommonPrefix for _, output := range outputs { contents = append(contents, output.Contents...) prefixes = append(prefixes, output.CommonPrefixes...) @@ -210,7 +208,7 @@ func (s *S3) BucketTree(bucket string) (string, error) { tree := treeprint.New() // Add top-level files. for _, object := range contents { - tree.AddNode(aws.StringValue(object.Key)) + tree.AddNode(aws.ToString(object.Key)) } // Recursively add folders and their children. if err := s.addNodes(tree, prefixes, bucket); err != nil { @@ -229,7 +227,7 @@ func (s *S3) BucketSizeAndCount(bucket string) (string, int, error) { var count int for _, output := range outputs { for _, object := range output.Contents { - size += aws.Int64Value(object.Size) + size += aws.ToInt64(object.Size) count++ } } @@ -249,7 +247,7 @@ func (s *S3) listObjects(bucket, delimiter string) ([]s3.ListObjectsV2Output, er Delimiter: aws.String(delimiter), ContinuationToken: listResp.NextContinuationToken, } - listResp, err = s.s3Client.ListObjectsV2(listParams) + listResp, err = s.s3Client.ListObjectsV2(context.Background(), listParams) if err != nil { return nil, fmt.Errorf("list objects for bucket %s: %w", bucket, err) } @@ -265,10 +263,10 @@ func (s *S3) bucketExists(bucket string) (bool, error) { input := &s3.HeadBucketInput{ Bucket: aws.String(bucket), } - _, err := s.s3Client.HeadBucket(input) + _, err := s.s3Client.HeadBucket(context.Background(), input) if err != nil { - var aerr awserr.Error - if errors.As(err, &aerr) && aerr.Code() == errCodeNotFound { + var aerr smithy.APIError + if errors.As(err, &aerr) && aerr.ErrorCode() == errCodeNotFound { return false, nil } return false, err @@ -276,16 +274,16 @@ func (s *S3) bucketExists(bucket string) (bool, error) { return true, nil } -func (s *S3) addNodes(tree treeprint.Tree, prefixes []*s3.CommonPrefix, bucket string) error { +func (s *S3) addNodes(tree treeprint.Tree, prefixes []types.CommonPrefix, bucket string) error { if len(prefixes) == 0 { return nil } listResp := &s3.ListObjectsV2Output{} var err error for _, prefix := range prefixes { - var respContents []*s3.Object - var respPrefixes []*s3.CommonPrefix - branch := tree.AddBranch(filepath.Base(aws.StringValue(prefix.Prefix))) + var respContents []types.Object + var respPrefixes []types.CommonPrefix + branch := tree.AddBranch(filepath.Base(aws.ToString(prefix.Prefix))) for { listParams := &s3.ListObjectsV2Input{ Bucket: aws.String(bucket), @@ -293,7 +291,7 @@ func (s *S3) addNodes(tree treeprint.Tree, prefixes []*s3.CommonPrefix, bucket s ContinuationToken: listResp.ContinuationToken, Prefix: prefix.Prefix, } - listResp, err = s.s3Client.ListObjectsV2(listParams) + listResp, err = s.s3Client.ListObjectsV2(context.Background(), listParams) if err != nil { return fmt.Errorf("list objects for bucket %s: %w", bucket, err) } @@ -304,7 +302,7 @@ func (s *S3) addNodes(tree treeprint.Tree, prefixes []*s3.CommonPrefix, bucket s } } for _, file := range respContents { - fileName := filepath.Base(aws.StringValue(file.Key)) + fileName := filepath.Base(aws.ToString(file.Key)) branch.AddNode(fileName) } if err := s.addNodes(branch, respPrefixes, bucket); err != nil { @@ -315,14 +313,14 @@ func (s *S3) addNodes(tree treeprint.Tree, prefixes []*s3.CommonPrefix, bucket s } func (s *S3) upload(bucket, key string, buf io.Reader) (string, error) { - in := &s3manager.UploadInput{ + in := &s3.PutObjectInput{ Body: buf, Bucket: aws.String(bucket), Key: aws.String(key), - ACL: aws.String(s3.ObjectCannedACLBucketOwnerFullControl), + ACL: types.ObjectCannedACLBucketOwnerFullControl, ContentType: defaultContentTypeFromExt(key), } - resp, err := s.s3Manager.Upload(in) + resp, err := s.s3Manager.Upload(context.Background(), in) if err != nil { return "", fmt.Errorf("upload %s to bucket %s: %w", key, bucket, err) } diff --git a/internal/pkg/aws/s3/s3_test.go b/internal/pkg/aws/s3/s3_test.go index a79ebc22c95..dcecb98e5ec 100644 --- a/internal/pkg/aws/s3/s3_test.go +++ b/internal/pkg/aws/s3/s3_test.go @@ -5,17 +5,18 @@ package s3 import ( "bytes" + "context" "errors" "fmt" "io" "testing" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aproint/copilot-cli/internal/pkg/aws/s3/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/s3/manager" + s3api "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/aws/smithy-go" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -29,24 +30,24 @@ func TestS3_Upload(t *testing.T) { }{ "return error if upload fails": { mockS3ManagerClient: func(m *mocks.Mocks3ManagerAPI) { - m.EXPECT().Upload(gomock.Any()).Do(func(in *s3manager.UploadInput, _ ...func(*s3manager.Uploader)) { - require.Equal(t, aws.StringValue(in.Bucket), "mockBucket") - require.Equal(t, aws.StringValue(in.Key), "src/mockIndex.html") + m.EXPECT().Upload(gomock.Any(), gomock.Any()).Do(func(_ context.Context, in *s3api.PutObjectInput, _ ...func(*manager.Uploader)) { + require.Equal(t, aws.ToString(in.Bucket), "mockBucket") + require.Equal(t, aws.ToString(in.Key), "src/mockIndex.html") }).Return(nil, errors.New("some error")) }, wantError: fmt.Errorf("upload src/mockIndex.html to bucket mockBucket: some error"), }, "should upload to the s3 bucket": { mockS3ManagerClient: func(m *mocks.Mocks3ManagerAPI) { - m.EXPECT().Upload(gomock.Any()).Do(func(in *s3manager.UploadInput, _ ...func(*s3manager.Uploader)) { + m.EXPECT().Upload(gomock.Any(), gomock.Any()).Do(func(_ context.Context, in *s3api.PutObjectInput, _ ...func(*manager.Uploader)) { b, err := io.ReadAll(in.Body) require.NoError(t, err) require.Equal(t, "bar", string(b)) - require.Equal(t, "mockBucket", aws.StringValue(in.Bucket)) - require.Equal(t, "src/mockIndex.html", aws.StringValue(in.Key)) - require.Equal(t, "text/html; charset=utf-8", aws.StringValue(in.ContentType)) - require.Equal(t, s3.ObjectCannedACLBucketOwnerFullControl, aws.StringValue(in.ACL)) - }).Return(&s3manager.UploadOutput{ + require.Equal(t, "mockBucket", aws.ToString(in.Bucket)) + require.Equal(t, "src/mockIndex.html", aws.ToString(in.Key)) + require.Equal(t, "text/html; charset=utf-8", aws.ToString(in.ContentType)) + require.Equal(t, string(types.ObjectCannedACLBucketOwnerFullControl), string(in.ACL)) + }).Return(&manager.UploadOutput{ Location: "mockURL", }, nil) }, @@ -80,40 +81,40 @@ func TestS3_Upload(t *testing.T) { } func TestS3_EmptyBucket(t *testing.T) { - batchObject1 := make([]*s3.ObjectVersion, 1000) - batchObject2 := make([]*s3.ObjectVersion, 10) - deleteMarkers := make([]*s3.DeleteMarkerEntry, 10) - batchObjectID1 := make([]*s3.ObjectIdentifier, 1000) - batchObjectID2 := make([]*s3.ObjectIdentifier, 10) - batchObjectID3 := make([]*s3.ObjectIdentifier, 20) + batchObject1 := make([]types.ObjectVersion, 1000) + batchObject2 := make([]types.ObjectVersion, 10) + deleteMarkers := make([]types.DeleteMarkerEntry, 10) + batchObjectID1 := make([]types.ObjectIdentifier, 1000) + batchObjectID2 := make([]types.ObjectIdentifier, 10) + batchObjectID3 := make([]types.ObjectIdentifier, 20) for i := 0; i < 1000; i++ { - batchObject1[i] = &s3.ObjectVersion{ + batchObject1[i] = types.ObjectVersion{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } - batchObjectID1[i] = &s3.ObjectIdentifier{ + batchObjectID1[i] = types.ObjectIdentifier{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } } for i := 0; i < 10; i++ { - batchObject2[i] = &s3.ObjectVersion{ + batchObject2[i] = types.ObjectVersion{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } - deleteMarkers[i] = &s3.DeleteMarkerEntry{ + deleteMarkers[i] = types.DeleteMarkerEntry{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } - batchObjectID2[i] = &s3.ObjectIdentifier{ + batchObjectID2[i] = types.ObjectIdentifier{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } - batchObjectID3[i] = &s3.ObjectIdentifier{ + batchObjectID3[i] = types.ObjectIdentifier{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } - batchObjectID3[i+10] = &s3.ObjectIdentifier{ + batchObjectID3[i+10] = types.ObjectIdentifier{ Key: aws.String("mockKey"), VersionId: aws.String("mockVersion"), } @@ -127,22 +128,22 @@ func TestS3_EmptyBucket(t *testing.T) { "should delete all objects within the bucket": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), - }).Return(&s3.ListObjectVersionsOutput{ + }).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(false), Versions: batchObject2, }, nil) - m.EXPECT().DeleteObjects(&s3.DeleteObjectsInput{ + m.EXPECT().DeleteObjects(gomock.Any(), &s3api.DeleteObjectsInput{ Bucket: aws.String("mockBucket"), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: batchObjectID2, Quiet: aws.Bool(true), }, - }).Return(&s3.DeleteObjectsOutput{}, nil) + }).Return(&s3api.DeleteObjectsOutput{}, nil) }, wantErr: nil, @@ -150,35 +151,35 @@ func TestS3_EmptyBucket(t *testing.T) { "should batch delete all objects within the bucket": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), - }).Return(&s3.ListObjectVersionsOutput{ + }).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(true), Versions: batchObject1, }, nil) - m.EXPECT().DeleteObjects(&s3.DeleteObjectsInput{ + m.EXPECT().DeleteObjects(gomock.Any(), &s3api.DeleteObjectsInput{ Bucket: aws.String("mockBucket"), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: batchObjectID1, Quiet: aws.Bool(true), }, - }).Return(&s3.DeleteObjectsOutput{}, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + }).Return(&s3api.DeleteObjectsOutput{}, nil) + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), - }).Return(&s3.ListObjectVersionsOutput{ + }).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(false), Versions: batchObject2, }, nil) - m.EXPECT().DeleteObjects(&s3.DeleteObjectsInput{ + m.EXPECT().DeleteObjects(gomock.Any(), &s3api.DeleteObjectsInput{ Bucket: aws.String("mockBucket"), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: batchObjectID2, Quiet: aws.Bool(true), }, - }).Return(&s3.DeleteObjectsOutput{}, nil) + }).Return(&s3api.DeleteObjectsOutput{}, nil) }, wantErr: nil, @@ -186,23 +187,23 @@ func TestS3_EmptyBucket(t *testing.T) { "should delete all objects within the bucket including delete markers": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), - }).Return(&s3.ListObjectVersionsOutput{ + }).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(false), Versions: batchObject2, DeleteMarkers: deleteMarkers, }, nil) - m.EXPECT().DeleteObjects(&s3.DeleteObjectsInput{ + m.EXPECT().DeleteObjects(gomock.Any(), &s3api.DeleteObjectsInput{ Bucket: aws.String("mockBucket"), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: batchObjectID3, Quiet: aws.Bool(true), }, - }).Return(&s3.DeleteObjectsOutput{}, nil) + }).Return(&s3api.DeleteObjectsOutput{}, nil) }, wantErr: nil, @@ -210,10 +211,10 @@ func TestS3_EmptyBucket(t *testing.T) { "should wrap up error if fail to list objects": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), }).Return(nil, errors.New("some error")) }, @@ -223,31 +224,31 @@ func TestS3_EmptyBucket(t *testing.T) { "should not invoke DeleteObjects if bucket is empty": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(gomock.Any()).Return(&s3.ListObjectVersionsOutput{ + m.EXPECT().ListObjectVersions(gomock.Any(), gomock.Any()).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(false), }, nil) - m.EXPECT().DeleteObjects(gomock.Any()).Times(0) + m.EXPECT().DeleteObjects(gomock.Any(), gomock.Any()).Times(0) }, wantErr: nil, }, "should wrap up error if fail to delete objects": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), - }).Return(&s3.ListObjectVersionsOutput{ + }).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(false), Versions: batchObject2, }, nil) - m.EXPECT().DeleteObjects(&s3.DeleteObjectsInput{ + m.EXPECT().DeleteObjects(gomock.Any(), &s3api.DeleteObjectsInput{ Bucket: aws.String("mockBucket"), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: batchObjectID2, Quiet: aws.Bool(true), }, @@ -259,9 +260,9 @@ func TestS3_EmptyBucket(t *testing.T) { "should not proceed with deletion as the bucket doesnt exists": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), - }).Return(nil, awserr.New(errCodeNotFound, "message", nil)) + }).Return(nil, &smithy.GenericAPIError{Code: errCodeNotFound, Message: "message"}) }, wantErr: nil, @@ -269,34 +270,34 @@ func TestS3_EmptyBucket(t *testing.T) { "should throw error while perform bucket exists check": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), - }).Return(nil, awserr.New("Unknown", "message", nil)) + }).Return(nil, &smithy.GenericAPIError{Code: "Unknown", Message: "message"}) }, wantErr: fmt.Errorf("unable to determine the existence of bucket %s: %w", "mockBucket", - awserr.New("Unknown", "message", nil)), + &smithy.GenericAPIError{Code: "Unknown", Message: "message"}), }, "some objects failed to delete": { inBucket: "mockBucket", mockS3Client: func(m *mocks.Mocks3API) { - m.EXPECT().HeadBucket(&s3.HeadBucketInput{ + m.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{ Bucket: aws.String("mockBucket"), }).Return(nil, nil) - m.EXPECT().ListObjectVersions(&s3.ListObjectVersionsInput{ + m.EXPECT().ListObjectVersions(gomock.Any(), &s3api.ListObjectVersionsInput{ Bucket: aws.String("mockBucket"), - }).Return(&s3.ListObjectVersionsOutput{ + }).Return(&s3api.ListObjectVersionsOutput{ IsTruncated: aws.Bool(false), Versions: batchObject2, }, nil) - m.EXPECT().DeleteObjects(&s3.DeleteObjectsInput{ + m.EXPECT().DeleteObjects(gomock.Any(), &s3api.DeleteObjectsInput{ Bucket: aws.String("mockBucket"), - Delete: &s3.Delete{ + Delete: &types.Delete{ Objects: batchObjectID2, Quiet: aws.Bool(true), }, - }).Return(&s3.DeleteObjectsOutput{ - Errors: []*s3.Error{ + }).Return(&s3api.DeleteObjectsOutput{ + Errors: []types.Error{ { Key: aws.String("mock/key"), Message: aws.String("some error"), @@ -496,61 +497,61 @@ func TestS3_BucketTree(t *testing.T) { } mockBucket := aws.String("bucketName") delimiter := aws.String("/") - nonexistentError := awserr.New(errCodeNotFound, "msg", errors.New("some error")) + nonexistentError := &smithy.GenericAPIError{Code: errCodeNotFound, Message: "msg"} mockContinuationToken := "next" - firstResp := s3.ListObjectsV2Output{ - CommonPrefixes: []*s3.CommonPrefix{ + firstResp := s3api.ListObjectsV2Output{ + CommonPrefixes: []types.CommonPrefix{ {Prefix: aws.String("Images")}, {Prefix: aws.String("css")}, {Prefix: aws.String("top")}, }, - Contents: []*s3.Object{ + Contents: []types.Object{ {Key: aws.String("README.md")}, {Key: aws.String("error.html")}, {Key: aws.String("index.html")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, } - imagesResp := s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + imagesResp := s3api.ListObjectsV2Output{ + Contents: []types.Object{ {Key: aws.String("firstImage.PNG")}, {Key: aws.String("secondImage.PNG")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, } - cssResp := s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + cssResp := s3api.ListObjectsV2Output{ + Contents: []types.Object{ {Key: aws.String("Style.css")}, {Key: aws.String("bootstrap.min.css")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, } - topResp := s3.ListObjectsV2Output{ - CommonPrefixes: []*s3.CommonPrefix{ + topResp := s3api.ListObjectsV2Output{ + CommonPrefixes: []types.CommonPrefix{ {Prefix: aws.String("middle")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, } - middleResp := s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + middleResp := s3api.ListObjectsV2Output{ + Contents: []types.Object{ {Key: aws.String("bottom.html")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, } testCases := map[string]struct { @@ -561,29 +562,29 @@ func TestS3_BucketTree(t *testing.T) { }{ "should return all objects within the bucket as a tree string": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, ContinuationToken: nil, Delimiter: delimiter, Prefix: nil, }).Return(&firstResp, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: delimiter, Prefix: aws.String("Images"), }).Return(&imagesResp, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: delimiter, Prefix: aws.String("css"), }).Return(&cssResp, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: delimiter, Prefix: aws.String("top"), }).Return(&topResp, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: delimiter, Prefix: aws.String("middle"), @@ -606,36 +607,36 @@ func TestS3_BucketTree(t *testing.T) { }, "should handle multiple pages of objects": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, ContinuationToken: nil, Delimiter: delimiter, Prefix: nil, }).Return( - &s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + &s3api.ListObjectsV2Output{ + Contents: []types.Object{ {Key: aws.String("README.md")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, NextContinuationToken: &mockContinuationToken, }, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, ContinuationToken: &mockContinuationToken, Delimiter: delimiter, Prefix: nil, }).Return( - &s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + &s3api.ListObjectsV2Output{ + Contents: []types.Object{ {Key: aws.String("READMETOO.md")}, }, Delimiter: delimiter, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, NextContinuationToken: nil, }, nil) @@ -647,19 +648,19 @@ func TestS3_BucketTree(t *testing.T) { }, "return nil if bucket doesn't exist": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nonexistentError) + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nonexistentError) }, }, "return err if cannot determine if bucket exists": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, errors.New("some error")) + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, errors.New("some error")) }, wantErr: errors.New("some error"), }, "should wrap error if fail to list objects": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, ContinuationToken: nil, Delimiter: delimiter, @@ -689,7 +690,7 @@ func TestS3_BucketTree(t *testing.T) { } tc.setupMocks(s3mocks) - gotTree, gotErr := service.BucketTree(aws.StringValue(mockBucket)) + gotTree, gotErr := service.BucketTree(aws.ToString(mockBucket)) if tc.wantErr != nil { require.EqualError(t, gotErr, tc.wantErr.Error()) return @@ -707,11 +708,11 @@ func TestS3_BucketSizeAndCount(t *testing.T) { s3ManagerAPI *mocks.Mocks3ManagerAPI } mockBucket := aws.String("bucketName") - nonexistentError := awserr.New(errCodeNotFound, "msg", errors.New("some error")) + nonexistentError := &smithy.GenericAPIError{Code: errCodeNotFound, Message: "msg"} mockContinuationToken := "next" - resp := s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + resp := s3api.ListObjectsV2Output{ + Contents: []types.Object{ { Key: aws.String("README.md"), Size: aws.Int64(111111), @@ -725,8 +726,8 @@ func TestS3_BucketSizeAndCount(t *testing.T) { Size: aws.Int64(333333), }, }, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, } @@ -739,8 +740,8 @@ func TestS3_BucketSizeAndCount(t *testing.T) { }{ "should return correct size and count": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: aws.String(""), ContinuationToken: nil, @@ -752,40 +753,40 @@ func TestS3_BucketSizeAndCount(t *testing.T) { }, "should handle multiple pages of objects": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: aws.String(""), ContinuationToken: nil, Prefix: nil, }).Return( - &s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + &s3api.ListObjectsV2Output{ + Contents: []types.Object{ { Key: aws.String("README.md"), Size: aws.Int64(123), }, }, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, NextContinuationToken: &mockContinuationToken, }, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: aws.String(""), ContinuationToken: &mockContinuationToken, Prefix: nil, }).Return( - &s3.ListObjectsV2Output{ - Contents: []*s3.Object{ + &s3api.ListObjectsV2Output{ + Contents: []types.Object{ { Key: aws.String("READMETOO.md"), Size: aws.Int64(321), }, }, - KeyCount: aws.Int64(14), - MaxKeys: aws.Int64(1000), + KeyCount: aws.Int32(14), + MaxKeys: aws.Int32(1000), Name: mockBucket, NextContinuationToken: nil, }, nil) @@ -795,13 +796,13 @@ func TestS3_BucketSizeAndCount(t *testing.T) { }, "empty bucket": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: aws.String(""), ContinuationToken: nil, Prefix: nil, - }).Return(&s3.ListObjectsV2Output{ + }).Return(&s3api.ListObjectsV2Output{ Contents: nil, Name: mockBucket, }, nil) @@ -811,19 +812,19 @@ func TestS3_BucketSizeAndCount(t *testing.T) { }, "return nil if bucket doesn't exist": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nonexistentError) + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nonexistentError) }, }, "return err if cannot determine if bucket exists": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, errors.New("some error")) + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, errors.New("some error")) }, wantErr: errors.New("some error"), }, "should wrap error if fail to list objects": { setupMocks: func(m s3Mocks) { - m.s3API.EXPECT().HeadBucket(&s3.HeadBucketInput{Bucket: mockBucket}).Return(&s3.HeadBucketOutput{}, nil) - m.s3API.EXPECT().ListObjectsV2(&s3.ListObjectsV2Input{ + m.s3API.EXPECT().HeadBucket(gomock.Any(), &s3api.HeadBucketInput{Bucket: mockBucket}).Return(&s3api.HeadBucketOutput{}, nil) + m.s3API.EXPECT().ListObjectsV2(gomock.Any(), &s3api.ListObjectsV2Input{ Bucket: mockBucket, Delimiter: aws.String(""), ContinuationToken: nil, @@ -851,7 +852,7 @@ func TestS3_BucketSizeAndCount(t *testing.T) { } tc.setupMocks(s3mocks) - gotSize, gotCount, gotErr := service.BucketSizeAndCount(aws.StringValue(mockBucket)) + gotSize, gotCount, gotErr := service.BucketSizeAndCount(aws.ToString(mockBucket)) if tc.wantErr != nil { require.EqualError(t, gotErr, tc.wantErr.Error()) return diff --git a/internal/pkg/cli/app_delete.go b/internal/pkg/cli/app_delete.go index 936c9875cff..5589889c41a 100644 --- a/internal/pkg/cli/app_delete.go +++ b/internal/pkg/cli/app_delete.go @@ -88,7 +88,7 @@ func newDeleteAppOpts(vars deleteAppVars) (*deleteAppOpts, error) { cfn: cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)), prompt: prompter, s3: func(session *session.Session) bucketEmptier { - return s3.New(session) + return s3.New(v2ConfigFromSessionRegion(session)) }, pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), sel: selector.NewAppEnvSelector(prompter, store), diff --git a/internal/pkg/cli/deploy/env.go b/internal/pkg/cli/deploy/env.go index 3a1c66d13e1..3852983e8db 100644 --- a/internal/pkg/cli/deploy/env.go +++ b/internal/pkg/cli/deploy/env.go @@ -147,8 +147,8 @@ func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { env: in.Env, templateFS: template.New(), - s3: awss3.New(envManagerSession), - prefixListGetter: ec2.New(envRegionSession), + s3: awss3.New(v2ConfigFromSessionRegion(envManagerSession)), + prefixListGetter: ec2.New(v2ConfigFromSessionRegion(envRegionSession)), appCFN: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), envDeployer: cfnClient, diff --git a/internal/pkg/cli/deploy/rdws.go b/internal/pkg/cli/deploy/rdws.go index 8f29a80ed16..a86d3104b38 100644 --- a/internal/pkg/cli/deploy/rdws.go +++ b/internal/pkg/cli/deploy/rdws.go @@ -59,7 +59,7 @@ func NewRDWSDeployer(in *WorkloadDeployerInput) (*rdwsDeployer, error) { } return &rdwsDeployer{ svcDeployer: svcDeployer, - customResourceS3Client: s3.New(svcDeployer.defaultSessWithEnvRegion), + customResourceS3Client: s3.New(v2ConfigFromSessionRegion(svcDeployer.defaultSessWithEnvRegion)), appVersionGetter: versionGetter, rdwsMft: rdwsMft, }, nil diff --git a/internal/pkg/cli/deploy/workload.go b/internal/pkg/cli/deploy/workload.go index d341cce55a7..a94f98c9686 100644 --- a/internal/pkg/cli/deploy/workload.go +++ b/internal/pkg/cli/deploy/workload.go @@ -321,7 +321,7 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { resources: resources, workspacePath: ws.Path(), fs: afero.NewOsFs(), - s3Client: s3.New(envSession), + s3Client: s3.New(v2ConfigFromSessionRegion(envSession)), addons: addons, repository: repository, deployer: cfn, diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index 818a63703f3..611e43f3901 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -125,7 +125,7 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { } o.rg = resourcegroupstaggingapi.New(sess) o.iam = iam.New(v2ConfigFromSessionRegion(sess)) - o.s3 = s3.New(sess) + o.s3 = s3.New(v2ConfigFromSessionRegion(sess)) o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), sess) o.deployer = cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) o.envDeleterFromApp = cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) diff --git a/internal/pkg/cli/env_init.go b/internal/pkg/cli/env_init.go index 2b9aae45b9c..b03acc6e766 100644 --- a/internal/pkg/cli/env_init.go +++ b/internal/pkg/cli/env_init.go @@ -500,7 +500,7 @@ func (o *initEnvOpts) askCustomizedResources() error { func (o *initEnvOpts) askImportResources() error { if o.selVPC == nil { - o.selVPC = selector.NewEC2Select(o.prompt, ec2.New(o.sess)) + o.selVPC = selector.NewEC2Select(o.prompt, ec2.New(v2ConfigFromSessionRegion(o.sess))) } if o.importVPC.ID == "" { vpcID, err := o.selVPC.VPC(envInitVPCSelectPrompt, "") @@ -516,7 +516,7 @@ func (o *initEnvOpts) askImportResources() error { o.importVPC.ID = vpcID } if o.ec2Client == nil { - o.ec2Client = ec2.New(o.sess) + o.ec2Client = ec2.New(v2ConfigFromSessionRegion(o.sess)) } dnsSupport, err := o.ec2Client.HasDNSSupport(o.importVPC.ID) if err != nil { @@ -633,7 +633,7 @@ func (o *initEnvOpts) askAZs() ([]string, error) { return o.adjustVPC.AZs, nil } if o.ec2Client == nil { - o.ec2Client = ec2.New(o.sess) + o.ec2Client = ec2.New(v2ConfigFromSessionRegion(o.sess)) } azs, err := o.ec2Client.ListAZs() if err != nil { diff --git a/internal/pkg/cli/run_local.go b/internal/pkg/cli/run_local.go index 02766e57df2..66ff23b5d40 100644 --- a/internal/pkg/cli/run_local.go +++ b/internal/pkg/cli/run_local.go @@ -50,11 +50,12 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/term/syncbuffer" "github.com/aproint/copilot-cli/internal/pkg/workspace" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + sdkecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" - sdkecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/aws/aws-sdk-go/service/rds" sdksecretsmanager "github.com/aws/aws-sdk-go/service/secretsmanager" sdkssm "github.com/aws/aws-sdk-go/service/ssm" @@ -209,7 +210,7 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { // so use the default sess and *hope* they have permissions. o.ecsClient = ecs.New(o.envManagerSess, envManagerConfig) o.ssm = ssm.New(envManagerConfig) - o.ecsExecutor = awsecs.New(o.envManagerSess) + o.ecsExecutor = awsecs.New(envManagerConfig) o.secretsManager = secretsmanager.New(defaultConfigEnvRegion) resources, err := cloudformation.New(o.sess, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(o.targetApp, o.targetEnv.Region) @@ -480,8 +481,8 @@ func (o *runLocalOpts) getSSMTarget(ctx context.Context) (string, error) { for _, ctr := range task.Containers { id := aws.StringValue(ctr.RuntimeId) - hasECSExec := slices.ContainsFunc(ctr.ManagedAgents, func(a *sdkecs.ManagedAgent) bool { - return aws.StringValue(a.Name) == "ExecuteCommandAgent" && aws.StringValue(a.LastStatus) == "RUNNING" + hasECSExec := slices.ContainsFunc(ctr.ManagedAgents, func(a sdkecs.ManagedAgent) bool { + return string(a.Name) == "ExecuteCommandAgent" && aws.StringValue(a.LastStatus) == "RUNNING" }) if id != "" && hasECSExec && aws.StringValue(ctr.LastStatus) == "RUNNING" { return fmt.Sprintf("ecs:%s_%s_%s", svc.ClusterName, taskName, aws.StringValue(ctr.RuntimeId)), nil @@ -546,10 +547,10 @@ func (o *runLocalOpts) getTask(ctx context.Context) (orchestrator.Task, error) { } for _, port := range ctr.PortMappings { - hostPort := strconv.FormatInt(aws.Int64Value(port.HostPort), 10) + hostPort := strconv.FormatInt(int64(awsv2.ToInt32(port.HostPort)), 10) ctrPort := hostPort if port.ContainerPort != nil { - ctrPort = strconv.FormatInt(aws.Int64Value(port.ContainerPort), 10) + ctrPort = strconv.FormatInt(int64(awsv2.ToInt32(port.ContainerPort)), 10) } for _, override := range o.portOverrides { @@ -1087,7 +1088,7 @@ func (o *runLocalOpts) getContainerDependencies(taskDef *awsecs.TaskDefinition) dependsOn: make(map[string]string), } for _, containerDep := range ctr.DependsOn { - dep.dependsOn[aws.StringValue(containerDep.ContainerName)] = strings.ToLower(aws.StringValue(containerDep.Condition)) + dep.dependsOn[aws.StringValue(containerDep.ContainerName)] = strings.ToLower(string(containerDep.Condition)) } dependencies[aws.StringValue(ctr.Name)] = dep } @@ -1113,8 +1114,8 @@ func (h *hostDiscoverer) Hosts(ctx context.Context) ([]orchestrator.Host, error) var hosts []orchestrator.Host for _, svc := range svcs { // find the primary deployment with Service Connect enabled - idx := slices.IndexFunc(svc.Deployments, func(dep *sdkecs.Deployment) bool { - return aws.StringValue(dep.Status) == "PRIMARY" && aws.BoolValue(dep.ServiceConnectConfiguration.Enabled) + idx := slices.IndexFunc(svc.Deployments, func(dep sdkecs.Deployment) bool { + return aws.StringValue(dep.Status) == "PRIMARY" && dep.ServiceConnectConfiguration.Enabled }) if idx == -1 { continue @@ -1124,7 +1125,7 @@ func (h *hostDiscoverer) Hosts(ctx context.Context) ([]orchestrator.Host, error) for _, alias := range sc.ClientAliases { hosts = append(hosts, orchestrator.Host{ Name: aws.StringValue(alias.DnsName), - Port: uint16(aws.Int64Value(alias.Port)), + Port: uint16(awsv2.ToInt32(alias.Port)), }) } } diff --git a/internal/pkg/cli/run_local_test.go b/internal/pkg/cli/run_local_test.go index 638ee37f6b6..adf2da57ef8 100644 --- a/internal/pkg/cli/run_local_test.go +++ b/internal/pkg/cli/run_local_test.go @@ -23,11 +23,11 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/term/selector" + sdkecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/request" "github.com/aws/aws-sdk-go/aws/session" - sdkecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/aws/aws-sdk-go/service/rds" "github.com/fsnotify/fsnotify" "github.com/golang/mock/gomock" @@ -273,34 +273,34 @@ func TestRunLocalOpts_Execute(t *testing.T) { taskDef := &awsecs.TaskDefinition{ TaskRoleArn: aws.String("mock-arn"), - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("FOO_VAR"), Value: aws.String("foo-value"), }, }, - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SHARED_SECRET"), ValueFrom: aws.String("mysecret"), }, }, - PortMappings: []*sdkecs.PortMapping{ + PortMappings: []sdkecs.PortMapping{ { - HostPort: aws.Int64(80), - ContainerPort: aws.Int64(8080), + HostPort: aws.Int32(int32(80)), + ContainerPort: aws.Int32(int32(8080)), }, { - HostPort: aws.Int64(9999), + HostPort: aws.Int32(int32(9999)), }, }, Essential: aws.Bool(true), - DependsOn: []*sdkecs.ContainerDependency{ + DependsOn: []sdkecs.ContainerDependency{ { - Condition: aws.String("START"), + Condition: sdkecs.ContainerConditionStart, ContainerName: aws.String("bar"), }, }, @@ -308,25 +308,25 @@ func TestRunLocalOpts_Execute(t *testing.T) { { Name: aws.String("bar"), Essential: aws.Bool(true), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("BAR_VAR"), Value: aws.String("bar-value"), }, }, - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SHARED_SECRET"), ValueFrom: aws.String("mysecret"), }, }, - PortMappings: []*sdkecs.PortMapping{ + PortMappings: []sdkecs.PortMapping{ { - HostPort: aws.Int64(10000), + HostPort: aws.Int32(int32(10000)), }, { - HostPort: aws.Int64(77), - ContainerPort: aws.Int64(7777), + HostPort: aws.Int32(int32(77)), + ContainerPort: aws.Int32(int32(7777)), }, }, }, @@ -334,52 +334,52 @@ func TestRunLocalOpts_Execute(t *testing.T) { } alteredTaskDef := &awsecs.TaskDefinition{ TaskRoleArn: aws.String("mock-arn"), - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("FOO_VAR"), Value: aws.String("foo-value"), }, }, - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SHARED_SECRET"), ValueFrom: aws.String("mysecret"), }, }, - PortMappings: []*sdkecs.PortMapping{ + PortMappings: []sdkecs.PortMapping{ { - HostPort: aws.Int64(80), - ContainerPort: aws.Int64(8081), + HostPort: aws.Int32(int32(80)), + ContainerPort: aws.Int32(int32(8081)), }, { - HostPort: aws.Int64(9999), + HostPort: aws.Int32(int32(9999)), }, }, }, { Name: aws.String("bar"), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("BAR_VAR"), Value: aws.String("bar-value"), }, }, - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SHARED_SECRET"), ValueFrom: aws.String("mysecret"), }, }, - PortMappings: []*sdkecs.PortMapping{ + PortMappings: []sdkecs.PortMapping{ { - HostPort: aws.Int64(10000), + HostPort: aws.Int32(int32(10000)), }, { - HostPort: aws.Int64(77), - ContainerPort: aws.Int64(7777), + HostPort: aws.Int32(int32(77)), + ContainerPort: aws.Int32(int32(7777)), }, }, }, @@ -537,13 +537,13 @@ func TestRunLocalOpts_Execute(t *testing.T) { Tasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/clusterName/taskName"), - Containers: []*sdkecs.Container{ + Containers: []sdkecs.Container{ { RuntimeId: aws.String("runtime-id"), LastStatus: aws.String("RUNNING"), - ManagedAgents: []*sdkecs.ManagedAgent{ + ManagedAgents: []sdkecs.ManagedAgent{ { - Name: aws.String("ExecuteCommandAgent"), + Name: sdkecs.ManagedAgentNameExecuteCommandAgent, LastStatus: aws.String("RUNNING"), }, }, @@ -744,7 +744,7 @@ ecs exec: all containers failed to retrieve credentials`), Tasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/clusterName/taskName"), - Containers: []*sdkecs.Container{ + Containers: []sdkecs.Container{ { RuntimeId: aws.String("runtime-id"), LastStatus: aws.String("RUNNING"), @@ -801,13 +801,13 @@ ecs exec: all containers failed to retrieve credentials`), Tasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/clusterName/taskName"), - Containers: []*sdkecs.Container{ + Containers: []sdkecs.Container{ { RuntimeId: aws.String("runtime-id"), LastStatus: aws.String("RUNNING"), - ManagedAgents: []*sdkecs.ManagedAgent{ + ManagedAgents: []sdkecs.ManagedAgent{ { - Name: aws.String("ExecuteCommandAgent"), + Name: sdkecs.ManagedAgentNameExecuteCommandAgent, LastStatus: aws.String("RUNNING"), }, }, @@ -881,13 +881,13 @@ ecs exec: all containers failed to retrieve credentials`), Tasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/clusterName/taskName"), - Containers: []*sdkecs.Container{ + Containers: []sdkecs.Container{ { RuntimeId: aws.String("runtime-id"), LastStatus: aws.String("RUNNING"), - ManagedAgents: []*sdkecs.ManagedAgent{ + ManagedAgents: []sdkecs.ManagedAgent{ { - Name: aws.String("ExecuteCommandAgent"), + Name: sdkecs.ManagedAgentNameExecuteCommandAgent, LastStatus: aws.String("RUNNING"), }, }, @@ -1258,7 +1258,7 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "overrides parsed and applied correctly": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), }, @@ -1291,10 +1291,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "overrides merged with existing env vars correctly": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("RANDOM_FOO"), Value: aws.String("foo"), @@ -1311,7 +1311,7 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, { Name: aws.String("bar"), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("RANDOM_BAR"), Value: aws.String("bar"), @@ -1354,10 +1354,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "error getting secret": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SECRET"), ValueFrom: aws.String("defaultSSM"), @@ -1373,10 +1373,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "error getting secret if invalid arn": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SECRET"), ValueFrom: aws.String("arn:aws:ecs:us-west-2:123456789:service/mycluster/myservice"), @@ -1389,16 +1389,16 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "error if secret redefines a var": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Environment: []*sdkecs.KeyValuePair{ + Environment: []sdkecs.KeyValuePair{ { Name: aws.String("SHOULD_BE_A_VAR"), Value: aws.String("foo"), }, }, - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SHOULD_BE_A_VAR"), ValueFrom: aws.String("bad"), @@ -1411,10 +1411,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "correct service used based on arn": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("SSM"), ValueFrom: aws.String("arn:aws:ssm:us-east-2:123456789:parameter/myparam"), @@ -1449,10 +1449,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "only unique secrets pulled": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("ONE"), ValueFrom: aws.String("shared"), @@ -1465,7 +1465,7 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, { Name: aws.String("bar"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("THREE"), ValueFrom: aws.String("shared"), @@ -1502,10 +1502,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "secrets set via overrides not pulled": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("ONE"), ValueFrom: aws.String("shared"), @@ -1518,7 +1518,7 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, { Name: aws.String("bar"), - Secrets: []*sdkecs.Secret{ + Secrets: []sdkecs.Secret{ { Name: aws.String("THREE"), ValueFrom: aws.String("shared"), @@ -1564,10 +1564,10 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { }, "region env vars set": { taskDef: &awsecs.TaskDefinition{ - ContainerDefinitions: []*sdkecs.ContainerDefinition{ + ContainerDefinitions: []sdkecs.ContainerDefinition{ { Name: aws.String("foo"), - Environment: []*sdkecs.KeyValuePair{}, + Environment: []sdkecs.KeyValuePair{}, }, }, }, @@ -1667,17 +1667,17 @@ func TestRunLocal_HostDiscovery(t *testing.T) { } ecsServices := []*awsecs.Service{ { - Deployments: []*sdkecs.Deployment{ + Deployments: []sdkecs.Deployment{ { Status: aws.String("ACTIVE"), ServiceConnectConfiguration: &sdkecs.ServiceConnectConfiguration{ - Enabled: aws.Bool(true), - Services: []*sdkecs.ServiceConnectService{ + Enabled: true, + Services: []sdkecs.ServiceConnectService{ { - ClientAliases: []*sdkecs.ServiceConnectClientAlias{ + ClientAliases: []sdkecs.ServiceConnectClientAlias{ { DnsName: aws.String("old"), - Port: aws.Int64(80), + Port: aws.Int32(int32(80)), }, }, }, @@ -1687,13 +1687,13 @@ func TestRunLocal_HostDiscovery(t *testing.T) { { Status: aws.String("PRIMARY"), ServiceConnectConfiguration: &sdkecs.ServiceConnectConfiguration{ - Enabled: aws.Bool(true), - Services: []*sdkecs.ServiceConnectService{ + Enabled: true, + Services: []sdkecs.ServiceConnectService{ { - ClientAliases: []*sdkecs.ServiceConnectClientAlias{ + ClientAliases: []sdkecs.ServiceConnectClientAlias{ { DnsName: aws.String("primary"), - Port: aws.Int64(80), + Port: aws.Int32(int32(80)), }, }, }, @@ -1703,17 +1703,17 @@ func TestRunLocal_HostDiscovery(t *testing.T) { }, }, { - Deployments: []*sdkecs.Deployment{ + Deployments: []sdkecs.Deployment{ { Status: aws.String("INACTIVE"), ServiceConnectConfiguration: &sdkecs.ServiceConnectConfiguration{ - Enabled: aws.Bool(true), - Services: []*sdkecs.ServiceConnectService{ + Enabled: true, + Services: []sdkecs.ServiceConnectService{ { - ClientAliases: []*sdkecs.ServiceConnectClientAlias{ + ClientAliases: []sdkecs.ServiceConnectClientAlias{ { DnsName: aws.String("inactive"), - Port: aws.Int64(80), + Port: aws.Int32(int32(80)), }, }, }, diff --git a/internal/pkg/cli/svc_delete.go b/internal/pkg/cli/svc_delete.go index 7981c37c0da..d97808d0ddd 100644 --- a/internal/pkg/cli/svc_delete.go +++ b/internal/pkg/cli/svc_delete.go @@ -101,7 +101,7 @@ func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { } opts.newSvcCleaner = func(sess *awssession.Session, env *config.Environment, manifestType string) cleaner { if manifestType == manifestinfo.StaticSiteType { - return clean.StaticSite(opts.appName, env.Name, opts.name, s3.New(sess, v2ConfigFromSessionRegion(sess)), awss3.New(sess)) + return clean.StaticSite(opts.appName, env.Name, opts.name, s3.New(sess, v2ConfigFromSessionRegion(sess)), awss3.New(v2ConfigFromSessionRegion(sess))) } return &clean.NoOp{} } diff --git a/internal/pkg/cli/svc_exec.go b/internal/pkg/cli/svc_exec.go index 20aaaf1e559..f53ae0cb15e 100644 --- a/internal/pkg/cli/svc_exec.go +++ b/internal/pkg/cli/svc_exec.go @@ -78,12 +78,12 @@ func newSvcExecOpts(vars execVars) (*svcExecOpts, error) { return ecs.New(s, v2ConfigFromSessionRegion(s)) }, newCommandExecutor: func(s *session.Session) ecsCommandExecutor { - return awsecs.New(s) + return awsecs.New(v2ConfigFromSessionRegion(s)) }, randInt: func(x int) int { return rand.Intn(x) }, - ssmPluginManager: exec.NewSSMPluginCommand(nil), + ssmPluginManager: exec.NewSSMPluginCommand(""), prompter: prompt.New(), sessProvider: sessProvider, }, nil diff --git a/internal/pkg/cli/svc_pause.go b/internal/pkg/cli/svc_pause.go index 0fda761d9ef..aa3981d7f24 100644 --- a/internal/pkg/cli/svc_pause.go +++ b/internal/pkg/cli/svc_pause.go @@ -93,7 +93,7 @@ func newSvcPauseOpts(vars svcPauseVars) (*svcPauseOpts, error) { if err != nil { return err } - opts.client = apprunner.New(sess) + opts.client = apprunner.New(v2ConfigFromSessionRegion(sess)) d, err := describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ App: opts.appName, Svc: opts.svcName, diff --git a/internal/pkg/cli/svc_resume.go b/internal/pkg/cli/svc_resume.go index 76969ed549d..ee78f8e94cd 100644 --- a/internal/pkg/cli/svc_resume.go +++ b/internal/pkg/cli/svc_resume.go @@ -165,7 +165,7 @@ func newResumeSvcOpts(vars resumeSvcVars) (*resumeSvcOpts, error) { if err != nil { return err } - a = apprunner.New(sess) + a = apprunner.New(v2ConfigFromSessionRegion(sess)) d, err = describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ App: opts.appName, Svc: opts.svcName, diff --git a/internal/pkg/cli/task_delete.go b/internal/pkg/cli/task_delete.go index 8158373505f..61433971319 100644 --- a/internal/pkg/cli/task_delete.go +++ b/internal/pkg/cli/task_delete.go @@ -111,7 +111,7 @@ func newDeleteTaskOpts(vars deleteTaskVars) (*deleteTaskOpts, error) { return ecr.New(v2ConfigFromSessionRegion(session)) }, newBucketEmptier: func(session *session.Session) bucketEmptier { - return s3.New(session) + return s3.New(v2ConfigFromSessionRegion(session)) }, }, nil } diff --git a/internal/pkg/cli/task_exec.go b/internal/pkg/cli/task_exec.go index e40dab3ddb7..fb7b29b4a8d 100644 --- a/internal/pkg/cli/task_exec.go +++ b/internal/pkg/cli/task_exec.go @@ -68,14 +68,14 @@ func newTaskExecOpts(vars taskExecVars) (*taskExecOpts, error) { return &taskExecOpts{ taskExecVars: vars, store: ssmStore, - ssmPluginManager: exec.NewSSMPluginCommand(nil), + ssmPluginManager: exec.NewSSMPluginCommand(""), prompter: prompter, newTaskSel: func(sess *session.Session) runningTaskSelector { return selector.NewTaskSelector(prompter, ecs.New(sess, v2ConfigFromSessionRegion(sess))) }, configSel: selector.NewConfigSelector(prompter, ssmStore), newCommandExecutor: func(s *session.Session) ecsCommandExecutor { - return awsecs.New(s) + return awsecs.New(v2ConfigFromSessionRegion(s)) }, provider: sessProvider, }, nil diff --git a/internal/pkg/cli/task_exec_test.go b/internal/pkg/cli/task_exec_test.go index 58a2d6ad0b4..0b8767e87e1 100644 --- a/internal/pkg/cli/task_exec_test.go +++ b/internal/pkg/cli/task_exec_test.go @@ -12,9 +12,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" - awsecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -307,7 +307,7 @@ func TestTaskExec_Execute(t *testing.T) { mockTask := &ecs.Task{ TaskArn: aws.String(mockTaskARN), ClusterArn: aws.String(mockClusterARN), - Containers: []*awsecs.Container{ + Containers: []awsecs.Container{ { Name: aws.String(mockContainerName), }, @@ -333,7 +333,7 @@ func TestTaskExec_Execute(t *testing.T) { inTask: &ecs.Task{ TaskArn: aws.String(mockBadTaskARN), ClusterArn: aws.String(mockClusterARN), - Containers: []*awsecs.Container{ + Containers: []awsecs.Container{ { Name: aws.String(mockContainerName), }, diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index b34686615bf..8b0619425c8 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -218,8 +218,8 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { return fmt.Errorf("configure task runner: %w", err) } opts.deployer = cloudformation.New(opts.sess, cloudformation.WithProgressTracker(os.Stderr)) - opts.defaultClusterGetter = awsecs.New(opts.sess) - opts.publicIPGetter = ec2.New(opts.sess) + opts.defaultClusterGetter = awsecs.New(v2ConfigFromSessionRegion(opts.sess)) + opts.publicIPGetter = ec2.New(v2ConfigFromSessionRegion(opts.sess)) return nil } @@ -234,7 +234,7 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { } opts.configureECSServiceDescriber = func(session *session.Session) ecs.ECSServiceDescriber { - return awsecs.New(session) + return awsecs.New(v2ConfigFromSessionRegion(session)) } opts.configureServiceDescriber = func(session *session.Session) ecs.ServiceDescriber { return ecs.New(session, v2ConfigFromSessionRegion(session)) @@ -243,7 +243,7 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { return ecs.New(session, v2ConfigFromSessionRegion(session)) } opts.configureUploader = func(session *session.Session) uploader { - return s3.New(session) + return s3.New(v2ConfigFromSessionRegion(session)) } opts.envCompatibilityChecker = func(app, env string) (versionCompatibilityChecker, error) { envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ @@ -264,8 +264,8 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { } func (o *runTaskOpts) configureRunner() (taskRunner, error) { - vpcGetter := ec2.New(o.sess) - ecsService := awsecs.New(o.sess) + vpcGetter := ec2.New(v2ConfigFromSessionRegion(o.sess)) + ecsService := awsecs.New(v2ConfigFromSessionRegion(o.sess)) if o.env != "" { deployStore, err := deploy.NewStore(o.provider, o.store) diff --git a/internal/pkg/deploy/cloudformation/cloudformation.go b/internal/pkg/deploy/cloudformation/cloudformation.go index 969e926f8ba..ab51340be4f 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation.go +++ b/internal/pkg/deploy/cloudformation/cloudformation.go @@ -214,8 +214,8 @@ func New(sess *session.Session, opts ...OptFn) CloudFormation { cfnClient: cloudformation.New(sess), codeStarClient: codestar.New(v2Config), cpClient: codepipeline.New(v2Config, v2Config), - ecsClient: ecs.New(sess), - cwClient: cloudwatch.New(sess, v2Config), + ecsClient: ecs.New(v2Config), + cwClient: cloudwatch.New(v2Config, v2Config), regionalClient: func(region string) cfnClient { return cloudformation.New(sess.Copy(&aws.Config{ Region: aws.String(region), @@ -226,11 +226,10 @@ func New(sess *session.Session, opts ...OptFn) CloudFormation { return ecr.New(regionalV2Config) }, appStackSet: stackset.New(sess), - s3Client: s3.New(sess), + s3Client: s3.New(v2Config), regionalS3Client: func(region string) s3Client { - return s3.New(sess.Copy(&aws.Config{ - Region: aws.String(region), - })) + regionalV2Config, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), region) + return s3.New(regionalV2Config) }, region: aws.StringValue(sess.Config.Region), console: new(discardFile), diff --git a/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go b/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go index 13f1ec32d47..664baf75fbf 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go +++ b/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go @@ -6,6 +6,7 @@ package cloudformation_test import ( + "context" "fmt" "io" "math/rand" @@ -18,6 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/iam" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" awss3 "github.com/aproint/copilot-cli/internal/pkg/aws/s3" + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" @@ -396,7 +398,9 @@ func Test_Environment_Deployment_Integration(t *testing.T) { cfClient := awsCF.New(sess) identity := identity.New(sess) s3ManagerClient := s3manager.NewUploader(sess) - s3Client := awss3.New(sess) + s3Config, err := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) + require.NoError(t, err) + s3Client := awss3.New(s3Config) iamClient := iam.New(sess) id, err := identity.Get() require.NoError(t, err) diff --git a/internal/pkg/deploy/cloudformation/cloudformation_test.go b/internal/pkg/deploy/cloudformation/cloudformation_test.go index 0984874c721..faff75362d1 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation_test.go +++ b/internal/pkg/deploy/cloudformation/cloudformation_test.go @@ -18,9 +18,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" - awsecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -350,9 +350,9 @@ Resources: }, }, nil).AnyTimes() mockECS.EXPECT().Service("cluster", "service").Return(&ecs.Service{ - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { - RolloutState: aws.String("COMPLETED"), + RolloutState: awsecs.DeploymentRolloutStateCompleted, Status: aws.String("PRIMARY"), TaskDefinition: aws.String("arn:aws:ecs:us-west-2:1111:task-definition/hello:10"), UpdatedAt: aws.Time(deploymentTime), diff --git a/internal/pkg/describe/backend_service.go b/internal/pkg/describe/backend_service.go index ee1e3258bdb..d12f1b31874 100644 --- a/internal/pkg/describe/backend_service.go +++ b/internal/pkg/describe/backend_service.go @@ -94,7 +94,8 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if err != nil { return nil, err } - return cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), nil + cfg := v2ConfigFromSessionRegion(sess) + return cloudwatch.New(cfg, cfg), nil } describer.initEnvDescribers = func(env string) (envDescriber, error) { if describer, ok := describer.envStackDescriber[env]; ok { diff --git a/internal/pkg/describe/lb_web_service.go b/internal/pkg/describe/lb_web_service.go index 104d50229a1..37217c95dba 100644 --- a/internal/pkg/describe/lb_web_service.go +++ b/internal/pkg/describe/lb_web_service.go @@ -132,7 +132,8 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if err != nil { return nil, err } - return cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), nil + cfg := v2ConfigFromSessionRegion(sess) + return cloudwatch.New(cfg, cfg), nil } return describer, nil } diff --git a/internal/pkg/describe/rd_web_service.go b/internal/pkg/describe/rd_web_service.go index 00eadff3a1c..fc8792c67b4 100644 --- a/internal/pkg/describe/rd_web_service.go +++ b/internal/pkg/describe/rd_web_service.go @@ -11,8 +11,6 @@ import ( "strings" "text/tabwriter" - "github.com/aws/aws-sdk-go/aws" - "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" @@ -174,7 +172,7 @@ func formatTracingConfiguration(configuration *apprunner.TraceConfiguration) *tr return nil } return &tracing{ - Vendor: aws.StringValue(configuration.Vendor), + Vendor: string(configuration.Vendor), } } diff --git a/internal/pkg/describe/rd_web_service_test.go b/internal/pkg/describe/rd_web_service_test.go index cb23ed5b736..d66e3df800b 100644 --- a/internal/pkg/describe/rd_web_service_test.go +++ b/internal/pkg/describe/rd_web_service_test.go @@ -11,7 +11,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/describe/mocks" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/service/apprunner/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -290,7 +290,7 @@ func TestRDWebServiceDescriber_Describe(t *testing.T) { }, Observability: apprunner.ObservabilityConfiguration{ TraceConfiguration: &apprunner.TraceConfiguration{ - Vendor: aws.String("mockVendor"), + Vendor: types.TracingVendor("mockVendor"), }, }, }, nil), diff --git a/internal/pkg/describe/service.go b/internal/pkg/describe/service.go index 1a4faa1a2de..2733d4b8e8f 100644 --- a/internal/pkg/describe/service.go +++ b/internal/pkg/describe/service.go @@ -18,7 +18,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" "github.com/aproint/copilot-cli/internal/pkg/ecs" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" ) @@ -169,7 +168,7 @@ func newAppRunnerServiceDescriber(opt NewServiceConfig) (*appRunnerServiceDescri return &appRunnerServiceDescriber{ WorkloadStackDescriber: stackDescriber, - apprunnerClient: apprunner.New(stackDescriber.sess), + apprunnerClient: apprunner.New(v2ConfigFromSessionRegion(stackDescriber.sess)), }, nil } @@ -225,7 +224,7 @@ func (d *ecsServiceDescriber) RollbackAlarmNames() ([]string, error) { if service.DeploymentConfiguration.Alarms == nil { return nil, nil } - return aws.StringValueSlice(service.DeploymentConfiguration.Alarms.AlarmNames), nil + return service.DeploymentConfiguration.Alarms.AlarmNames, nil } // ServiceARN retrieves the ARN of the app runner service. diff --git a/internal/pkg/describe/service_test.go b/internal/pkg/describe/service_test.go index 6135cec3602..bc112e88f95 100644 --- a/internal/pkg/describe/service_test.go +++ b/internal/pkg/describe/service_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - ecsapi "github.com/aws/aws-sdk-go/service/ecs" + ecsapi "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -48,10 +48,10 @@ func TestECSServiceDescriber_EnvVars(t *testing.T) { setupMocks: func(m ecsSvcDescriberMocks) { gomock.InOrder( m.mockECSClient.EXPECT().TaskDefinition(testApp, testEnv, testSvc).Return(&ecs.TaskDefinition{ - ContainerDefinitions: []*ecsapi.ContainerDefinition{ + ContainerDefinitions: []ecsapi.ContainerDefinition{ { Name: aws.String("container"), - Environment: []*ecsapi.KeyValuePair{ + Environment: []ecsapi.KeyValuePair{ { Name: aws.String("COPILOT_SERVICE_NAME"), Value: aws.String("my-svc"), @@ -159,9 +159,9 @@ func TestECSServiceDescriber_RollbackAlarmNames(t *testing.T) { m.mockECSClient.EXPECT().Service(testApp, testEnv, testSvc).Return(&awsecs.Service{ DeploymentConfiguration: &ecsapi.DeploymentConfiguration{ Alarms: &ecsapi.DeploymentAlarms{ - AlarmNames: []*string{aws.String("alarm1"), aws.String("alarm2")}, - Enable: aws.Bool(true), - Rollback: aws.Bool(true), + AlarmNames: []string{"alarm1", "alarm2"}, + Enable: true, + Rollback: true, }, }, }, nil), @@ -229,12 +229,12 @@ func TestECSServiceDescriber_ServiceConnectDNSNames(t *testing.T) { "success": { setupMocks: func(m ecsSvcDescriberMocks) { m.mockECSClient.EXPECT().Service(testApp, testEnv, testSvc).Return(&awsecs.Service{ - Deployments: []*ecsapi.Deployment{ + Deployments: []ecsapi.Deployment{ { ServiceConnectConfiguration: &ecsapi.ServiceConnectConfiguration{ - Enabled: aws.Bool(true), + Enabled: true, Namespace: aws.String("foobar.com"), - Services: []*ecsapi.ServiceConnectService{ + Services: []ecsapi.ServiceConnectService{ { PortName: aws.String("frontend"), }, @@ -310,10 +310,10 @@ func TestECSServiceDescriber_Secrets(t *testing.T) { setupMocks: func(m ecsSvcDescriberMocks) { gomock.InOrder( m.mockECSClient.EXPECT().TaskDefinition(testApp, testEnv, testSvc).Return(&ecs.TaskDefinition{ - ContainerDefinitions: []*ecsapi.ContainerDefinition{ + ContainerDefinitions: []ecsapi.ContainerDefinition{ { Name: aws.String("container"), - Secrets: []*ecsapi.Secret{ + Secrets: []ecsapi.Secret{ { Name: aws.String("GITHUB_WEBHOOK_SECRET"), ValueFrom: aws.String("GH_WEBHOOK_SECRET"), @@ -404,8 +404,8 @@ func TestECSServiceDescriber_Platform(t *testing.T) { gomock.InOrder( m.mockECSClient.EXPECT().TaskDefinition(testApp, testEnv, testSvc).Return(&ecs.TaskDefinition{ RuntimePlatform: &ecsapi.RuntimePlatform{ - CpuArchitecture: aws.String("ARM64"), - OperatingSystemFamily: aws.String("LINUX"), + CpuArchitecture: ecsapi.CPUArchitectureArm64, + OperatingSystemFamily: ecsapi.OSFamilyLinux, }, }, nil)) }, diff --git a/internal/pkg/describe/static_site.go b/internal/pkg/describe/static_site.go index a61048bb480..76602a62def 100644 --- a/internal/pkg/describe/static_site.go +++ b/internal/pkg/describe/static_site.go @@ -71,7 +71,8 @@ func NewStaticSiteDescriber(opt NewServiceConfig) (*StaticSiteDescriber, error) if err != nil { return nil, nil, err } - return awsS3.New(sess), s3.New(sess, v2ConfigFromSessionRegion(sess)), nil + cfg := v2ConfigFromSessionRegion(sess) + return awsS3.New(cfg), s3.New(sess, cfg), nil } return describer, nil } diff --git a/internal/pkg/describe/status_describe.go b/internal/pkg/describe/status_describe.go index 97c6c55c9f1..d4b50e60052 100644 --- a/internal/pkg/describe/status_describe.go +++ b/internal/pkg/describe/status_describe.go @@ -105,8 +105,8 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er env: opt.Env, svc: opt.Svc, svcDescriber: ecs.New(sess, v2ConfigFromSessionRegion(sess)), - cwSvcGetter: cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), - ecsSvcGetter: awsecs.New(sess), + cwSvcGetter: cloudwatch.New(v2ConfigFromSessionRegion(sess), v2ConfigFromSessionRegion(sess)), + ecsSvcGetter: awsecs.New(v2ConfigFromSessionRegion(sess)), aasSvcGetter: aas.New(v2ConfigFromSessionRegion(sess)), targetHealthGetter: elbv2.New(v2ConfigFromSessionRegion(sess)), }, nil @@ -149,7 +149,8 @@ func NewStaticSiteStatusDescriber(opt *NewServiceStatusConfig) (*staticSiteStatu if err != nil { return nil, nil, err } - return awsS3.New(sess), s3.New(sess, v2ConfigFromSessionRegion(sess)), nil + cfg := v2ConfigFromSessionRegion(sess) + return awsS3.New(cfg), s3.New(sess, cfg), nil } return describer, nil } diff --git a/internal/pkg/describe/status_describe_test.go b/internal/pkg/describe/status_describe_test.go index 4e16e17d722..2fe9f9c95ac 100644 --- a/internal/pkg/describe/status_describe_test.go +++ b/internal/pkg/describe/status_describe_test.go @@ -16,9 +16,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/elbv2" "github.com/aproint/copilot-cli/internal/pkg/describe/mocks" "github.com/aproint/copilot-cli/internal/pkg/ecs" + ecsapi "github.com/aws/aws-sdk-go-v2/service/ecs/types" elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" "github.com/aws/aws-sdk-go/aws" - ecsapi "github.com/aws/aws-sdk-go/service/ecs" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -179,9 +179,9 @@ func TestServiceStatus_Describe(t *testing.T) { { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/1234567890123456789"), StartedAt: &startTime, - HealthStatus: aws.String("HEALTHY"), + HealthStatus: ecsapi.HealthStatusHealthy, LastStatus: aws.String("RUNNING"), - Containers: []*ecsapi.Container{ + Containers: []ecsapi.Container{ { Image: aws.String("mockImageID1"), ImageDigest: aws.String("69671a968e8ec3648e2697417750e"), @@ -194,9 +194,9 @@ func TestServiceStatus_Describe(t *testing.T) { }, nil), m.ecsServiceGetter.EXPECT().Service(mockCluster, mockService).Return(&awsecs.Service{ Status: aws.String("ACTIVE"), - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(1), - Deployments: []*ecsapi.Deployment{ + DesiredCount: 1, + RunningCount: 1, + Deployments: []ecsapi.Deployment{ { UpdatedAt: &startTime, TaskDefinition: aws.String("mockTaskDefinition"), @@ -251,12 +251,12 @@ func TestServiceStatus_Describe(t *testing.T) { gomock.InOrder( m.serviceDescriber.EXPECT().DescribeService("mockApp", "mockEnv", "mockSvc").Return(mockServiceDesc, nil), m.ecsServiceGetter.EXPECT().Service(mockCluster, mockService).Return(&awsecs.Service{ - Deployments: []*ecsapi.Deployment{ + Deployments: []ecsapi.Deployment{ { UpdatedAt: aws.Time(startTime), }, }, - LoadBalancers: []*ecsapi.LoadBalancer{ + LoadBalancers: []ecsapi.LoadBalancer{ { TargetGroupArn: aws.String("group-1"), }, @@ -297,10 +297,10 @@ func TestServiceStatus_Describe(t *testing.T) { Tasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/task-with-private-ip-being-target"), - Attachments: []*ecsapi.Attachment{ + Attachments: []ecsapi.Attachment{ { Type: aws.String("ElasticNetworkInterface"), - Details: []*ecsapi.KeyValuePair{ + Details: []ecsapi.KeyValuePair{ { Name: aws.String("privateIPv4Address"), Value: aws.String("1.2.3.4"), @@ -311,10 +311,10 @@ func TestServiceStatus_Describe(t *testing.T) { }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/task-with-private-ip-not-a-target"), - Attachments: []*ecsapi.Attachment{ + Attachments: []ecsapi.Attachment{ { Type: aws.String("ElasticNetworkInterface"), - Details: []*ecsapi.KeyValuePair{ + Details: []ecsapi.KeyValuePair{ { Name: aws.String("privateIPv4Address"), Value: aws.String("5.6.7.8"), @@ -327,15 +327,15 @@ func TestServiceStatus_Describe(t *testing.T) { }, nil), m.ecsServiceGetter.EXPECT().Service(mockCluster, mockService).Return(&awsecs.Service{ Status: aws.String("ACTIVE"), - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(1), - Deployments: []*ecsapi.Deployment{ + DesiredCount: 1, + RunningCount: 1, + Deployments: []ecsapi.Deployment{ { UpdatedAt: &startTime, TaskDefinition: aws.String("mockTaskDefinition"), }, }, - LoadBalancers: []*ecsapi.LoadBalancer{ + LoadBalancers: []ecsapi.LoadBalancer{ { TargetGroupArn: aws.String("group-1"), }, @@ -462,9 +462,9 @@ func TestServiceStatus_Describe(t *testing.T) { { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/1234567890123456789"), StartedAt: &startTime, - HealthStatus: aws.String("HEALTHY"), + HealthStatus: ecsapi.HealthStatusHealthy, LastStatus: aws.String("RUNNING"), - Containers: []*ecsapi.Container{ + Containers: []ecsapi.Container{ { Image: aws.String("mockImageID1"), ImageDigest: aws.String("69671a968e8ec3648e2697417750e"), @@ -481,9 +481,9 @@ func TestServiceStatus_Describe(t *testing.T) { }, nil), m.ecsServiceGetter.EXPECT().Service(mockCluster, mockService).Return(&awsecs.Service{ Status: aws.String("ACTIVE"), - DesiredCount: aws.Int64(1), - RunningCount: aws.Int64(1), - Deployments: []*ecsapi.Deployment{ + DesiredCount: 1, + RunningCount: 1, + Deployments: []ecsapi.Deployment{ { UpdatedAt: &startTime, TaskDefinition: aws.String("mockTaskDefinition"), @@ -867,10 +867,10 @@ func Test_targetHealthForTasks(t *testing.T) { inTasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/task-with-private-ip-being-target"), - Attachments: []*ecsapi.Attachment{ + Attachments: []ecsapi.Attachment{ { Type: aws.String("ElasticNetworkInterface"), - Details: []*ecsapi.KeyValuePair{ + Details: []ecsapi.KeyValuePair{ { Name: aws.String("privateIPv4Address"), Value: aws.String("1.2.3.4"), @@ -881,10 +881,10 @@ func Test_targetHealthForTasks(t *testing.T) { }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/task-with-private-ip-being-target"), - Attachments: []*ecsapi.Attachment{ + Attachments: []ecsapi.Attachment{ { Type: aws.String("ElasticNetworkInterface"), - Details: []*ecsapi.KeyValuePair{ + Details: []ecsapi.KeyValuePair{ { Name: aws.String("privateIPv4Address"), Value: aws.String("4.3.2.1"), @@ -934,10 +934,10 @@ func Test_targetHealthForTasks(t *testing.T) { inTasks: []*awsecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/task-with-private-ip-being-target"), - Attachments: []*ecsapi.Attachment{ + Attachments: []ecsapi.Attachment{ { Type: aws.String("ElasticNetworkInterface"), - Details: []*ecsapi.KeyValuePair{ + Details: []ecsapi.KeyValuePair{ { Name: aws.String("privateIPv4Address"), Value: aws.String("42.42.42.42"), @@ -948,10 +948,10 @@ func Test_targetHealthForTasks(t *testing.T) { }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789012:task/mockCluster/not-target"), - Attachments: []*ecsapi.Attachment{ + Attachments: []ecsapi.Attachment{ { Type: aws.String("ElasticNetworkInterface"), - Details: []*ecsapi.KeyValuePair{ + Details: []ecsapi.KeyValuePair{ { Name: aws.String("privateIPv4Address"), Value: aws.String("4.3.2.1"), diff --git a/internal/pkg/describe/worker_service.go b/internal/pkg/describe/worker_service.go index e4ee9b023f8..dfafc1a958c 100644 --- a/internal/pkg/describe/worker_service.go +++ b/internal/pkg/describe/worker_service.go @@ -70,7 +70,8 @@ func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, e if err != nil { return nil, err } - return cloudwatch.New(sess, v2ConfigFromSessionRegion(sess)), nil + cfg := v2ConfigFromSessionRegion(sess) + return cloudwatch.New(cfg, cfg), nil } return describer, nil } diff --git a/internal/pkg/ecs/ecs.go b/internal/pkg/ecs/ecs.go index 76f60535b6b..59e836e5d07 100644 --- a/internal/pkg/ecs/ecs.go +++ b/internal/pkg/ecs/ecs.go @@ -82,7 +82,7 @@ type Client struct { func New(sess *session.Session, rgConfig awsv2.Config) *Client { return &Client{ rgGetter: resourcegroups.New(rgConfig), - ecsClient: ecs.New(sess), + ecsClient: ecs.New(rgConfig), } } @@ -574,14 +574,14 @@ func (c Client) HasNonZeroExitCode(taskARNs []string, cluster string) error { for _, describedTask := range tasks { for _, container := range describedTask.Containers { - if isContainerEssential[aws.StringValue(container.Name)] && aws.Int64Value(container.ExitCode) != 0 { + if isContainerEssential[aws.StringValue(container.Name)] && awsv2.ToInt32(container.ExitCode) != 0 { taskID, err := ecs.TaskID(aws.StringValue(describedTask.TaskArn)) if err != nil { return err } return &ErrExitCode{aws.StringValue(container.Name), taskID, - int(aws.Int64Value(container.ExitCode))} + int(awsv2.ToInt32(container.ExitCode))} } } } diff --git a/internal/pkg/ecs/ecs_test.go b/internal/pkg/ecs/ecs_test.go index f02e715972c..c8d3295ea8d 100644 --- a/internal/pkg/ecs/ecs_test.go +++ b/internal/pkg/ecs/ecs_test.go @@ -13,8 +13,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/ecs/mocks" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" - awsecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -588,7 +589,7 @@ func TestClient_ServiceConnectServices(t *testing.T) { m.ecsClient.EXPECT().ActiveClusters("mockARN1", "mockARN2").Return([]string{"mockARN1"}, nil) m.ecsClient.EXPECT().ActiveServices("mockARN1", []string{mockSvcARN}).Return([]string{mockSvcARN}, nil) m.ecsClient.EXPECT().Service(mockCluster, mockService).Return(&ecs.Service{ - Deployments: []*awsecs.Deployment{}, + Deployments: []awsecs.Deployment{}, }, nil) }, }, @@ -605,7 +606,7 @@ func TestClient_ServiceConnectServices(t *testing.T) { m.ecsClient.EXPECT().ActiveClusters("mockARN1", "mockARN2").Return([]string{"mockARN1"}, nil) m.ecsClient.EXPECT().ActiveServices("mockARN1", []string{mockSvcARN}).Return([]string{mockSvcARN}, nil) m.ecsClient.EXPECT().Service(mockCluster, mockService).Return(&ecs.Service{ - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ {}, }, }, nil) @@ -624,7 +625,7 @@ func TestClient_ServiceConnectServices(t *testing.T) { m.ecsClient.EXPECT().ActiveClusters("mockARN1", "mockARN2").Return([]string{"mockARN1"}, nil) m.ecsClient.EXPECT().ActiveServices("mockARN1", []string{mockSvcARN}).Return([]string{mockSvcARN}, nil) m.ecsClient.EXPECT().Service(mockCluster, mockService).Return(&ecs.Service{ - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { ServiceConnectConfiguration: &awsecs.ServiceConnectConfiguration{ Namespace: aws.String("namespace"), @@ -651,7 +652,7 @@ func TestClient_ServiceConnectServices(t *testing.T) { m.ecsClient.EXPECT().Service(mockCluster, mockService).Return(&ecs.Service{ ServiceArn: aws.String(mockSvcARN), ClusterArn: aws.String("cluster1"), - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { ServiceConnectConfiguration: &awsecs.ServiceConnectConfiguration{ Namespace: aws.String("namespace"), @@ -683,7 +684,7 @@ func TestClient_ServiceConnectServices(t *testing.T) { m.ecsClient.EXPECT().Service(mockCluster, mockService).Return(&ecs.Service{ ServiceArn: aws.String(mockSvcARN), ClusterArn: aws.String("cluster1"), - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { ServiceConnectConfiguration: &awsecs.ServiceConnectConfiguration{ Namespace: aws.String("namespace"), @@ -790,7 +791,7 @@ func TestClient_LastUpdatedAt(t *testing.T) { m.ecsClient.EXPECT().ActiveClusters("mockARN1", "mockARN2").Return([]string{"mockARN1"}, nil), m.ecsClient.EXPECT().ActiveServices("mockARN1", []string{mockSvcARN}).Return([]string{mockSvcARN}, nil), m.ecsClient.EXPECT().Service(mockCluster, mockService).Return(&ecs.Service{ - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { UpdatedAt: &mockTime, }, @@ -977,13 +978,13 @@ func TestClient_listActiveCopilotTasks(t *testing.T) { Return([]*ecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-task")}, }, }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-application")}, }, }, @@ -992,7 +993,7 @@ func TestClient_listActiveCopilotTasks(t *testing.T) { }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/987765654"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-task")}, }, }, @@ -1002,7 +1003,7 @@ func TestClient_listActiveCopilotTasks(t *testing.T) { wanted: []*ecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-task")}, }, }, @@ -1017,13 +1018,13 @@ func TestClient_listActiveCopilotTasks(t *testing.T) { Return([]*ecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-task")}, }, }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-application")}, }, }, @@ -1033,13 +1034,13 @@ func TestClient_listActiveCopilotTasks(t *testing.T) { wanted: []*ecs.Task{ { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-task")}, }, }, { TaskArn: aws.String("arn:aws:ecs:us-west-2:123456789:task/123456789"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ {Key: aws.String("copilot-application")}, }, }, @@ -1093,7 +1094,7 @@ func TestClient_StopWorkloadTasks(t *testing.T) { mockECSTask := []*ecs.Task{ { TaskArn: aws.String("deadbeef"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ { Key: aws.String("copilot-service"), }, @@ -1101,7 +1102,7 @@ func TestClient_StopWorkloadTasks(t *testing.T) { }, { TaskArn: aws.String("abcd"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ { Key: aws.String("copilot-service"), }, @@ -1223,7 +1224,7 @@ func TestClient_StopOneOffTasks(t *testing.T) { mockECSTask := []*ecs.Task{ { TaskArn: aws.String("deadbeef"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ { Key: aws.String("copilot-task"), }, @@ -1341,7 +1342,7 @@ func Test_StopDefaultClusterTasks(t *testing.T) { mockECSTask := []*ecs.Task{ { TaskArn: aws.String("deadbeef"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ { Key: aws.String("copilot-task"), }, @@ -1349,7 +1350,7 @@ func Test_StopDefaultClusterTasks(t *testing.T) { }, { TaskArn: aws.String("deadbeef"), - Tags: []*awsecs.Tag{ + Tags: []awsecs.Tag{ { Key: aws.String("copilot-service"), }, @@ -1449,11 +1450,11 @@ func TestServiceDescriber_TaskDefinition(t *testing.T) { m.EXPECT().TaskDefinition("phonetool-test-svc").Return(&ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String("the-container"), Image: aws.String("beautiful-image"), - Environment: []*awsecs.KeyValuePair{ + Environment: []awsecs.KeyValuePair{ { Name: aws.String("weather"), Value: aws.String("snowy"), @@ -1463,7 +1464,7 @@ func TestServiceDescriber_TaskDefinition(t *testing.T) { Value: aws.String("low"), }, }, - Secrets: []*awsecs.Secret{ + Secrets: []awsecs.Secret{ { Name: aws.String("secret-1"), ValueFrom: aws.String("first walk to Hokkaido"), @@ -1473,8 +1474,8 @@ func TestServiceDescriber_TaskDefinition(t *testing.T) { ValueFrom: aws.String("then get on the HAYABUSA"), }, }, - EntryPoint: aws.StringSlice([]string{"do", "not", "enter"}), - Command: aws.StringSlice([]string{"--force", "--verbose"}), + EntryPoint: []string{"do", "not", "enter"}, + Command: []string{"--force", "--verbose"}, }, }, }, nil) @@ -1482,11 +1483,11 @@ func TestServiceDescriber_TaskDefinition(t *testing.T) { wantedTaskDefinition: &ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String("the-container"), Image: aws.String("beautiful-image"), - Environment: []*awsecs.KeyValuePair{ + Environment: []awsecs.KeyValuePair{ { Name: aws.String("weather"), Value: aws.String("snowy"), @@ -1496,7 +1497,7 @@ func TestServiceDescriber_TaskDefinition(t *testing.T) { Value: aws.String("low"), }, }, - Secrets: []*awsecs.Secret{ + Secrets: []awsecs.Secret{ { Name: aws.String("secret-1"), ValueFrom: aws.String("first walk to Hokkaido"), @@ -1506,8 +1507,8 @@ func TestServiceDescriber_TaskDefinition(t *testing.T) { ValueFrom: aws.String("then get on the HAYABUSA"), }, }, - EntryPoint: aws.StringSlice([]string{"do", "not", "enter"}), - Command: aws.StringSlice([]string{"--force", "--verbose"}), + EntryPoint: []string{"do", "not", "enter"}, + Command: []string{"--force", "--verbose"}, }, }, }, @@ -1826,10 +1827,10 @@ func Test_HasNonZeroExitCode(t *testing.T) { TaskDefinitionArn: aws.String("arn:aws:ecs:us-west-2:1233454566:task-definition/CdkExampleStacknametaskdefinitionCA96DCAA:1"), StoppedReason: aws.String("Task failed to start"), LastStatus: aws.String("STOPPED"), - Containers: []*awsecs.Container{ + Containers: []awsecs.Container{ { Name: aws.String("the-one-and-only-one-container"), - ExitCode: aws.Int64(1), + ExitCode: awsv2.Int32(1), }, }, }, @@ -1837,14 +1838,14 @@ func Test_HasNonZeroExitCode(t *testing.T) { m.ecsClient.EXPECT().TaskDefinition("arn:aws:ecs:us-west-2:1233454566:task-definition/CdkExampleStacknametaskdefinitionCA96DCAA:1").Return(&ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String("the-one-and-only-one-container"), Image: aws.String("beautiful-image"), - EntryPoint: aws.StringSlice([]string{"enter", "here"}), - Command: aws.StringSlice([]string{"do", "not", "enter", "here"}), + EntryPoint: []string{"enter", "here"}, + Command: []string{"do", "not", "enter", "here"}, Essential: aws.Bool(true), - Environment: []*awsecs.KeyValuePair{ + Environment: []awsecs.KeyValuePair{ { Name: aws.String("enter"), Value: aws.String("no"), @@ -1854,7 +1855,7 @@ func Test_HasNonZeroExitCode(t *testing.T) { Value: aws.String("yes"), }, }, - Secrets: []*awsecs.Secret{ + Secrets: []awsecs.Secret{ { Name: aws.String("truth"), ValueFrom: aws.String("go-ask-the-wise"), diff --git a/internal/pkg/ecs/run_task_request_test.go b/internal/pkg/ecs/run_task_request_test.go index 3e806bec5ad..d696478432c 100644 --- a/internal/pkg/ecs/run_task_request_test.go +++ b/internal/pkg/ecs/run_task_request_test.go @@ -12,8 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/ecs/mocks" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" - awsecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -37,13 +37,13 @@ func Test_RunTaskRequestFromECSService(t *testing.T) { m.EXPECT().TaskDefinition("task-def").Return(&ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String("the-one-and-only-one-container"), Image: aws.String("beautiful-image"), - EntryPoint: aws.StringSlice([]string{"enter", "here"}), - Command: aws.StringSlice([]string{"do", "not", "enter", "here"}), - Environment: []*awsecs.KeyValuePair{ + EntryPoint: []string{"enter", "here"}, + Command: []string{"do", "not", "enter", "here"}, + Environment: []awsecs.KeyValuePair{ { Name: aws.String("enter"), Value: aws.String("no"), @@ -53,7 +53,7 @@ func Test_RunTaskRequestFromECSService(t *testing.T) { Value: aws.String("yes"), }, }, - Secrets: []*awsecs.Secret{ + Secrets: []awsecs.Secret{ { Name: aws.String("truth"), ValueFrom: aws.String("go-ask-the-wise"), @@ -127,7 +127,7 @@ func Test_RunTaskRequestFromECSService(t *testing.T) { m.EXPECT().TaskDefinition("task-def").Return(&ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String("the-first-container"), }, @@ -178,13 +178,13 @@ func Test_RunTaskRequestFromService(t *testing.T) { m.EXPECT().TaskDefinition(testApp, testEnv, testSvc).Return(&ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String(testSvc), Image: aws.String("beautiful-image"), - EntryPoint: aws.StringSlice([]string{"enter", "here"}), - Command: aws.StringSlice([]string{"do", "not", "enter", "here"}), - Environment: []*awsecs.KeyValuePair{ + EntryPoint: []string{"enter", "here"}, + Command: []string{"do", "not", "enter", "here"}, + Environment: []awsecs.KeyValuePair{ { Name: aws.String("enter"), Value: aws.String("no"), @@ -194,7 +194,7 @@ func Test_RunTaskRequestFromService(t *testing.T) { Value: aws.String("yes"), }, }, - Secrets: []*awsecs.Secret{ + Secrets: []awsecs.Secret{ { Name: aws.String("truth"), ValueFrom: aws.String("go-ask-the-wise"), @@ -292,13 +292,13 @@ func Test_RunTaskRequestFromJob(t *testing.T) { m.EXPECT().TaskDefinition(testApp, testEnv, testJob).Return(&ecs.TaskDefinition{ ExecutionRoleArn: aws.String("execution-role"), TaskRoleArn: aws.String("task-role"), - ContainerDefinitions: []*awsecs.ContainerDefinition{ + ContainerDefinitions: []awsecs.ContainerDefinition{ { Name: aws.String(testJob), Image: aws.String("beautiful-image"), - EntryPoint: aws.StringSlice([]string{"enter", "here"}), - Command: aws.StringSlice([]string{"do", "not", "enter", "here"}), - Environment: []*awsecs.KeyValuePair{ + EntryPoint: []string{"enter", "here"}, + Command: []string{"do", "not", "enter", "here"}, + Environment: []awsecs.KeyValuePair{ { Name: aws.String("enter"), Value: aws.String("no"), @@ -308,7 +308,7 @@ func Test_RunTaskRequestFromJob(t *testing.T) { Value: aws.String("yes"), }, }, - Secrets: []*awsecs.Secret{ + Secrets: []awsecs.Secret{ { Name: aws.String("truth"), ValueFrom: aws.String("go-ask-the-wise"), diff --git a/internal/pkg/exec/ssm_plugin.go b/internal/pkg/exec/ssm_plugin.go index ab511435465..d065368ed0b 100644 --- a/internal/pkg/exec/ssm_plugin.go +++ b/internal/pkg/exec/ssm_plugin.go @@ -12,9 +12,7 @@ import ( "net/http" "os" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ecs" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" ) const ( @@ -26,7 +24,7 @@ const ( // SSMPluginCommand represents commands that can be run to trigger the ssm plugin. type SSMPluginCommand struct { - sess *session.Session + region string runner http httpClient @@ -38,22 +36,22 @@ type SSMPluginCommand struct { } // NewSSMPluginCommand returns a SSMPluginCommand. -func NewSSMPluginCommand(s *session.Session) SSMPluginCommand { +func NewSSMPluginCommand(region string) SSMPluginCommand { return SSMPluginCommand{ runner: NewCmd(), - sess: s, + region: region, http: http.DefaultClient, } } // StartSession starts a session using the ssm plugin. -func (s SSMPluginCommand) StartSession(ssmSess *ecs.Session) error { +func (s SSMPluginCommand) StartSession(ssmSess *types.Session) error { response, err := json.Marshal(ssmSess) if err != nil { return fmt.Errorf("marshal session response: %w", err) } if err := s.runner.InteractiveRun(ssmPluginBinaryName, - []string{string(response), aws.StringValue(s.sess.Config.Region), startSessionAction}); err != nil { + []string{string(response), s.region, startSessionAction}); err != nil { return fmt.Errorf("start session: %w", err) } return nil diff --git a/internal/pkg/exec/ssm_plugin_test.go b/internal/pkg/exec/ssm_plugin_test.go index ebb62af7711..7a4aa4f2540 100644 --- a/internal/pkg/exec/ssm_plugin_test.go +++ b/internal/pkg/exec/ssm_plugin_test.go @@ -10,9 +10,8 @@ import ( "net/http/httptest" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ecs" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -32,15 +31,15 @@ func (c *fakeHTTPClient) Get(url string) (resp *http.Response, err error) { } func TestSSMPluginCommand_StartSession(t *testing.T) { - mockSession := &ecs.Session{ - SessionId: aws.String("mockSessionID"), - StreamUrl: aws.String("mockStreamURL"), - TokenValue: aws.String("mockTokenValue"), + mockSession := &types.Session{ + SessionId: awsv2.String("mockSessionID"), + StreamUrl: awsv2.String("mockStreamURL"), + TokenValue: awsv2.String("mockTokenValue"), } var mockRunner *Mockrunner mockError := errors.New("some error") tests := map[string]struct { - inSession *ecs.Session + inSession *types.Session setupMocks func(controller *gomock.Controller) wantedError error }{ @@ -68,11 +67,7 @@ func TestSSMPluginCommand_StartSession(t *testing.T) { tc.setupMocks(ctrl) s := SSMPluginCommand{ runner: mockRunner, - sess: &session.Session{ - Config: &aws.Config{ - Region: aws.String("us-west-2"), - }, - }, + region: "us-west-2", } err := s.StartSession(tc.inSession) if tc.wantedError != nil { diff --git a/internal/pkg/logging/task.go b/internal/pkg/logging/task.go index fcae136dc18..6fb1ea18d62 100644 --- a/internal/pkg/logging/task.go +++ b/internal/pkg/logging/task.go @@ -48,7 +48,7 @@ func NewTaskClient(sess *session.Session, groupName string, tasks []*task.Task) groupName: groupName, tasks: tasks, - taskDescriber: ecs.New(sess), + taskDescriber: ecs.New(v2ConfigFromSessionRegion(sess)), eventsLogger: cloudwatchlogs.New(v2ConfigFromSessionRegion(sess)), eventsWriter: log.OutputWriter, diff --git a/internal/pkg/manifest/loader.go b/internal/pkg/manifest/loader.go index 44eea188d9e..5f66274cdb7 100644 --- a/internal/pkg/manifest/loader.go +++ b/internal/pkg/manifest/loader.go @@ -4,7 +4,12 @@ package manifest import ( + "context" + "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/session" ) @@ -28,11 +33,16 @@ func newDynamicWorkloadManifest(mft workloadManifest) *DynamicWorkloadManifest { return &DynamicWorkloadManifest{ mft: mft, newSubnetIDsGetter: func(s *session.Session) subnetIDsGetter { - return ec2.New(s) + return ec2.New(v2ConfigFromSessionRegion(s)) }, } } +func v2ConfigFromSessionRegion(sess *session.Session) awsv2.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) + return cfg +} + // Manifest returns the manifest content. func (s *DynamicWorkloadManifest) Manifest() any { return s.mft diff --git a/internal/pkg/stream/ecs.go b/internal/pkg/stream/ecs.go index 6d9656e1820..595a8d03a7c 100644 --- a/internal/pkg/stream/ecs.go +++ b/internal/pkg/stream/ecs.go @@ -146,15 +146,14 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { var primaryDeploymentId string for _, deployment := range out.Deployments { status := aws.StringValue(deployment.Status) - desiredCount, runningCount := aws.Int64Value(deployment.DesiredCount), aws.Int64Value(deployment.RunningCount) rollingDeploy := ECSDeployment{ Status: status, TaskDefRevision: parseRevisionFromTaskDefARN(aws.StringValue(deployment.TaskDefinition)), - DesiredCount: int(desiredCount), - RunningCount: int(runningCount), - FailedCount: int(aws.Int64Value(deployment.FailedTasks)), - PendingCount: int(aws.Int64Value(deployment.PendingCount)), - RolloutState: aws.StringValue(deployment.RolloutState), + DesiredCount: int(deployment.DesiredCount), + RunningCount: int(deployment.RunningCount), + FailedCount: int(deployment.FailedTasks), + PendingCount: int(deployment.PendingCount), + RolloutState: string(deployment.RolloutState), CreatedAt: aws.TimeValue(deployment.CreatedAt), UpdatedAt: aws.TimeValue(deployment.UpdatedAt), Id: aws.StringValue(deployment.Id), @@ -211,8 +210,8 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { } var alarms []cloudwatch.AlarmStatus - if out.DeploymentConfiguration != nil && out.DeploymentConfiguration.Alarms != nil && aws.BoolValue(out.DeploymentConfiguration.Alarms.Enable) { - alarmNames := aws.StringValueSlice(out.DeploymentConfiguration.Alarms.AlarmNames) + if out.DeploymentConfiguration != nil && out.DeploymentConfiguration.Alarms != nil && out.DeploymentConfiguration.Alarms.Enable { + alarmNames := out.DeploymentConfiguration.Alarms.AlarmNames alarms, err = s.cw.AlarmStatuses(cloudwatch.WithNames(alarmNames)) if err != nil { if request.IsErrorThrottle(err) { diff --git a/internal/pkg/stream/ecs_test.go b/internal/pkg/stream/ecs_test.go index 708ba1d3a1f..0d742aaf6ba 100644 --- a/internal/pkg/stream/ecs_test.go +++ b/internal/pkg/stream/ecs_test.go @@ -11,8 +11,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aws/aws-sdk-go/aws" - awsecs "github.com/aws/aws-sdk-go/service/ecs" "github.com/stretchr/testify/require" ) @@ -85,9 +85,9 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { out: &ecs.Service{ DeploymentConfiguration: &awsecs.DeploymentConfiguration{ Alarms: &awsecs.DeploymentAlarms{ - AlarmNames: []*string{aws.String("alarm1"), aws.String("alarm2")}, - Enable: aws.Bool(true), - Rollback: aws.Bool(true), + AlarmNames: []string{"alarm1", "alarm2"}, + Enable: true, + Rollback: true, }, }, }, @@ -109,9 +109,9 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { out: &ecs.Service{ DeploymentConfiguration: &awsecs.DeploymentConfiguration{ Alarms: &awsecs.DeploymentAlarms{ - AlarmNames: []*string{aws.String("alarm1"), aws.String("alarm2")}, - Enable: aws.Bool(true), - Rollback: aws.Bool(true), + AlarmNames: []string{"alarm1", "alarm2"}, + Enable: true, + Rollback: true, }, }, }, @@ -140,24 +140,24 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { startDate := time.Date(2020, time.November, 23, 18, 0, 0, 0, time.UTC) m := mockECS{ out: &ecs.Service{ - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { - DesiredCount: aws.Int64(10), - FailedTasks: aws.Int64(0), - PendingCount: aws.Int64(0), - RolloutState: aws.String("COMPLETED"), - RunningCount: aws.Int64(10), + DesiredCount: 10, + FailedTasks: 0, + PendingCount: 0, + RolloutState: awsecs.DeploymentRolloutStateCompleted, + RunningCount: 10, Status: aws.String("PRIMARY"), TaskDefinition: aws.String("arn:aws:ecs:us-west-2:1111:task-definition/myapp-test-mysvc:2"), UpdatedAt: aws.Time(startDate), Id: aws.String("ecs-svc/123"), }, { - DesiredCount: aws.Int64(10), - FailedTasks: aws.Int64(10), - PendingCount: aws.Int64(0), - RolloutState: aws.String("FAILED"), - RunningCount: aws.Int64(0), + DesiredCount: 10, + FailedTasks: 10, + PendingCount: 0, + RolloutState: awsecs.DeploymentRolloutStateFailed, + RunningCount: 0, Status: aws.String("ACTIVE"), TaskDefinition: aws.String("arn:aws:ecs:us-west-2:1111:task-definition/myapp-test-mysvc:1"), UpdatedAt: aws.Time(oldStartDate), @@ -166,12 +166,12 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { }, DeploymentConfiguration: &awsecs.DeploymentConfiguration{ Alarms: &awsecs.DeploymentAlarms{ - AlarmNames: []*string{aws.String("alarm1"), aws.String("alarm2")}, - Enable: aws.Bool(true), - Rollback: aws.Bool(true), + AlarmNames: []string{"alarm1", "alarm2"}, + Enable: true, + Rollback: true, }, }, - Events: []*awsecs.ServiceEvent{ + Events: []awsecs.ServiceEvent{ { CreatedAt: aws.Time(startDate), Id: aws.String("id1"), @@ -301,21 +301,21 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { startDate := time.Date(2020, time.November, 23, 18, 0, 0, 0, time.UTC) m := mockECS{ out: &ecs.Service{ - Deployments: []*awsecs.Deployment{ + Deployments: []awsecs.Deployment{ { - DesiredCount: aws.Int64(10), - FailedTasks: aws.Int64(0), - PendingCount: aws.Int64(0), - RunningCount: aws.Int64(10), + DesiredCount: 10, + FailedTasks: 0, + PendingCount: 0, + RunningCount: 10, Status: aws.String("PRIMARY"), TaskDefinition: aws.String("arn:aws:ecs:us-west-2:1111:task-definition/myapp-test-mysvc:2"), UpdatedAt: aws.Time(startDate), }, { - DesiredCount: aws.Int64(10), - FailedTasks: aws.Int64(10), - PendingCount: aws.Int64(0), - RunningCount: aws.Int64(0), + DesiredCount: 10, + FailedTasks: 10, + PendingCount: 0, + RunningCount: 0, Status: aws.String("ACTIVE"), TaskDefinition: aws.String("arn:aws:ecs:us-west-2:1111:task-definition/myapp-test-mysvc:1"), UpdatedAt: aws.Time(oldStartDate), @@ -323,8 +323,8 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { }, DeploymentConfiguration: &awsecs.DeploymentConfiguration{ DeploymentCircuitBreaker: &awsecs.DeploymentCircuitBreaker{ - Enable: aws.Bool(false), - Rollback: aws.Bool(true), + Enable: false, + Rollback: true, }, }, }, @@ -369,7 +369,7 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { startDate := time.Date(2020, time.November, 23, 18, 0, 0, 0, time.UTC) m := mockECS{ out: &ecs.Service{ - Events: []*awsecs.ServiceEvent{ + Events: []awsecs.ServiceEvent{ { // Failure event Id: aws.String("1"), @@ -467,7 +467,7 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { startDate := time.Date(2020, time.November, 23, 18, 0, 0, 0, time.UTC) m := mockECS{ out: &ecs.Service{ - Events: []*awsecs.ServiceEvent{ + Events: []awsecs.ServiceEvent{ { // Failure event Id: aws.String("1"), @@ -499,7 +499,7 @@ func TestECSDeploymentStreamer_Fetch(t *testing.T) { startDate := time.Date(2020, time.November, 23, 18, 0, 0, 0, time.UTC) m := mockECS{ out: &ecs.Service{ - Events: []*awsecs.ServiceEvent{ + Events: []awsecs.ServiceEvent{ { // Failure event Id: aws.String("1"), diff --git a/internal/pkg/task/config_runner_test.go b/internal/pkg/task/config_runner_test.go index 1d561e8da0e..065be149237 100644 --- a/internal/pkg/task/config_runner_test.go +++ b/internal/pkg/task/config_runner_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - awsecs "github.com/aws/aws-sdk-go/service/ecs" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -25,10 +25,10 @@ const ( var taskWithENI = ecs.Task{ TaskArn: aws.String("task-1"), - Attachments: []*awsecs.Attachment{ + Attachments: []awsecs.Attachment{ { Type: aws.String(attachmentTypeName), - Details: []*awsecs.KeyValuePair{ + Details: []awsecs.KeyValuePair{ { Name: aws.String(detailsKeyName), Value: aws.String("eni-1"), diff --git a/internal/pkg/task/env_runner_test.go b/internal/pkg/task/env_runner_test.go index 4f3d5cb291a..ad0e6593002 100644 --- a/internal/pkg/task/env_runner_test.go +++ b/internal/pkg/task/env_runner_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - awsecs "github.com/aws/aws-sdk-go/service/ecs" + awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -63,10 +63,10 @@ func TestEnvRunner_Run(t *testing.T) { taskWithENI = ecs.Task{ TaskArn: aws.String("task-1"), - Attachments: []*awsecs.Attachment{ + Attachments: []awsecs.Attachment{ { Type: aws.String(attachmentTypeName), - Details: []*awsecs.KeyValuePair{ + Details: []awsecs.KeyValuePair{ { Name: aws.String(detailsKeyName), Value: aws.String("eni-1"), From 676465f05df7686c13f36ea20293404ab184e4a6 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 16:02:12 +0200 Subject: [PATCH 09/17] migrate another mega set --- internal/pkg/addon/addon_integration_test.go | 2 +- internal/pkg/addon/cloudformation.go | 14 +- internal/pkg/apprunner/apprunner.go | 3 +- internal/pkg/aws/cloudformation/changeset.go | 81 +-- .../pkg/aws/cloudformation/cloudformation.go | 187 ++++--- .../aws/cloudformation/cloudformation_test.go | 514 +++++++++--------- .../cloudformationtest/cloudformationtest.go | 2 +- internal/pkg/aws/cloudformation/errors.go | 17 +- internal/pkg/aws/cloudformation/interfaces.go | 37 +- .../mocks/mock_cloudformation.go | 293 ++++++---- internal/pkg/aws/cloudformation/stack.go | 36 +- internal/pkg/aws/cloudformation/stack_test.go | 12 +- .../pkg/aws/cloudformation/stackset/errors.go | 26 +- .../stackset/mocks/mock_stackset.go | 122 +++-- .../aws/cloudformation/stackset/stackset.go | 175 +++--- .../cloudformation/stackset/stackset_test.go | 190 +++---- .../pkg/aws/cloudformation/stackset/status.go | 26 +- .../cloudformation/stackset/status_test.go | 98 ++-- .../pkg/aws/cloudformation/stackstatus.go | 40 +- .../aws/cloudformation/stackstatus_test.go | 18 +- internal/pkg/cli/app_delete.go | 17 +- internal/pkg/cli/app_delete_test.go | 4 +- internal/pkg/cli/app_init.go | 9 +- internal/pkg/cli/app_upgrade.go | 2 +- internal/pkg/cli/cli.go | 12 +- internal/pkg/cli/config_store.go | 19 +- internal/pkg/cli/deploy.go | 10 +- internal/pkg/cli/deploy/aws_config.go | 15 - internal/pkg/cli/deploy/backend.go | 20 +- internal/pkg/cli/deploy/backend_test.go | 7 +- internal/pkg/cli/deploy/env.go | 42 +- internal/pkg/cli/deploy/env_test.go | 10 +- internal/pkg/cli/deploy/job_test.go | 2 +- internal/pkg/cli/deploy/lbws.go | 28 +- internal/pkg/cli/deploy/lbws_test.go | 5 +- internal/pkg/cli/deploy/mocks/mock_env.go | 6 +- internal/pkg/cli/deploy/patch/env.go | 5 +- internal/pkg/cli/deploy/rdws.go | 17 +- internal/pkg/cli/deploy/rdws_test.go | 7 +- internal/pkg/cli/deploy/static_site_test.go | 14 +- internal/pkg/cli/deploy/svc.go | 8 +- internal/pkg/cli/deploy/worker.go | 15 +- internal/pkg/cli/deploy/worker_test.go | 7 +- internal/pkg/cli/deploy/workload.go | 90 ++- internal/pkg/cli/deploy/workload_test.go | 7 +- internal/pkg/cli/deploy_test.go | 2 +- internal/pkg/cli/env_delete.go | 54 +- internal/pkg/cli/env_delete_test.go | 31 +- internal/pkg/cli/env_deploy_test.go | 2 +- internal/pkg/cli/env_init.go | 54 +- internal/pkg/cli/env_init_test.go | 97 ++-- internal/pkg/cli/env_package_test.go | 2 +- internal/pkg/cli/init.go | 16 +- internal/pkg/cli/init_test.go | 2 +- internal/pkg/cli/interfaces.go | 7 +- internal/pkg/cli/job_delete.go | 41 +- internal/pkg/cli/job_delete_test.go | 28 +- internal/pkg/cli/job_deploy.go | 17 +- internal/pkg/cli/job_init.go | 2 +- internal/pkg/cli/job_logs.go | 7 +- internal/pkg/cli/job_run.go | 15 +- internal/pkg/cli/mocks/mock_interfaces.go | 89 ++- internal/pkg/cli/mocks/mock_rg.go | 2 +- internal/pkg/cli/pipeline_delete.go | 6 +- internal/pkg/cli/pipeline_delete_test.go | 2 +- internal/pkg/cli/pipeline_deploy.go | 6 +- internal/pkg/cli/pipeline_init.go | 19 +- internal/pkg/cli/pipeline_init_test.go | 21 +- internal/pkg/cli/pipeline_package.go | 2 +- internal/pkg/cli/run_local.go | 199 ++++--- internal/pkg/cli/run_local_test.go | 184 +++---- internal/pkg/cli/svc_delete.go | 33 +- internal/pkg/cli/svc_delete_test.go | 24 +- internal/pkg/cli/svc_deploy.go | 21 +- internal/pkg/cli/svc_deploy_test.go | 4 +- internal/pkg/cli/svc_exec.go | 34 +- internal/pkg/cli/svc_exec_test.go | 37 +- internal/pkg/cli/svc_init.go | 4 +- internal/pkg/cli/svc_init_test.go | 2 +- internal/pkg/cli/svc_logs.go | 14 +- internal/pkg/cli/svc_logs_test.go | 2 +- internal/pkg/cli/svc_package.go | 17 +- internal/pkg/cli/task_delete.go | 101 ++-- internal/pkg/cli/task_delete_test.go | 92 ++-- internal/pkg/cli/task_exec.go | 46 +- internal/pkg/cli/task_exec_test.go | 23 +- internal/pkg/cli/task_run.go | 93 ++-- internal/pkg/cli/task_run_test.go | 95 ++-- internal/pkg/cli/validate.go | 10 +- internal/pkg/config/app.go | 49 +- internal/pkg/config/app_test.go | 32 +- internal/pkg/config/env.go | 41 +- internal/pkg/config/env_test.go | 34 +- internal/pkg/config/store.go | 30 +- internal/pkg/config/store_integration_test.go | 4 +- internal/pkg/config/store_test.go | 4 +- internal/pkg/config/workload.go | 40 +- internal/pkg/config/workload_test.go | 48 +- internal/pkg/deploy/app.go | 2 +- internal/pkg/deploy/cloudformation/app.go | 14 +- .../pkg/deploy/cloudformation/app_test.go | 58 +- .../deploy/cloudformation/cloudformation.go | 146 +++-- .../cloudformation_integration_test.go | 39 +- .../cloudformation/cloudformation_test.go | 103 ++-- internal/pkg/deploy/cloudformation/env.go | 14 +- .../pkg/deploy/cloudformation/env_test.go | 16 +- .../mocks/mock_cloudformation.go | 13 +- .../pkg/deploy/cloudformation/pipeline.go | 6 +- .../deploy/cloudformation/pipeline_test.go | 4 +- .../pkg/deploy/cloudformation/stack/app.go | 4 +- .../deploy/cloudformation/stack/app_test.go | 12 +- .../cloudformation/stack/backend_svc.go | 12 +- .../cloudformation/stack/backend_svc_test.go | 6 +- .../pkg/deploy/cloudformation/stack/env.go | 18 +- .../deploy/cloudformation/stack/env_test.go | 6 +- .../lb_grpc_web_service_integration_test.go | 7 +- ...lb_network_web_service_integration_test.go | 7 +- .../stack/lb_web_service_integration_test.go | 7 +- .../deploy/cloudformation/stack/lb_web_svc.go | 12 +- .../cloudformation/stack/lb_web_svc_test.go | 10 +- .../stack/mocks/mock_workload.go | 12 +- .../deploy/cloudformation/stack/pipeline.go | 2 +- .../cloudformation/stack/pipeline_test.go | 4 +- .../deploy/cloudformation/stack/rd_web_svc.go | 8 +- .../stack/rd_web_svc_integration_test.go | 7 +- .../cloudformation/stack/rd_web_svc_test.go | 12 +- .../cloudformation/stack/scheduled_job.go | 16 +- .../stack/scheduled_job_integration_test.go | 7 +- .../stack/scheduled_job_test.go | 18 +- .../stack/stack_local_integration_test.go | 6 +- .../cloudformation/stack/static_site.go | 8 +- .../stack/static_site_integration_test.go | 7 +- .../cloudformation/stack/static_site_test.go | 6 +- .../pkg/deploy/cloudformation/stack/tags.go | 6 +- .../pkg/deploy/cloudformation/stack/task.go | 4 +- .../deploy/cloudformation/stack/task_test.go | 4 +- .../cloudformation/stack/transformers.go | 64 +-- .../cloudformation/stack/transformers_test.go | 2 +- .../validate_template_integration_test.go | 23 +- ...windows_lb_web_service_integration_test.go | 7 +- .../stack/worker_service_integration_test.go | 7 +- .../deploy/cloudformation/stack/worker_svc.go | 10 +- .../cloudformation/stack/worker_svc_test.go | 6 +- .../deploy/cloudformation/stack/workload.go | 20 +- internal/pkg/deploy/cloudformation/task.go | 24 +- .../pkg/deploy/cloudformation/task_test.go | 12 +- .../deploy/cloudformation/workload_test.go | 17 +- internal/pkg/deploy/deploy.go | 2 +- internal/pkg/deploy/deploy_test.go | 2 +- internal/pkg/deploy/pipeline.go | 2 +- internal/pkg/deploy/pipeline_test.go | 2 +- internal/pkg/deploy/sns.go | 2 +- internal/pkg/describe/app.go | 7 +- internal/pkg/describe/aws_config.go | 15 - internal/pkg/describe/backend_service.go | 8 +- internal/pkg/describe/env.go | 5 +- internal/pkg/describe/lb_web_service.go | 18 +- internal/pkg/describe/pipeline.go | 6 +- internal/pkg/describe/pipeline_show.go | 6 +- internal/pkg/describe/pipeline_status.go | 4 +- internal/pkg/describe/service.go | 6 +- internal/pkg/describe/service_test.go | 2 +- internal/pkg/describe/stack/stack.go | 19 +- internal/pkg/describe/stack/stack_test.go | 10 +- internal/pkg/describe/static_site.go | 6 +- internal/pkg/describe/status_describe.go | 28 +- internal/pkg/describe/status_describe_test.go | 2 +- internal/pkg/describe/worker_service.go | 4 +- internal/pkg/describe/workload.go | 13 +- internal/pkg/ecs/ecs.go | 38 +- internal/pkg/ecs/ecs_test.go | 2 +- internal/pkg/ecs/run_task_request.go | 18 +- internal/pkg/ecs/run_task_request_test.go | 2 +- internal/pkg/initialize/workload.go | 4 +- internal/pkg/initialize/workload_test.go | 10 +- internal/pkg/logging/aws_config.go | 15 - internal/pkg/logging/task.go | 8 +- internal/pkg/logging/task_test.go | 2 +- internal/pkg/logging/workload.go | 7 +- internal/pkg/logging/workload_test.go | 2 +- internal/pkg/manifest/applyenv_test.go | 2 +- internal/pkg/manifest/backend_svc.go | 10 +- internal/pkg/manifest/backend_svc_test.go | 2 +- internal/pkg/manifest/env.go | 38 +- internal/pkg/manifest/env_test.go | 2 +- internal/pkg/manifest/http.go | 16 +- internal/pkg/manifest/http_test.go | 2 +- internal/pkg/manifest/job.go | 6 +- internal/pkg/manifest/job_test.go | 2 +- internal/pkg/manifest/lb_web_svc.go | 18 +- internal/pkg/manifest/lb_web_svc_test.go | 2 +- internal/pkg/manifest/loader.go | 22 +- internal/pkg/manifest/loader_test.go | 7 +- .../marshal_manifest_integration_test.go | 2 +- internal/pkg/manifest/rd_web_svc.go | 8 +- internal/pkg/manifest/rd_web_svc_test.go | 2 +- internal/pkg/manifest/static_site.go | 2 +- internal/pkg/manifest/static_site_test.go | 2 +- internal/pkg/manifest/storage.go | 6 +- internal/pkg/manifest/storage_test.go | 2 +- internal/pkg/manifest/svc.go | 70 +-- internal/pkg/manifest/svc_test.go | 2 +- internal/pkg/manifest/transform_test.go | 2 +- internal/pkg/manifest/union_test.go | 2 +- internal/pkg/manifest/validate.go | 106 ++-- internal/pkg/manifest/validate_env.go | 30 +- internal/pkg/manifest/validate_env_test.go | 2 +- internal/pkg/manifest/validate_test.go | 2 +- internal/pkg/manifest/worker_svc.go | 18 +- internal/pkg/manifest/worker_svc_test.go | 2 +- internal/pkg/manifest/workload.go | 37 +- internal/pkg/manifest/workload_ecs.go | 24 +- internal/pkg/manifest/workload_ecs_test.go | 2 +- internal/pkg/manifest/workload_test.go | 4 +- internal/pkg/runner/jobrunner/jobrunner.go | 6 +- .../pkg/runner/jobrunner/jobrunner_test.go | 2 +- internal/pkg/s3/s3.go | 3 +- internal/pkg/stream/cfnstack.go | 28 +- internal/pkg/stream/cfnstack_test.go | 34 +- internal/pkg/stream/cfnstackset.go | 4 +- internal/pkg/stream/cfnstackset_test.go | 8 +- internal/pkg/stream/ecs.go | 31 +- internal/pkg/stream/ecs_test.go | 2 +- internal/pkg/stream/throttle.go | 10 + internal/pkg/task/config_runner_test.go | 2 +- internal/pkg/task/env_runner_test.go | 2 +- internal/pkg/task/task.go | 6 +- internal/pkg/template/template_functions.go | 14 +- .../pkg/template/template_functions_test.go | 2 +- .../pkg/template/template_integration_test.go | 17 +- internal/pkg/template/workload.go | 8 +- internal/pkg/template/workload_test.go | 2 +- internal/pkg/term/progress/ecs.go | 18 +- internal/pkg/term/progress/ecs_test.go | 2 +- internal/pkg/term/selector/creds.go | 37 +- internal/pkg/term/selector/creds_test.go | 44 +- .../pkg/term/selector/mocks/mock_creds.go | 45 +- internal/pkg/term/selector/selector_test.go | 2 +- 238 files changed, 3062 insertions(+), 2947 deletions(-) delete mode 100644 internal/pkg/cli/deploy/aws_config.go delete mode 100644 internal/pkg/describe/aws_config.go delete mode 100644 internal/pkg/logging/aws_config.go create mode 100644 internal/pkg/stream/throttle.go diff --git a/internal/pkg/addon/addon_integration_test.go b/internal/pkg/addon/addon_integration_test.go index d3fc47adaf0..30815f254e6 100644 --- a/internal/pkg/addon/addon_integration_test.go +++ b/internal/pkg/addon/addon_integration_test.go @@ -13,7 +13,7 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/addon" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/addon/cloudformation.go b/internal/pkg/addon/cloudformation.go index 1adff1b1971..8a2009a0a98 100644 --- a/internal/pkg/addon/cloudformation.go +++ b/internal/pkg/addon/cloudformation.go @@ -153,10 +153,11 @@ func (t *cfnTemplate) assignNewNodesTo(tplName string) { // mergeTwoLevelMaps merges the top and second level keys of src node to dst. // It assumes that both nodes are nested maps. For example, a node can hold: // Mapping01: # Top Level is a map. -// Key01: # Second Level is also a map. -// Name: Value01 -// Key02: # Second Level. -// Name: Value02 +// +// Key01: # Second Level is also a map. +// Name: Value01 +// Key02: # Second Level. +// Name: Value02 // // If a second-level key exists in both src and dst but has different values, then returns an errKeyAlreadyExists. // If a second-level key exists in src but not in dst, it merges the second level key to dst. @@ -179,8 +180,9 @@ func mergeTwoLevelMaps(dst, src *yaml.Node) error { // mergeSingleLevelMaps merges the keys of src node to dst. // It assumes that both nodes are a map. For example, a node can hold: // Resources: -// MyResourceName: -// ... # If the contents of "MyResourceName" are not equal in both src and dst then err. +// +// MyResourceName: +// ... # If the contents of "MyResourceName" are not equal in both src and dst then err. // // If a key exists in both src and dst but has different values, then returns an errKeyAlreadyExists. // If a key exists in both src and dst and the values are equal, then do nothing. diff --git a/internal/pkg/apprunner/apprunner.go b/internal/pkg/apprunner/apprunner.go index e480e4eb31f..a71c50a8d4e 100644 --- a/internal/pkg/apprunner/apprunner.go +++ b/internal/pkg/apprunner/apprunner.go @@ -13,7 +13,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" awsv2 "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/apprunner/types" - "github.com/aws/aws-sdk-go/aws/session" ) const ( @@ -38,7 +37,7 @@ type Client struct { } // New inits a new Client. -func New(_ *session.Session, rgConfig awsv2.Config) *Client { +func New(rgConfig awsv2.Config) *Client { return &Client{ rgGetter: resourcegroups.New(rgConfig), appRunnerClient: apprunner.New(rgConfig), diff --git a/internal/pkg/aws/cloudformation/changeset.go b/internal/pkg/aws/cloudformation/changeset.go index 1a66d594056..59a99f62951 100644 --- a/internal/pkg/aws/cloudformation/changeset.go +++ b/internal/pkg/aws/cloudformation/changeset.go @@ -9,8 +9,9 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + awsv2 "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" "github.com/google/uuid" ) @@ -29,7 +30,7 @@ type ChangeSetDescription struct { ExecutionStatus string StatusReason string CreationTime time.Time - Changes []*cloudformation.Change + Changes []types.Change } type changeSetType int @@ -37,9 +38,9 @@ type changeSetType int func (t changeSetType) String() string { switch t { case updateChangeSetType: - return cloudformation.ChangeSetTypeUpdate + return string(types.ChangeSetTypeUpdate) default: - return cloudformation.ChangeSetTypeCreate + return string(types.ChangeSetTypeCreate) } } @@ -92,33 +93,33 @@ func (cs *changeSet) String() string { // create creates a ChangeSet, waits until it's created, and returns the ChangeSet ID on success. func (cs *changeSet) create(conf *stackConfig) error { input := &cloudformation.CreateChangeSetInput{ - ChangeSetName: aws.String(cs.name), - StackName: aws.String(cs.stackName), - ChangeSetType: aws.String(cs.csType.String()), + ChangeSetName: awsv2.String(cs.name), + StackName: awsv2.String(cs.stackName), + ChangeSetType: types.ChangeSetType(cs.csType.String()), Parameters: conf.Parameters, Tags: conf.Tags, RoleARN: conf.RoleARN, - IncludeNestedStacks: aws.Bool(true), - Capabilities: aws.StringSlice([]string{ - cloudformation.CapabilityCapabilityIam, - cloudformation.CapabilityCapabilityNamedIam, - cloudformation.CapabilityCapabilityAutoExpand, - }), + IncludeNestedStacks: awsv2.Bool(true), + Capabilities: []types.Capability{ + types.CapabilityCapabilityIam, + types.CapabilityCapabilityNamedIam, + types.CapabilityCapabilityAutoExpand, + }, } if conf.TemplateBody != "" { - input.TemplateBody = aws.String(conf.TemplateBody) + input.TemplateBody = awsv2.String(conf.TemplateBody) } if conf.TemplateURL != "" { - input.TemplateURL = aws.String(conf.TemplateURL) + input.TemplateURL = awsv2.String(conf.TemplateURL) } - out, err := cs.client.CreateChangeSet(input) + out, err := cs.client.CreateChangeSet(context.Background(), input) if err != nil { return fmt.Errorf("create %s: %w", cs, err) } - err = cs.client.WaitUntilChangeSetCreateCompleteWithContext(context.Background(), &cloudformation.DescribeChangeSetInput{ + err = cs.client.WaitUntilChangeSetCreateComplete(context.Background(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: out.Id, - }, waiters...) + }, waiterMaxDuration, withChangeSetCreateCompleteDelay) if err != nil { return fmt.Errorf("wait for creation of %s: %w", cs, err) } @@ -126,7 +127,7 @@ func (cs *changeSet) create(conf *stackConfig) error { // Using the full ID is essential in case the ChangeSet execution status is obsolete. // If we call DescribeChangeSet using the ChangeSet name and Stack name on an obsolete changeset, the results is empty. // On the other hand, if you DescribeChangeSet using the full ID then the ChangeSet summary is retrieved correctly. - cs.name = aws.StringValue(out.Id) + cs.name = awsv2.ToString(out.Id) return nil } @@ -134,20 +135,22 @@ func (cs *changeSet) create(conf *stackConfig) error { func (cs *changeSet) describe() (*ChangeSetDescription, error) { var executionStatus, statusReason string var creationTime time.Time - var changes []*cloudformation.Change + var changes []types.Change var nextToken *string for { - out, err := cs.client.DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ - ChangeSetName: aws.String(cs.name), - StackName: aws.String(cs.stackName), + out, err := cs.client.DescribeChangeSet(context.Background(), &cloudformation.DescribeChangeSetInput{ + ChangeSetName: awsv2.String(cs.name), + StackName: awsv2.String(cs.stackName), NextToken: nextToken, }) if err != nil { return nil, fmt.Errorf("describe %s: %w", cs, err) } - executionStatus = aws.StringValue(out.ExecutionStatus) - statusReason = aws.StringValue(out.StatusReason) - creationTime = aws.TimeValue(out.CreationTime) + executionStatus = string(out.ExecutionStatus) + statusReason = awsv2.ToString(out.StatusReason) + if out.CreationTime != nil { + creationTime = *out.CreationTime + } changes = append(changes, out.Changes...) nextToken = out.NextToken @@ -169,7 +172,7 @@ func (cs *changeSet) execute() error { if err != nil { return err } - if descr.ExecutionStatus != cloudformation.ExecutionStatusAvailable { + if descr.ExecutionStatus != string(types.ExecutionStatusAvailable) { // Ignore execute request if the change set does not contain any modifications. if descr.StatusReason == noChangesReason { return nil @@ -182,9 +185,9 @@ func (cs *changeSet) execute() error { descr: descr, } } - _, err = cs.client.ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{ - ChangeSetName: aws.String(cs.name), - StackName: aws.String(cs.stackName), + _, err = cs.client.ExecuteChangeSet(context.Background(), &cloudformation.ExecuteChangeSetInput{ + ChangeSetName: awsv2.String(cs.name), + StackName: awsv2.String(cs.stackName), }) if err != nil { return fmt.Errorf("execute %s: %w", cs, err) @@ -198,7 +201,7 @@ func (cs *changeSet) executeWithNoRollback() error { if err != nil { return err } - if descr.ExecutionStatus != cloudformation.ExecutionStatusAvailable { + if descr.ExecutionStatus != string(types.ExecutionStatusAvailable) { // Ignore execute request if the change set does not contain any modifications. if descr.StatusReason == noChangesReason { return nil @@ -211,10 +214,10 @@ func (cs *changeSet) executeWithNoRollback() error { descr: descr, } } - _, err = cs.client.ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{ - ChangeSetName: aws.String(cs.name), - StackName: aws.String(cs.stackName), - DisableRollback: aws.Bool(true), + _, err = cs.client.ExecuteChangeSet(context.Background(), &cloudformation.ExecuteChangeSetInput{ + ChangeSetName: awsv2.String(cs.name), + StackName: awsv2.String(cs.stackName), + DisableRollback: awsv2.Bool(true), }) if err != nil { return fmt.Errorf("execute %s: %w", cs, err) @@ -253,9 +256,9 @@ func (cs *changeSet) createAndExecute(conf *stackConfig) error { // delete removes the change set. func (cs *changeSet) delete() error { - _, err := cs.client.DeleteChangeSet(&cloudformation.DeleteChangeSetInput{ - ChangeSetName: aws.String(cs.name), - StackName: aws.String(cs.stackName), + _, err := cs.client.DeleteChangeSet(context.Background(), &cloudformation.DeleteChangeSetInput{ + ChangeSetName: awsv2.String(cs.name), + StackName: awsv2.String(cs.stackName), }) if err != nil { return fmt.Errorf("delete %s: %w", cs, err) diff --git a/internal/pkg/aws/cloudformation/cloudformation.go b/internal/pkg/aws/cloudformation/cloudformation.go index 239bd07ef11..e99ca7957be 100644 --- a/internal/pkg/aws/cloudformation/cloudformation.go +++ b/internal/pkg/aws/cloudformation/cloudformation.go @@ -10,26 +10,25 @@ import ( "fmt" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudformation" + awsv2 "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" ) -type eventMatcher func(*cloudformation.StackEvent) bool +type eventMatcher func(types.StackEvent) bool var eventErrorStates = []string{ - cloudformation.ResourceStatusCreateFailed, - cloudformation.ResourceStatusDeleteFailed, - cloudformation.ResourceStatusImportFailed, - cloudformation.ResourceStatusUpdateFailed, - cloudformation.ResourceStatusImportRollbackFailed, + string(types.ResourceStatusCreateFailed), + string(types.ResourceStatusDeleteFailed), + string(types.ResourceStatusImportFailed), + string(types.ResourceStatusUpdateFailed), + string(types.ResourceStatusImportRollbackFailed), } -var waiters = []request.WaiterOption{ - request.WithWaiterDelay(request.ConstantWaiterDelay(5 * time.Second)), // How long to wait in between poll cfn for updates. - request.WithWaiterMaxAttempts(1080), // Wait for at most 90 mins for any cfn action. -} +const ( + waiterDelay = 5 * time.Second + waiterMaxDuration = 90 * time.Minute +) // CloudFormation represents a client to make requests to AWS CloudFormation. type CloudFormation struct { @@ -37,12 +36,32 @@ type CloudFormation struct { } // New creates a new CloudFormation client. -func New(s *session.Session) *CloudFormation { +func New(cfg awsv2.Config) *CloudFormation { return &CloudFormation{ - cloudformation.New(s), + clientWithWaiters{Client: cloudformation.NewFromConfig(cfg)}, } } +type clientWithWaiters struct { + *cloudformation.Client +} + +func (c clientWithWaiters) WaitUntilChangeSetCreateComplete(ctx context.Context, in *cloudformation.DescribeChangeSetInput, maxWaitDur time.Duration, optFns ...func(*cloudformation.ChangeSetCreateCompleteWaiterOptions)) error { + return cloudformation.NewChangeSetCreateCompleteWaiter(c.Client).Wait(ctx, in, maxWaitDur, optFns...) +} + +func (c clientWithWaiters) WaitUntilStackCreateComplete(ctx context.Context, in *cloudformation.DescribeStacksInput, maxWaitDur time.Duration, optFns ...func(*cloudformation.StackCreateCompleteWaiterOptions)) error { + return cloudformation.NewStackCreateCompleteWaiter(c.Client).Wait(ctx, in, maxWaitDur, optFns...) +} + +func (c clientWithWaiters) WaitUntilStackUpdateComplete(ctx context.Context, in *cloudformation.DescribeStacksInput, maxWaitDur time.Duration, optFns ...func(*cloudformation.StackUpdateCompleteWaiterOptions)) error { + return cloudformation.NewStackUpdateCompleteWaiter(c.Client).Wait(ctx, in, maxWaitDur, optFns...) +} + +func (c clientWithWaiters) WaitUntilStackDeleteComplete(ctx context.Context, in *cloudformation.DescribeStacksInput, maxWaitDur time.Duration, optFns ...func(*cloudformation.StackDeleteCompleteWaiterOptions)) error { + return cloudformation.NewStackDeleteCompleteWaiter(c.Client).Wait(ctx, in, maxWaitDur, optFns...) +} + // Create deploys a new CloudFormation stack using Change Sets. // If the stack already exists in a failed state, deletes the stack and re-creates it. func (c *CloudFormation) Create(stack *Stack) (changeSetID string, err error) { @@ -55,7 +74,7 @@ func (c *CloudFormation) Create(stack *Stack) (changeSetID string, err error) { // If the stack does not exist, create it. return c.create(stack) } - status := StackStatus(aws.StringValue(descr.StackStatus)) + status := StackStatus(descr.StackStatus) if status.requiresCleanup() { // If the stack exists, but failed to create, we'll clean it up and then re-create it. if err := c.DeleteAndWait(stack.Name); err != nil { @@ -94,9 +113,9 @@ func (c *CloudFormation) DescribeChangeSet(changeSetID, stackName string) (*Chan // WaitForCreate blocks until the stack is created or until the max attempt window expires. func (c *CloudFormation) WaitForCreate(ctx context.Context, stackName string) error { - err := c.client.WaitUntilStackCreateCompleteWithContext(ctx, &cloudformation.DescribeStacksInput{ - StackName: aws.String(stackName), - }, waiters...) + err := c.client.WaitUntilStackCreateComplete(ctx, &cloudformation.DescribeStacksInput{ + StackName: awsv2.String(stackName), + }, waiterMaxDuration, withStackCreateCompleteDelay) if err != nil { return fmt.Errorf("wait until stack %s create is complete: %w", stackName, err) } @@ -110,7 +129,7 @@ func (c *CloudFormation) Update(stack *Stack) (changeSetID string, err error) { if err != nil { return "", err } - status := StackStatus(aws.StringValue(descr.StackStatus)) + status := StackStatus(descr.StackStatus) if status.InProgress() { return "", &ErrStackUpdateInProgress{ Name: stack.Name, @@ -129,9 +148,9 @@ func (c *CloudFormation) UpdateAndWait(stack *Stack) error { // WaitForUpdate blocks until the stack is updated or until the max attempt window expires. func (c *CloudFormation) WaitForUpdate(ctx context.Context, stackName string) error { - err := c.client.WaitUntilStackUpdateCompleteWithContext(ctx, &cloudformation.DescribeStacksInput{ - StackName: aws.String(stackName), - }, waiters...) + err := c.client.WaitUntilStackUpdateComplete(ctx, &cloudformation.DescribeStacksInput{ + StackName: awsv2.String(stackName), + }, waiterMaxDuration, withStackUpdateCompleteDelay) if err != nil { return fmt.Errorf("wait until stack %s update is complete: %w", stackName, err) } @@ -141,8 +160,8 @@ func (c *CloudFormation) WaitForUpdate(ctx context.Context, stackName string) er // Delete removes an existing CloudFormation stack. // If the stack doesn't exist then do nothing. func (c *CloudFormation) Delete(stackName string) error { - _, err := c.client.DeleteStack(&cloudformation.DeleteStackInput{ - StackName: aws.String(stackName), + _, err := c.client.DeleteStack(context.Background(), &cloudformation.DeleteStackInput{ + StackName: awsv2.String(stackName), }) if err != nil { if !stackDoesNotExist(err) { @@ -156,23 +175,23 @@ func (c *CloudFormation) Delete(stackName string) error { // DeleteAndWait calls Delete then blocks until the stack is deleted or until the max attempt window expires. func (c *CloudFormation) DeleteAndWait(stackName string) error { return c.deleteAndWait(&cloudformation.DeleteStackInput{ - StackName: aws.String(stackName), + StackName: awsv2.String(stackName), }) } // DeleteAndWaitWithRoleARN is DeleteAndWait but with a role ARN that AWS CloudFormation assumes to delete the stack. func (c *CloudFormation) DeleteAndWaitWithRoleARN(stackName, roleARN string) error { return c.deleteAndWait(&cloudformation.DeleteStackInput{ - StackName: aws.String(stackName), - RoleARN: aws.String(roleARN), + StackName: awsv2.String(stackName), + RoleARN: awsv2.String(roleARN), }) } // Describe returns a description of an existing stack. // If the stack does not exist, returns ErrStackNotFound. func (c *CloudFormation) Describe(name string) (*StackDescription, error) { - out, err := c.client.DescribeStacks(&cloudformation.DescribeStacksInput{ - StackName: aws.String(name), + out, err := c.client.DescribeStacks(context.Background(), &cloudformation.DescribeStacksInput{ + StackName: awsv2.String(name), }) if err != nil { if stackDoesNotExist(err) { @@ -183,10 +202,15 @@ func (c *CloudFormation) Describe(name string) (*StackDescription, error) { if len(out.Stacks) == 0 { return nil, &ErrStackNotFound{name: name} } - descr := StackDescription(*out.Stacks[0]) + descr := StackDescription(out.Stacks[0]) return &descr, nil } +// DescribeStackEvents describes stack events using a background context. +func (c *CloudFormation) DescribeStackEvents(input *cloudformation.DescribeStackEventsInput) (*cloudformation.DescribeStackEventsOutput, error) { + return c.client.DescribeStackEvents(context.Background(), input) +} + // Exists returns true if the CloudFormation stack exists, false otherwise. // If an error occurs for another reason than ErrStackNotFound, then returns the error. func (c *CloudFormation) Exists(name string) (bool, error) { @@ -206,38 +230,38 @@ type MetadataOpts *cloudformation.GetTemplateSummaryInput // MetadataWithStackName sets up the stack name for cloudformation.GetTemplateSummaryInput. func MetadataWithStackName(name string) MetadataOpts { return &cloudformation.GetTemplateSummaryInput{ - StackName: aws.String(name), + StackName: awsv2.String(name), } } // MetadataWithStackSetName sets up the stack set name for cloudformation.GetTemplateSummaryInput. func MetadataWithStackSetName(name string) MetadataOpts { return &cloudformation.GetTemplateSummaryInput{ - StackSetName: aws.String(name), + StackSetName: awsv2.String(name), } } // Metadata returns the Metadata property of the CloudFormation stack(set)'s template. // If the stack does not exist, returns ErrStackNotFound. func (c *CloudFormation) Metadata(opt MetadataOpts) (string, error) { - out, err := c.GetTemplateSummary(opt) + out, err := c.GetTemplateSummary(context.Background(), opt) if err != nil { if stackDoesNotExist(err) { - if aws.StringValue(opt.StackName) != "" { - return "", &ErrStackNotFound{name: aws.StringValue(opt.StackName)} + if awsv2.ToString(opt.StackName) != "" { + return "", &ErrStackNotFound{name: awsv2.ToString(opt.StackName)} } - return "", &ErrStackNotFound{name: aws.StringValue(opt.StackSetName)} + return "", &ErrStackNotFound{name: awsv2.ToString(opt.StackSetName)} } return "", fmt.Errorf("get template summary: %w", err) } - return aws.StringValue(out.Metadata), nil + return awsv2.ToString(out.Metadata), nil } // TemplateBody returns the template body of an existing stack. // If the stack does not exist, returns ErrStackNotFound. func (c *CloudFormation) TemplateBody(name string) (string, error) { - out, err := c.client.GetTemplate(&cloudformation.GetTemplateInput{ - StackName: aws.String(name), + out, err := c.client.GetTemplate(context.Background(), &cloudformation.GetTemplateInput{ + StackName: awsv2.String(name), }) if err != nil { if stackDoesNotExist(err) { @@ -245,15 +269,15 @@ func (c *CloudFormation) TemplateBody(name string) (string, error) { } return "", fmt.Errorf("get template %s: %w", name, err) } - return aws.StringValue(out.TemplateBody), nil + return awsv2.ToString(out.TemplateBody), nil } // TemplateBodyFromChangeSet returns the template body of a stack based on a change set. // If the stack does not exist, then returns ErrStackNotFound. func (c *CloudFormation) TemplateBodyFromChangeSet(changeSetID, stackName string) (string, error) { - out, err := c.client.GetTemplate(&cloudformation.GetTemplateInput{ - ChangeSetName: aws.String(changeSetID), - StackName: aws.String(stackName), + out, err := c.client.GetTemplate(context.Background(), &cloudformation.GetTemplateInput{ + ChangeSetName: awsv2.String(changeSetID), + StackName: awsv2.String(stackName), }) if err != nil { if stackDoesNotExist(err) { @@ -261,7 +285,7 @@ func (c *CloudFormation) TemplateBodyFromChangeSet(changeSetID, stackName string } return "", fmt.Errorf("get template for stack %s and change set %s: %w", stackName, changeSetID, err) } - return aws.StringValue(out.TemplateBody), nil + return awsv2.ToString(out.TemplateBody), nil } // Outputs returns the outputs of a stack description. @@ -272,30 +296,27 @@ func (c *CloudFormation) Outputs(stack *Stack) (map[string]string, error) { } outputs := make(map[string]string) for _, output := range stackDescription.Outputs { - outputs[aws.StringValue(output.OutputKey)] = aws.StringValue(output.OutputValue) + outputs[awsv2.ToString(output.OutputKey)] = awsv2.ToString(output.OutputValue) } return outputs, nil } // Events returns the list of stack events in **chronological** order. func (c *CloudFormation) Events(stackName string) ([]StackEvent, error) { - return c.events(stackName, func(in *cloudformation.StackEvent) bool { return true }) + return c.events(stackName, func(in types.StackEvent) bool { return true }) } // StackResources returns the list of resources created as part of a CloudFormation stack. func (c *CloudFormation) StackResources(name string) ([]*StackResource, error) { - out, err := c.DescribeStackResources(&cloudformation.DescribeStackResourcesInput{ - StackName: aws.String(name), + out, err := c.DescribeStackResources(context.Background(), &cloudformation.DescribeStackResourcesInput{ + StackName: awsv2.String(name), }) if err != nil { return nil, fmt.Errorf("describe resources for stack %s: %w", name, err) } var resources []*StackResource for _, r := range out.StackResources { - if r == nil { - continue - } - sr := StackResource(*r) + sr := StackResource(r) resources = append(resources, &sr) } return resources, nil @@ -305,16 +326,16 @@ func (c *CloudFormation) events(stackName string, match eventMatcher) ([]StackEv var nextToken *string var events []StackEvent for { - out, err := c.client.DescribeStackEvents(&cloudformation.DescribeStackEventsInput{ + out, err := c.client.DescribeStackEvents(context.Background(), &cloudformation.DescribeStackEventsInput{ NextToken: nextToken, - StackName: aws.String(stackName), + StackName: awsv2.String(stackName), }) if err != nil { return nil, fmt.Errorf("describe stack events for stack %s: %w", stackName, err) } for _, event := range out.StackEvents { if match(event) { - events = append(events, StackEvent(*event)) + events = append(events, StackEvent(event)) } } nextToken = out.NextToken @@ -333,9 +354,9 @@ func (c *CloudFormation) events(stackName string, match eventMatcher) ([]StackEv // ErrorEvents returns the list of events with "failed" status in **chronological order** func (c *CloudFormation) ErrorEvents(stackName string) ([]StackEvent, error) { - return c.events(stackName, func(in *cloudformation.StackEvent) bool { + return c.events(stackName, func(in types.StackEvent) bool { for _, status := range eventErrorStates { - if aws.StringValue(in.ResourceStatus) == status { + if string(in.ResourceStatus) == status { return true } } @@ -352,7 +373,7 @@ func (c *CloudFormation) ListStacksWithTags(tags map[string]string) ([]StackDesc var summaries []StackDescription for { - out, err := c.client.DescribeStacks(&cloudformation.DescribeStacksInput{ + out, err := c.client.DescribeStacks(context.Background(), &cloudformation.DescribeStacksInput{ NextToken: nextToken, }) if err != nil { @@ -362,7 +383,7 @@ func (c *CloudFormation) ListStacksWithTags(tags map[string]string) ([]StackDesc for _, summary := range out.Stacks { stackTags := summary.Tags if match(stackTags) { - summaries = append(summaries, StackDescription(*summary)) + summaries = append(summaries, StackDescription(summary)) } } nextToken = out.NextToken @@ -376,8 +397,8 @@ func (c *CloudFormation) ListStacksWithTags(tags map[string]string) ([]StackDesc // CancelUpdateStack attempts to cancel the update for a CloudFormation stack specified by the stackName. // Returns an error if failed to cancel CloudFormation stack update. func (c *CloudFormation) CancelUpdateStack(stackName string) error { - if _, err := c.client.CancelUpdateStack(&cloudformation.CancelUpdateStackInput{ - StackName: aws.String(stackName), + if _, err := c.client.CancelUpdateStack(context.Background(), &cloudformation.CancelUpdateStackInput{ + StackName: awsv2.String(stackName), }); err != nil { if !stackDoesNotExist(err) && !cancelUpdateStackNotInUpdateProgress(err) { return fmt.Errorf("cancel update stack: %w", err) @@ -409,32 +430,32 @@ func (c *CloudFormation) update(stack *Stack) (string, error) { } func (c *CloudFormation) deleteAndWait(in *cloudformation.DeleteStackInput) error { - _, err := c.client.DeleteStack(in) + _, err := c.client.DeleteStack(context.Background(), in) if err != nil { if !stackDoesNotExist(err) { - return fmt.Errorf("delete stack %s: %w", aws.StringValue(in.StackName), err) + return fmt.Errorf("delete stack %s: %w", awsv2.ToString(in.StackName), err) } return nil // If the stack is already deleted, don't wait for it. } - err = c.client.WaitUntilStackDeleteCompleteWithContext(context.Background(), &cloudformation.DescribeStacksInput{ + err = c.client.WaitUntilStackDeleteComplete(context.Background(), &cloudformation.DescribeStacksInput{ StackName: in.StackName, - }, waiters...) + }, waiterMaxDuration, withStackDeleteCompleteDelay) if err != nil { - return fmt.Errorf("wait until stack %s delete is complete: %w", aws.StringValue(in.StackName), err) + return fmt.Errorf("wait until stack %s delete is complete: %w", awsv2.ToString(in.StackName), err) } return nil } // makeTagMatcher takes a set of wanted tags and returns a function which matches if the given set of // `cloudformation.Tag`s contains tags with all wanted keys and values -func makeTagMatcher(wantedTags map[string]string) func([]*cloudformation.Tag) bool { +func makeTagMatcher(wantedTags map[string]string) func([]types.Tag) bool { // Match all stacks if no desired tags are specified. if len(wantedTags) == 0 { - return func([]*cloudformation.Tag) bool { return true } + return func([]types.Tag) bool { return true } } - return func(tags []*cloudformation.Tag) bool { + return func(tags []types.Tag) bool { // Define a map to determine whether each wanted tag is a match. tagsMatched := make(map[string]bool, len(wantedTags)) @@ -445,8 +466,8 @@ func makeTagMatcher(wantedTags map[string]string) func([]*cloudformation.Tag) bo // Loop over all tags on the stack and decide whether they match any of the wanted tags. for _, tag := range tags { - tagKey := aws.StringValue(tag.Key) - tagValue := aws.StringValue(tag.Value) + tagKey := awsv2.ToString(tag.Key) + tagValue := awsv2.ToString(tag.Value) if wantedTags[tagKey] == tagValue || wantedTags[tagKey] == "" { tagsMatched[tagKey] = true } @@ -462,3 +483,23 @@ func makeTagMatcher(wantedTags map[string]string) func([]*cloudformation.Tag) bo return true } } + +func withChangeSetCreateCompleteDelay(o *cloudformation.ChangeSetCreateCompleteWaiterOptions) { + o.MinDelay = waiterDelay + o.MaxDelay = waiterDelay +} + +func withStackCreateCompleteDelay(o *cloudformation.StackCreateCompleteWaiterOptions) { + o.MinDelay = waiterDelay + o.MaxDelay = waiterDelay +} + +func withStackUpdateCompleteDelay(o *cloudformation.StackUpdateCompleteWaiterOptions) { + o.MinDelay = waiterDelay + o.MaxDelay = waiterDelay +} + +func withStackDeleteCompleteDelay(o *cloudformation.StackDeleteCompleteWaiterOptions) { + o.MinDelay = waiterDelay + o.MaxDelay = waiterDelay +} diff --git a/internal/pkg/aws/cloudformation/cloudformation_test.go b/internal/pkg/aws/cloudformation/cloudformation_test.go index 2ca09aebfed..fd233eafd96 100644 --- a/internal/pkg/aws/cloudformation/cloudformation_test.go +++ b/internal/pkg/aws/cloudformation/cloudformation_test.go @@ -11,9 +11,10 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "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" + "github.com/aws/smithy-go" "github.com/golang/mock/gomock" "github.com/google/uuid" "github.com/stretchr/testify/require" @@ -27,10 +28,17 @@ const ( var ( mockStack = NewStack("id", "template") - errDoesNotExist = awserr.New("ValidationError", "does not exist", nil) - errStackNotInUpdateProgress = awserr.New("ValidationError", "CancelUpdateStack cannot be called from current stack status", nil) + errDoesNotExist = apiErr("ValidationError", "does not exist") + errStackNotInUpdateProgress = apiErr("ValidationError", "CancelUpdateStack cannot be called from current stack status") ) +func apiErr(code, message string) error { + return &smithy.GenericAPIError{ + Code: code, + Message: message, + } +} + func TestCloudFormation_Create(t *testing.T) { testCases := map[string]struct { inStack *Stack @@ -41,7 +49,7 @@ func TestCloudFormation_Create(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{ + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{ StackName: aws.String(mockStack.Name), }).Return(nil, errors.New("some unexpected error")) return m @@ -52,10 +60,10 @@ func TestCloudFormation_Create(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{ { - StackStatus: aws.String(cloudformation.StackStatusCreateInProgress), + StackStatus: types.StackStatusCreateInProgress, }, }, }, nil) @@ -69,10 +77,10 @@ func TestCloudFormation_Create(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{ { - StackStatus: aws.String(cloudformation.StackStatusCreateComplete), + StackStatus: types.StackStatusCreateComplete, }, }, }, nil) @@ -81,7 +89,7 @@ func TestCloudFormation_Create(t *testing.T) { wantedErr: &ErrStackAlreadyExists{ Name: mockStack.Name, Stack: &StackDescription{ - StackStatus: aws.String(cloudformation.StackStatusCreateComplete), + StackStatus: types.StackStatusCreateComplete, }, }, }, @@ -89,7 +97,7 @@ func TestCloudFormation_Create(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) addCreateDeployCalls(m) return m }, @@ -98,44 +106,44 @@ func TestCloudFormation_Create(t *testing.T) { inStack: NewStack("id", "template", WithDisableRollback()), createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, errDoesNotExist) - m.EXPECT().CreateChangeSet(&cloudformation.CreateChangeSetInput{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().CreateChangeSet(gomock.Any(), &cloudformation.CreateChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStack.Name), - ChangeSetType: aws.String(cloudformation.ChangeSetTypeCreate), + ChangeSetType: types.ChangeSetTypeCreate, TemplateBody: aws.String(mockStack.TemplateBody), Parameters: nil, Tags: nil, RoleARN: nil, IncludeNestedStacks: aws.Bool(true), - Capabilities: aws.StringSlice([]string{ - cloudformation.CapabilityCapabilityIam, - cloudformation.CapabilityCapabilityNamedIam, - cloudformation.CapabilityCapabilityAutoExpand, - }), + Capabilities: []types.Capability{ + types.CapabilityCapabilityIam, + types.CapabilityCapabilityNamedIam, + types.CapabilityCapabilityAutoExpand, + }, }).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetID), StackId: aws.String(mockStack.Name), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), - }, gomock.Any()) - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + }, gomock.Any(), gomock.Any()) + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String(mockStack.Name), }).Return(&cloudformation.DescribeChangeSetOutput{ - Changes: []*cloudformation.Change{ + Changes: []types.Change{ { - ResourceChange: &cloudformation.ResourceChange{ + ResourceChange: &types.ResourceChange{ ResourceType: aws.String("ecs service"), }, - Type: aws.String(cloudformation.ChangeTypeResource), + Type: types.ChangeTypeResource, }, }, - ExecutionStatus: aws.String(cloudformation.ExecutionStatusAvailable), + ExecutionStatus: types.ExecutionStatusAvailable, StatusReason: aws.String("some reason"), }, nil) - m.EXPECT().ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{ + m.EXPECT().ExecuteChangeSet(gomock.Any(), &cloudformation.ExecuteChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String(mockStack.Name), DisableRollback: aws.Bool(true), @@ -147,7 +155,7 @@ func TestCloudFormation_Create(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) addCreateDeployCalls(m) return m }, @@ -156,17 +164,17 @@ func TestCloudFormation_Create(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{ { - StackStatus: aws.String(cloudformation.StackStatusRollbackComplete), + StackStatus: types.StackStatusRollbackComplete, }, }, }, nil) - m.EXPECT().DeleteStack(&cloudformation.DeleteStackInput{ + m.EXPECT().DeleteStack(gomock.Any(), &cloudformation.DeleteStackInput{ StackName: aws.String(mockStack.Name), }) - m.EXPECT().WaitUntilStackDeleteCompleteWithContext(gomock.Any(), &cloudformation.DescribeStacksInput{ + m.EXPECT().WaitUntilStackDeleteComplete(gomock.Any(), &cloudformation.DescribeStacksInput{ StackName: aws.String(mockStack.Name), }, gomock.Any(), gomock.Any()) addCreateDeployCalls(m) @@ -209,7 +217,7 @@ func TestCloudFormation_DescribeChangeSet(t *testing.T) { defer ctrl.Finish() m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeChangeSet(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) cfn := CloudFormation{ client: m, } @@ -228,35 +236,35 @@ func TestCloudFormation_DescribeChangeSet(t *testing.T) { defer ctrl.Finish() m := mocks.NewMockclient(ctrl) - wantedChanges := []*cloudformation.Change{ + wantedChanges := []types.Change{ { - ResourceChange: &cloudformation.ResourceChange{ + ResourceChange: &types.ResourceChange{ ResourceType: aws.String("AWS::ECS::Service"), }, }, { - ResourceChange: &cloudformation.ResourceChange{ + ResourceChange: &types.ResourceChange{ ResourceType: aws.String("AWS::ECS::Cluster"), }, }, } gomock.InOrder( - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String("phonetool-test"), NextToken: nil, }).Return(&cloudformation.DescribeChangeSetOutput{ - Changes: []*cloudformation.Change{ + Changes: []types.Change{ wantedChanges[0], }, NextToken: aws.String("1111"), }, nil), - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String("phonetool-test"), NextToken: aws.String("1111"), }).Return(&cloudformation.DescribeChangeSetOutput{ - Changes: []*cloudformation.Change{ + Changes: []types.Change{ wantedChanges[1], }, }, nil), @@ -283,9 +291,9 @@ func TestCloudFormation_WaitForCreate(t *testing.T) { "wraps error on failure": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().WaitUntilStackCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeStacksInput{ + m.EXPECT().WaitUntilStackCreateComplete(gomock.Any(), &cloudformation.DescribeStacksInput{ StackName: aws.String(mockStack.Name), - }, gomock.Any()).Return(errors.New("some error")) + }, gomock.Any(), gomock.Any()).Return(errors.New("some error")) return m }, wantedErr: fmt.Errorf("wait until stack %s create is complete: %w", mockStack.Name, errors.New("some error")), @@ -324,8 +332,8 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateInProgress)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateInProgress}}, }, nil) return m }, @@ -337,13 +345,13 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(nil, errors.New("some error")) - m.EXPECT().DescribeChangeSet(gomock.Any()). + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(&cloudformation.DescribeChangeSetOutput{ - Changes: []*cloudformation.Change{}, + Changes: []types.Change{}, StatusReason: aws.String("some other reason"), }, nil) return m @@ -354,16 +362,16 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(errors.New("some error")) - m.EXPECT().DescribeChangeSet(gomock.Any()). + }, gomock.Any(), gomock.Any()).Return(errors.New("some error")) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(&cloudformation.DescribeChangeSetOutput{ StatusReason: aws.String("some reason"), }, nil) @@ -375,15 +383,15 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(nil, errors.New("some error")) - m.EXPECT().DescribeChangeSet(gomock.Any()). + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(&cloudformation.DescribeChangeSetOutput{ NextToken: aws.String("mockNext"), }, nil) - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), NextToken: aws.String("mockNext")}). @@ -396,16 +404,16 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(nil, errors.New("some error")) - m.EXPECT().DescribeChangeSet(gomock.Any()). + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(&cloudformation.DescribeChangeSetOutput{ - Changes: []*cloudformation.Change{}, + Changes: []types.Change{}, StatusReason: aws.String("The submitted information didn't contain changes. Submit different information to create a change set."), }, nil) - m.EXPECT().DeleteChangeSet(&cloudformation.DeleteChangeSetInput{ + m.EXPECT().DeleteChangeSet(gomock.Any(), &cloudformation.DeleteChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), }).Return(nil, nil) @@ -417,16 +425,16 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(nil) - m.EXPECT().DescribeChangeSet(gomock.Any()). + }, gomock.Any(), gomock.Any()).Return(nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(nil, errors.New("some error")) return m }, @@ -436,31 +444,31 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(&cloudformation.CreateChangeSetInput{ + m.EXPECT().CreateChangeSet(gomock.Any(), &cloudformation.CreateChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), - ChangeSetType: aws.String("UPDATE"), + ChangeSetType: types.ChangeSetTypeUpdate, IncludeNestedStacks: aws.Bool(true), - Capabilities: aws.StringSlice([]string{ - cloudformation.CapabilityCapabilityIam, - cloudformation.CapabilityCapabilityNamedIam, - cloudformation.CapabilityCapabilityAutoExpand, - }), + Capabilities: []types.Capability{ + types.CapabilityCapabilityIam, + types.CapabilityCapabilityNamedIam, + types.CapabilityCapabilityAutoExpand, + }, TemplateBody: aws.String("template"), }).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(nil) - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + }, gomock.Any(), gomock.Any()).Return(nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName)}). Return(&cloudformation.DescribeChangeSetOutput{ - ExecutionStatus: aws.String(cloudformation.ExecutionStatusUnavailable), + ExecutionStatus: types.ExecutionStatusUnavailable, StatusReason: aws.String(noChangesReason), }, nil) return m @@ -470,18 +478,18 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(nil) - m.EXPECT().DescribeChangeSet(gomock.Any()). + }, gomock.Any(), gomock.Any()).Return(nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(&cloudformation.DescribeChangeSetOutput{ - ExecutionStatus: aws.String(cloudformation.ExecutionStatusUnavailable), + ExecutionStatus: types.ExecutionStatusUnavailable, StatusReason: aws.String("some other reason"), }, nil) return m @@ -492,20 +500,20 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ + m.EXPECT().CreateChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(nil) - m.EXPECT().DescribeChangeSet(gomock.Any()). + }, gomock.Any(), gomock.Any()).Return(nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()). Return(&cloudformation.DescribeChangeSetOutput{ - ExecutionStatus: aws.String(cloudformation.ExecutionStatusAvailable), + ExecutionStatus: types.ExecutionStatusAvailable, }, nil) - m.EXPECT().ExecuteChangeSet(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().ExecuteChangeSet(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedErr: fmt.Errorf("execute change set copilot-31323334-3536-4738-b930-313233333435 for stack id: some error"), @@ -514,33 +522,33 @@ func TestCloudFormation_Update(t *testing.T) { inStack: NewStack("id", "template", WithDisableRollback()), createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(&cloudformation.CreateChangeSetInput{ + m.EXPECT().CreateChangeSet(gomock.Any(), &cloudformation.CreateChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), - ChangeSetType: aws.String("UPDATE"), + ChangeSetType: types.ChangeSetTypeUpdate, IncludeNestedStacks: aws.Bool(true), - Capabilities: aws.StringSlice([]string{ - cloudformation.CapabilityCapabilityIam, - cloudformation.CapabilityCapabilityNamedIam, - cloudformation.CapabilityCapabilityAutoExpand, - }), + Capabilities: []types.Capability{ + types.CapabilityCapabilityIam, + types.CapabilityCapabilityNamedIam, + types.CapabilityCapabilityAutoExpand, + }, TemplateBody: aws.String("template"), }).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(nil) - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + }, gomock.Any(), gomock.Any()).Return(nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName)}). Return(&cloudformation.DescribeChangeSetOutput{ - ExecutionStatus: aws.String(cloudformation.ExecutionStatusAvailable), + ExecutionStatus: types.ExecutionStatusAvailable, }, nil) - m.EXPECT().ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{ + m.EXPECT().ExecuteChangeSet(gomock.Any(), &cloudformation.ExecuteChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), DisableRollback: aws.Bool(true), @@ -552,33 +560,33 @@ func TestCloudFormation_Update(t *testing.T) { inStack: mockStack, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{StackStatus: aws.String(cloudformation.StackStatusUpdateComplete)}}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{{StackStatus: types.StackStatusUpdateComplete}}, }, nil) - m.EXPECT().CreateChangeSet(&cloudformation.CreateChangeSetInput{ + m.EXPECT().CreateChangeSet(gomock.Any(), &cloudformation.CreateChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), - ChangeSetType: aws.String("UPDATE"), + ChangeSetType: types.ChangeSetTypeUpdate, IncludeNestedStacks: aws.Bool(true), - Capabilities: aws.StringSlice([]string{ - cloudformation.CapabilityCapabilityIam, - cloudformation.CapabilityCapabilityNamedIam, - cloudformation.CapabilityCapabilityAutoExpand, - }), + Capabilities: []types.Capability{ + types.CapabilityCapabilityIam, + types.CapabilityCapabilityNamedIam, + types.CapabilityCapabilityAutoExpand, + }, TemplateBody: aws.String("template"), }).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetName), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), - }, gomock.Any()).Return(nil) - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + }, gomock.Any(), gomock.Any()).Return(nil) + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName)}). Return(&cloudformation.DescribeChangeSetOutput{ - ExecutionStatus: aws.String(cloudformation.ExecutionStatusAvailable), + ExecutionStatus: types.ExecutionStatusAvailable, }, nil) - m.EXPECT().ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{ + m.EXPECT().ExecuteChangeSet(gomock.Any(), &cloudformation.ExecuteChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStackName), }).Return(&cloudformation.ExecuteChangeSetOutput{}, nil) @@ -622,17 +630,17 @@ func TestCloudFormation_UpdateAndWait(t *testing.T) { "waits until the stack is created": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{ { - StackStatus: aws.String(cloudformation.StackStatusCreateComplete), + StackStatus: types.StackStatusCreateComplete, }, }, }, nil) addUpdateDeployCalls(m) - m.EXPECT().WaitUntilStackUpdateCompleteWithContext(gomock.Any(), &cloudformation.DescribeStacksInput{ + m.EXPECT().WaitUntilStackUpdateComplete(gomock.Any(), &cloudformation.DescribeStacksInput{ StackName: aws.String(mockStack.Name), - }, gomock.Any()).Return(nil) + }, gomock.Any(), gomock.Any()).Return(nil) return m }, }, @@ -668,7 +676,7 @@ func TestCloudFormation_Delete(t *testing.T) { "fails on unexpected error": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DeleteStack(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DeleteStack(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedErr: fmt.Errorf("delete stack %s: %w", mockStack.Name, errors.New("some error")), @@ -676,7 +684,7 @@ func TestCloudFormation_Delete(t *testing.T) { "exits successfully if stack does not exist": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DeleteStack(&cloudformation.DeleteStackInput{ + m.EXPECT().DeleteStack(gomock.Any(), &cloudformation.DeleteStackInput{ StackName: aws.String(mockStack.Name), }).Return(nil, errDoesNotExist) return m @@ -685,7 +693,7 @@ func TestCloudFormation_Delete(t *testing.T) { "exits successfully if stack can be deleted": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DeleteStack(&cloudformation.DeleteStackInput{ + m.EXPECT().DeleteStack(gomock.Any(), &cloudformation.DeleteStackInput{ StackName: aws.String(mockStack.Name), }).Return(nil, nil) return m @@ -719,20 +727,20 @@ func TestCloudFormation_DeleteAndWait(t *testing.T) { "skip waiting if stack does not exist": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DeleteStack(gomock.Any()).Return(nil, errDoesNotExist) - m.EXPECT().WaitUntilStackDeleteCompleteWithContext(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) + m.EXPECT().DeleteStack(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().WaitUntilStackDeleteComplete(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) return m }, }, "wait for stack deletion if stack is being deleted": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DeleteStack(&cloudformation.DeleteStackInput{ + m.EXPECT().DeleteStack(gomock.Any(), &cloudformation.DeleteStackInput{ StackName: aws.String(mockStack.Name), }).Return(nil, nil) - m.EXPECT().WaitUntilStackDeleteCompleteWithContext(gomock.Any(), &cloudformation.DescribeStacksInput{ + m.EXPECT().WaitUntilStackDeleteComplete(gomock.Any(), &cloudformation.DescribeStacksInput{ StackName: aws.String(mockStack.Name), - }, gomock.Any()) + }, gomock.Any(), gomock.Any()) return m }, }, @@ -767,7 +775,7 @@ func TestStackDescriber_Metadata(t *testing.T) { "should wrap cfn error on unexpected error": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplateSummary(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().GetTemplateSummary(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, @@ -776,7 +784,7 @@ func TestStackDescriber_Metadata(t *testing.T) { "should return ErrStackNotFound if stack does not exist": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplateSummary(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().GetTemplateSummary(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) return m }, @@ -786,7 +794,7 @@ func TestStackDescriber_Metadata(t *testing.T) { isStackSet: true, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplateSummary(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().GetTemplateSummary(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) return m }, @@ -795,7 +803,7 @@ func TestStackDescriber_Metadata(t *testing.T) { "should return Metadata property of template summary on success for stack": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplateSummary(&cloudformation.GetTemplateSummaryInput{ + m.EXPECT().GetTemplateSummary(gomock.Any(), &cloudformation.GetTemplateSummaryInput{ StackName: aws.String("phonetoolStack"), }).Return(&cloudformation.GetTemplateSummaryOutput{ Metadata: aws.String("hello"), @@ -809,7 +817,7 @@ func TestStackDescriber_Metadata(t *testing.T) { isStackSet: true, createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplateSummary(&cloudformation.GetTemplateSummaryInput{ + m.EXPECT().GetTemplateSummary(gomock.Any(), &cloudformation.GetTemplateSummaryInput{ StackSetName: aws.String("phonetoolStackSet"), }).Return(&cloudformation.GetTemplateSummaryOutput{ Metadata: aws.String("hello"), @@ -857,7 +865,7 @@ func TestCloudFormation_Describe(t *testing.T) { "return ErrStackNotFound if stack does not exist": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) return m }, wantedErr: &ErrStackNotFound{name: mockStack.Name}, @@ -865,8 +873,8 @@ func TestCloudFormation_Describe(t *testing.T) { "returns ErrStackNotFound if the list returned is empty": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{}, + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{}, }, nil) return m }, @@ -875,8 +883,8 @@ func TestCloudFormation_Describe(t *testing.T) { "returns a StackDescription if stack exists": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{ { StackName: aws.String(mockStack.Name), }, @@ -917,7 +925,7 @@ func TestCloudFormation_Exists(t *testing.T) { wantedErr := errors.New("some error") m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, wantedErr) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, wantedErr) c := CloudFormation{ client: m, } @@ -934,7 +942,7 @@ func TestCloudFormation_Exists(t *testing.T) { defer ctrl.Finish() m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) c := CloudFormation{ client: m, } @@ -952,10 +960,10 @@ func TestCloudFormation_Exists(t *testing.T) { defer ctrl.Finish() m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{ + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{ StackName: aws.String("phonetool-test"), }).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{{}}, + Stacks: []types.Stack{{}}, }, nil) c := CloudFormation{ client: m, @@ -979,7 +987,7 @@ func TestCloudFormation_TemplateBody(t *testing.T) { "return ErrStackNotFound if stack does not exist": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplate(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) return m }, wantedErr: &ErrStackNotFound{name: mockStack.Name}, @@ -987,7 +995,7 @@ func TestCloudFormation_TemplateBody(t *testing.T) { "returns the template body if the stack exists": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplate(&cloudformation.GetTemplateInput{ + m.EXPECT().GetTemplate(gomock.Any(), &cloudformation.GetTemplateInput{ StackName: aws.String(mockStack.Name), }).Return(&cloudformation.GetTemplateOutput{ TemplateBody: aws.String("hello"), @@ -1026,7 +1034,7 @@ func TestCloudFormation_TemplateBodyFromChangeSet(t *testing.T) { "return ErrStackNotFound if stack does not exist": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplate(gomock.Any()).Return(nil, errDoesNotExist) + m.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).Return(nil, errDoesNotExist) return m }, wantedErr: (&ErrStackNotFound{name: mockStack.Name}).Error(), @@ -1034,7 +1042,7 @@ func TestCloudFormation_TemplateBodyFromChangeSet(t *testing.T) { "returns wrapped error on expected error": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplate(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().GetTemplate(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedErr: fmt.Sprintf("get template for stack %s and change set %s: some error", mockStack.Name, mockChangeSetID), @@ -1042,7 +1050,7 @@ func TestCloudFormation_TemplateBodyFromChangeSet(t *testing.T) { "returns the template body if the change set and stack exists": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().GetTemplate(&cloudformation.GetTemplateInput{ + m.EXPECT().GetTemplate(gomock.Any(), &cloudformation.GetTemplateInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String(mockStack.Name), }).Return(&cloudformation.GetTemplateOutput{ @@ -1086,11 +1094,11 @@ func TestCloudFormation_Outputs(t *testing.T) { "successfully returns outputs": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStacksOutput{ + Stacks: []types.Stack{ { StackName: aws.String(mockStack.Name), - Outputs: []*cloudformation.Output{ + Outputs: []types.Output{ { OutputKey: aws.String("PipelineConnection"), OutputValue: aws.String("mockARN"), @@ -1108,7 +1116,7 @@ func TestCloudFormation_Outputs(t *testing.T) { "wraps error from Describe()": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStacks(gomock.Any()).Return(nil, fmt.Errorf("some error")) + m.EXPECT().DescribeStacks(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("some error")) return m }, wantedOutputs: nil, @@ -1138,17 +1146,17 @@ func TestCloudFormation_Outputs(t *testing.T) { } func TestCloudFormation_ErrorEvents(t *testing.T) { - mockEvents := []*cloudformation.StackEvent{ + mockEvents := []types.StackEvent{ { LogicalResourceId: aws.String("abc123"), ResourceType: aws.String("ECS::Service"), - ResourceStatus: aws.String("CREATE_FAILED"), + ResourceStatus: types.ResourceStatus("CREATE_FAILED"), ResourceStatusReason: aws.String("Space elevator disconnected. (Service moonshot)"), }, { LogicalResourceId: aws.String("xyz"), ResourceType: aws.String("ECS::Service"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), ResourceStatusReason: aws.String("Moon landing achieved. (Service moonshot)"), }, } @@ -1159,7 +1167,7 @@ func TestCloudFormation_ErrorEvents(t *testing.T) { }{ "completes successfully": { mockCf: func(m *mocks.Mockclient) { - m.EXPECT().DescribeStackEvents(&cloudformation.DescribeStackEventsInput{ + m.EXPECT().DescribeStackEvents(gomock.Any(), &cloudformation.DescribeStackEventsInput{ StackName: aws.String(mockStack.Name), }).Return(&cloudformation.DescribeStackEventsOutput{ StackEvents: mockEvents, @@ -1169,14 +1177,14 @@ func TestCloudFormation_ErrorEvents(t *testing.T) { { LogicalResourceId: aws.String("abc123"), ResourceType: aws.String("ECS::Service"), - ResourceStatus: aws.String("CREATE_FAILED"), + ResourceStatus: types.ResourceStatus("CREATE_FAILED"), ResourceStatusReason: aws.String("Space elevator disconnected. (Service moonshot)"), }, }, }, "error retrieving events": { mockCf: func(m *mocks.Mockclient) { - m.EXPECT().DescribeStackEvents(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeStackEvents(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) }, wantedErr: "describe stack events for stack id: some error", }, @@ -1215,10 +1223,10 @@ func TestCloudFormation_Events(t *testing.T) { "return events in chronological order": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStackEvents(&cloudformation.DescribeStackEventsInput{ + m.EXPECT().DescribeStackEvents(gomock.Any(), &cloudformation.DescribeStackEventsInput{ StackName: aws.String(mockStack.Name), }).Return(&cloudformation.DescribeStackEventsOutput{ - StackEvents: []*cloudformation.StackEvent{ + StackEvents: []types.StackEvent{ { ResourceType: aws.String("ecs"), }, @@ -1269,7 +1277,7 @@ func TestStackDescriber_StackResources(t *testing.T) { "return a wrapped error if fail to describe stack resources": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStackResources(gomock.Any()).Return(nil, errors.New("some error")) + m.EXPECT().DescribeStackResources(gomock.Any(), gomock.Any()).Return(nil, errors.New("some error")) return m }, wantedError: fmt.Errorf("describe resources for stack phonetool-test-api: some error"), @@ -1277,10 +1285,10 @@ func TestStackDescriber_StackResources(t *testing.T) { "returns type-casted stack resources on success": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().DescribeStackResources(&cloudformation.DescribeStackResourcesInput{ + m.EXPECT().DescribeStackResources(gomock.Any(), &cloudformation.DescribeStackResourcesInput{ StackName: aws.String("phonetool-test-api"), }).Return(&cloudformation.DescribeStackResourcesOutput{ - StackResources: []*cloudformation.StackResource{ + StackResources: []types.StackResource{ { StackName: aws.String("phonetool-test-api"), }, @@ -1320,48 +1328,48 @@ func TestStackDescriber_StackResources(t *testing.T) { } func TestCloudFormation_ListStacksWithTags(t *testing.T) { - mockAppTag := cloudformation.Tag{ + mockAppTag := types.Tag{ Key: aws.String("copilot-application"), Value: aws.String("phonetool"), } - mockEnvTag := cloudformation.Tag{ + mockEnvTag := types.Tag{ Key: aws.String("copilot-environment"), Value: aws.String("test-pdx"), } - mockTaskTag1 := cloudformation.Tag{ + mockTaskTag1 := types.Tag{ Key: aws.String("copilot-task"), Value: aws.String("db-migrate"), } - mockTaskTag2 := cloudformation.Tag{ + mockTaskTag2 := types.Tag{ Key: aws.String("copilot-task"), Value: aws.String("default-oneoff"), } - mockStack1 := cloudformation.Stack{ + mockStack1 := types.Stack{ StackName: aws.String("task-appenv"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, - &mockTaskTag1, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, + mockTaskTag1, }, } - mockStack2 := cloudformation.Stack{ + mockStack2 := types.Stack{ StackName: aws.String("task-default-oneoff"), - Tags: []*cloudformation.Tag{ - &mockTaskTag2, + Tags: []types.Tag{ + mockTaskTag2, }, } - mockStack3 := cloudformation.Stack{ + mockStack3 := types.Stack{ StackName: aws.String("phonetool-test-pdx"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, }, } mockStacks := &cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ - &mockStack1, - &mockStack2, - &mockStack3, + Stacks: []types.Stack{ + mockStack1, + mockStack2, + mockStack3, }, } testCases := map[string]struct { @@ -1376,22 +1384,22 @@ func TestCloudFormation_ListStacksWithTags(t *testing.T) { "copilot-environment": "test-pdx", }, mockCf: func(m *mocks.Mockclient) { - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{}).Return(mockStacks, nil) + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{}).Return(mockStacks, nil) }, wantedStacks: []StackDescription{ { StackName: aws.String("task-appenv"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, - &mockTaskTag1, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, + mockTaskTag1, }, }, { StackName: aws.String("phonetool-test-pdx"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, }, }, }, @@ -1401,34 +1409,34 @@ func TestCloudFormation_ListStacksWithTags(t *testing.T) { "copilot-task": "", }, mockCf: func(m *mocks.Mockclient) { - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{}).Return(&cloudformation.DescribeStacksOutput{ + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{}).Return(&cloudformation.DescribeStacksOutput{ NextToken: aws.String("abc"), - Stacks: []*cloudformation.Stack{ - &mockStack1, + Stacks: []types.Stack{ + mockStack1, }, }, nil) - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{ + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{ NextToken: aws.String("abc"), }).Return(&cloudformation.DescribeStacksOutput{ - Stacks: []*cloudformation.Stack{ - &mockStack2, - &mockStack3, + Stacks: []types.Stack{ + mockStack2, + mockStack3, }, }, nil) }, wantedStacks: []StackDescription{ { StackName: aws.String("task-appenv"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, - &mockTaskTag1, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, + mockTaskTag1, }, }, { StackName: aws.String("task-default-oneoff"), - Tags: []*cloudformation.Tag{ - &mockTaskTag2, + Tags: []types.Tag{ + mockTaskTag2, }, }, }, @@ -1436,28 +1444,28 @@ func TestCloudFormation_ListStacksWithTags(t *testing.T) { "empty map returns all stacks": { inTags: map[string]string{}, mockCf: func(m *mocks.Mockclient) { - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{}).Return(mockStacks, nil) + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{}).Return(mockStacks, nil) }, wantedStacks: []StackDescription{ { StackName: aws.String("task-appenv"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, - &mockTaskTag1, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, + mockTaskTag1, }, }, { StackName: aws.String("task-default-oneoff"), - Tags: []*cloudformation.Tag{ - &mockTaskTag2, + Tags: []types.Tag{ + mockTaskTag2, }, }, { StackName: aws.String("phonetool-test-pdx"), - Tags: []*cloudformation.Tag{ - &mockAppTag, - &mockEnvTag, + Tags: []types.Tag{ + mockAppTag, + mockEnvTag, }, }, }, @@ -1465,7 +1473,7 @@ func TestCloudFormation_ListStacksWithTags(t *testing.T) { "error listing stacks": { inTags: map[string]string{}, mockCf: func(m *mocks.Mockclient) { - m.EXPECT().DescribeStacks(&cloudformation.DescribeStacksInput{}).Return(nil, errors.New("some error")) + m.EXPECT().DescribeStacks(gomock.Any(), &cloudformation.DescribeStacksInput{}).Return(nil, errors.New("some error")) }, wantedErr: "list stacks: some error", }, @@ -1505,7 +1513,7 @@ func TestCloudformation_CancelUpdateStack(t *testing.T) { "return a wrapped error if fail to cancel stack update": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().CancelUpdateStack(&cloudformation.CancelUpdateStackInput{ + m.EXPECT().CancelUpdateStack(gomock.Any(), &cloudformation.CancelUpdateStackInput{ StackName: aws.String("phonetool-test-api"), }).Return(nil, errors.New("some error")) return m @@ -1515,7 +1523,7 @@ func TestCloudformation_CancelUpdateStack(t *testing.T) { "return nil if the stack is not found": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().CancelUpdateStack(&cloudformation.CancelUpdateStackInput{ + m.EXPECT().CancelUpdateStack(gomock.Any(), &cloudformation.CancelUpdateStackInput{ StackName: aws.String("phonetool-test-api"), }).Return(nil, errDoesNotExist) return m @@ -1524,7 +1532,7 @@ func TestCloudformation_CancelUpdateStack(t *testing.T) { "return nil if the stack is not in update progress state": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().CancelUpdateStack(&cloudformation.CancelUpdateStackInput{ + m.EXPECT().CancelUpdateStack(gomock.Any(), &cloudformation.CancelUpdateStackInput{ StackName: aws.String("phonetool-test-api"), }).Return(nil, errStackNotInUpdateProgress) return m @@ -1533,7 +1541,7 @@ func TestCloudformation_CancelUpdateStack(t *testing.T) { "success": { createMock: func(ctrl *gomock.Controller) client { m := mocks.NewMockclient(ctrl) - m.EXPECT().CancelUpdateStack(&cloudformation.CancelUpdateStackInput{ + m.EXPECT().CancelUpdateStack(gomock.Any(), &cloudformation.CancelUpdateStackInput{ StackName: aws.String("phonetool-test-api"), }).Return(&cloudformation.CancelUpdateStackOutput{}, nil) return m @@ -1564,51 +1572,51 @@ func TestCloudformation_CancelUpdateStack(t *testing.T) { } func addCreateDeployCalls(m *mocks.Mockclient) { - addDeployCalls(m, cloudformation.ChangeSetTypeCreate) + addDeployCalls(m, types.ChangeSetTypeCreate) } func addUpdateDeployCalls(m *mocks.Mockclient) { - addDeployCalls(m, cloudformation.ChangeSetTypeUpdate) + addDeployCalls(m, types.ChangeSetTypeUpdate) } -func addDeployCalls(m *mocks.Mockclient, changeSetType string) { - m.EXPECT().CreateChangeSet(&cloudformation.CreateChangeSetInput{ +func addDeployCalls(m *mocks.Mockclient, changeSetType types.ChangeSetType) { + m.EXPECT().CreateChangeSet(gomock.Any(), &cloudformation.CreateChangeSetInput{ ChangeSetName: aws.String(mockChangeSetName), StackName: aws.String(mockStack.Name), - ChangeSetType: aws.String(changeSetType), + ChangeSetType: changeSetType, TemplateBody: aws.String(mockStack.TemplateBody), Parameters: nil, Tags: nil, RoleARN: nil, IncludeNestedStacks: aws.Bool(true), - Capabilities: aws.StringSlice([]string{ - cloudformation.CapabilityCapabilityIam, - cloudformation.CapabilityCapabilityNamedIam, - cloudformation.CapabilityCapabilityAutoExpand, - }), + Capabilities: []types.Capability{ + types.CapabilityCapabilityIam, + types.CapabilityCapabilityNamedIam, + types.CapabilityCapabilityAutoExpand, + }, }).Return(&cloudformation.CreateChangeSetOutput{ Id: aws.String(mockChangeSetID), StackId: aws.String(mockStack.Name), }, nil) - m.EXPECT().WaitUntilChangeSetCreateCompleteWithContext(gomock.Any(), &cloudformation.DescribeChangeSetInput{ + m.EXPECT().WaitUntilChangeSetCreateComplete(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), - }, gomock.Any()) - m.EXPECT().DescribeChangeSet(&cloudformation.DescribeChangeSetInput{ + }, gomock.Any(), gomock.Any()) + m.EXPECT().DescribeChangeSet(gomock.Any(), &cloudformation.DescribeChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String(mockStack.Name), }).Return(&cloudformation.DescribeChangeSetOutput{ - Changes: []*cloudformation.Change{ + Changes: []types.Change{ { - ResourceChange: &cloudformation.ResourceChange{ + ResourceChange: &types.ResourceChange{ ResourceType: aws.String("ecs service"), }, - Type: aws.String(cloudformation.ChangeTypeResource), + Type: types.ChangeTypeResource, }, }, - ExecutionStatus: aws.String(cloudformation.ExecutionStatusAvailable), + ExecutionStatus: types.ExecutionStatusAvailable, StatusReason: aws.String("some reason"), }, nil) - m.EXPECT().ExecuteChangeSet(&cloudformation.ExecuteChangeSetInput{ + m.EXPECT().ExecuteChangeSet(gomock.Any(), &cloudformation.ExecuteChangeSetInput{ ChangeSetName: aws.String(mockChangeSetID), StackName: aws.String(mockStack.Name), }) diff --git a/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go b/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go index 052bc951f56..9ae7be1bfbc 100644 --- a/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go +++ b/internal/pkg/aws/cloudformation/cloudformationtest/cloudformationtest.go @@ -7,7 +7,7 @@ import ( "context" cfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" - sdk "github.com/aws/aws-sdk-go/service/cloudformation" + sdk "github.com/aws/aws-sdk-go-v2/service/cloudformation" ) // Double is a test double for cloudformation.CloudFormation diff --git a/internal/pkg/aws/cloudformation/errors.go b/internal/pkg/aws/cloudformation/errors.go index 03a17383627..82646eb4356 100644 --- a/internal/pkg/aws/cloudformation/errors.go +++ b/internal/pkg/aws/cloudformation/errors.go @@ -4,10 +4,11 @@ package cloudformation import ( + "errors" "fmt" "strings" - "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/smithy-go" ) // ErrChangeSetEmpty occurs when the change set does not contain any new or updated resources. @@ -69,11 +70,12 @@ func (e *ErrStackUpdateInProgress) Error() string { // stackDoesNotExist returns true if the underlying error is a stack doesn't exist. func stackDoesNotExist(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { + var aerr smithy.APIError + if ok := errors.As(err, &aerr); ok { + switch aerr.ErrorCode() { case "ValidationError": // A ValidationError occurs if we describe a stack which doesn't exist. - if strings.Contains(aerr.Message(), "does not exist") { + if strings.Contains(aerr.ErrorMessage(), "does not exist") { return true } } @@ -84,10 +86,11 @@ func stackDoesNotExist(err error) bool { // cancelUpdateStackNotInUpdateProgress returns true if the underlying error is CancelUpdateStack // cannot be called for a stack that is not in UPDATE_IN_PROGRESS state. func cancelUpdateStackNotInUpdateProgress(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { + var aerr smithy.APIError + if ok := errors.As(err, &aerr); ok { + switch aerr.ErrorCode() { case "ValidationError": - if strings.Contains(aerr.Message(), "CancelUpdateStack cannot be called from current stack status") { + if strings.Contains(aerr.ErrorMessage(), "CancelUpdateStack cannot be called from current stack status") { return true } } diff --git a/internal/pkg/aws/cloudformation/interfaces.go b/internal/pkg/aws/cloudformation/interfaces.go index 4dfb935a27a..c0706fb86f6 100644 --- a/internal/pkg/aws/cloudformation/interfaces.go +++ b/internal/pkg/aws/cloudformation/interfaces.go @@ -4,30 +4,31 @@ package cloudformation import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/cloudformation" + "context" + "time" + + "github.com/aws/aws-sdk-go-v2/service/cloudformation" ) type changeSetAPI interface { - CreateChangeSet(*cloudformation.CreateChangeSetInput) (*cloudformation.CreateChangeSetOutput, error) - WaitUntilChangeSetCreateCompleteWithContext(aws.Context, *cloudformation.DescribeChangeSetInput, ...request.WaiterOption) error - DescribeChangeSet(*cloudformation.DescribeChangeSetInput) (*cloudformation.DescribeChangeSetOutput, error) - ExecuteChangeSet(*cloudformation.ExecuteChangeSetInput) (*cloudformation.ExecuteChangeSetOutput, error) - DeleteChangeSet(*cloudformation.DeleteChangeSetInput) (*cloudformation.DeleteChangeSetOutput, error) + CreateChangeSet(context.Context, *cloudformation.CreateChangeSetInput, ...func(*cloudformation.Options)) (*cloudformation.CreateChangeSetOutput, error) + WaitUntilChangeSetCreateComplete(context.Context, *cloudformation.DescribeChangeSetInput, time.Duration, ...func(*cloudformation.ChangeSetCreateCompleteWaiterOptions)) error + DescribeChangeSet(context.Context, *cloudformation.DescribeChangeSetInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeChangeSetOutput, error) + ExecuteChangeSet(context.Context, *cloudformation.ExecuteChangeSetInput, ...func(*cloudformation.Options)) (*cloudformation.ExecuteChangeSetOutput, error) + DeleteChangeSet(context.Context, *cloudformation.DeleteChangeSetInput, ...func(*cloudformation.Options)) (*cloudformation.DeleteChangeSetOutput, error) } type client interface { changeSetAPI - GetTemplateSummary(in *cloudformation.GetTemplateSummaryInput) (*cloudformation.GetTemplateSummaryOutput, error) - DescribeStacks(*cloudformation.DescribeStacksInput) (*cloudformation.DescribeStacksOutput, error) - DescribeStackEvents(*cloudformation.DescribeStackEventsInput) (*cloudformation.DescribeStackEventsOutput, error) - DescribeStackResources(input *cloudformation.DescribeStackResourcesInput) (*cloudformation.DescribeStackResourcesOutput, error) - GetTemplate(input *cloudformation.GetTemplateInput) (*cloudformation.GetTemplateOutput, error) - DeleteStack(*cloudformation.DeleteStackInput) (*cloudformation.DeleteStackOutput, error) - WaitUntilStackCreateCompleteWithContext(aws.Context, *cloudformation.DescribeStacksInput, ...request.WaiterOption) error - WaitUntilStackUpdateCompleteWithContext(aws.Context, *cloudformation.DescribeStacksInput, ...request.WaiterOption) error - WaitUntilStackDeleteCompleteWithContext(aws.Context, *cloudformation.DescribeStacksInput, ...request.WaiterOption) error - CancelUpdateStack(in *cloudformation.CancelUpdateStackInput) (*cloudformation.CancelUpdateStackOutput, error) + GetTemplateSummary(context.Context, *cloudformation.GetTemplateSummaryInput, ...func(*cloudformation.Options)) (*cloudformation.GetTemplateSummaryOutput, error) + DescribeStacks(context.Context, *cloudformation.DescribeStacksInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) + DescribeStackEvents(context.Context, *cloudformation.DescribeStackEventsInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeStackEventsOutput, error) + DescribeStackResources(context.Context, *cloudformation.DescribeStackResourcesInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeStackResourcesOutput, error) + GetTemplate(context.Context, *cloudformation.GetTemplateInput, ...func(*cloudformation.Options)) (*cloudformation.GetTemplateOutput, error) + DeleteStack(context.Context, *cloudformation.DeleteStackInput, ...func(*cloudformation.Options)) (*cloudformation.DeleteStackOutput, error) + WaitUntilStackCreateComplete(context.Context, *cloudformation.DescribeStacksInput, time.Duration, ...func(*cloudformation.StackCreateCompleteWaiterOptions)) error + WaitUntilStackUpdateComplete(context.Context, *cloudformation.DescribeStacksInput, time.Duration, ...func(*cloudformation.StackUpdateCompleteWaiterOptions)) error + WaitUntilStackDeleteComplete(context.Context, *cloudformation.DescribeStacksInput, time.Duration, ...func(*cloudformation.StackDeleteCompleteWaiterOptions)) error + CancelUpdateStack(context.Context, *cloudformation.CancelUpdateStackInput, ...func(*cloudformation.Options)) (*cloudformation.CancelUpdateStackOutput, error) } diff --git a/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go b/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go index 9747fb8deff..2c01d4784a2 100644 --- a/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go +++ b/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go @@ -1,15 +1,15 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./internal/pkg/aws/cloudformation/interfaces.go +// Source: internal/pkg/aws/cloudformation/interfaces.go // Package mocks is a generated GoMock package. package mocks import ( + context "context" reflect "reflect" + time "time" - aws "github.com/aws/aws-sdk-go/aws" - request "github.com/aws/aws-sdk-go/aws/request" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" gomock "github.com/golang/mock/gomock" ) @@ -37,82 +37,102 @@ func (m *MockchangeSetAPI) EXPECT() *MockchangeSetAPIMockRecorder { } // CreateChangeSet mocks base method. -func (m *MockchangeSetAPI) CreateChangeSet(arg0 *cloudformation.CreateChangeSetInput) (*cloudformation.CreateChangeSetOutput, error) { +func (m *MockchangeSetAPI) CreateChangeSet(arg0 context.Context, arg1 *cloudformation.CreateChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.CreateChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.CreateChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateChangeSet indicates an expected call of CreateChangeSet. -func (mr *MockchangeSetAPIMockRecorder) CreateChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockchangeSetAPIMockRecorder) CreateChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).CreateChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).CreateChangeSet), varargs...) } // DeleteChangeSet mocks base method. -func (m *MockchangeSetAPI) DeleteChangeSet(arg0 *cloudformation.DeleteChangeSetInput) (*cloudformation.DeleteChangeSetOutput, error) { +func (m *MockchangeSetAPI) DeleteChangeSet(arg0 context.Context, arg1 *cloudformation.DeleteChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DeleteChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.DeleteChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteChangeSet indicates an expected call of DeleteChangeSet. -func (mr *MockchangeSetAPIMockRecorder) DeleteChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockchangeSetAPIMockRecorder) DeleteChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).DeleteChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).DeleteChangeSet), varargs...) } // DescribeChangeSet mocks base method. -func (m *MockchangeSetAPI) DescribeChangeSet(arg0 *cloudformation.DescribeChangeSetInput) (*cloudformation.DescribeChangeSetOutput, error) { +func (m *MockchangeSetAPI) DescribeChangeSet(arg0 context.Context, arg1 *cloudformation.DescribeChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeChangeSet indicates an expected call of DescribeChangeSet. -func (mr *MockchangeSetAPIMockRecorder) DescribeChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockchangeSetAPIMockRecorder) DescribeChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).DescribeChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).DescribeChangeSet), varargs...) } // ExecuteChangeSet mocks base method. -func (m *MockchangeSetAPI) ExecuteChangeSet(arg0 *cloudformation.ExecuteChangeSetInput) (*cloudformation.ExecuteChangeSetOutput, error) { +func (m *MockchangeSetAPI) ExecuteChangeSet(arg0 context.Context, arg1 *cloudformation.ExecuteChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.ExecuteChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExecuteChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExecuteChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.ExecuteChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ExecuteChangeSet indicates an expected call of ExecuteChangeSet. -func (mr *MockchangeSetAPIMockRecorder) ExecuteChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockchangeSetAPIMockRecorder) ExecuteChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).ExecuteChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteChangeSet", reflect.TypeOf((*MockchangeSetAPI)(nil).ExecuteChangeSet), varargs...) } -// WaitUntilChangeSetCreateCompleteWithContext mocks base method. -func (m *MockchangeSetAPI) WaitUntilChangeSetCreateCompleteWithContext(arg0 aws.Context, arg1 *cloudformation.DescribeChangeSetInput, arg2 ...request.WaiterOption) error { +// WaitUntilChangeSetCreateComplete mocks base method. +func (m *MockchangeSetAPI) WaitUntilChangeSetCreateComplete(arg0 context.Context, arg1 *cloudformation.DescribeChangeSetInput, arg2 time.Duration, arg3 ...func(*cloudformation.ChangeSetCreateCompleteWaiterOptions)) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "WaitUntilChangeSetCreateCompleteWithContext", varargs...) + ret := m.ctrl.Call(m, "WaitUntilChangeSetCreateComplete", varargs...) ret0, _ := ret[0].(error) return ret0 } -// WaitUntilChangeSetCreateCompleteWithContext indicates an expected call of WaitUntilChangeSetCreateCompleteWithContext. -func (mr *MockchangeSetAPIMockRecorder) WaitUntilChangeSetCreateCompleteWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// WaitUntilChangeSetCreateComplete indicates an expected call of WaitUntilChangeSetCreateComplete. +func (mr *MockchangeSetAPIMockRecorder) WaitUntilChangeSetCreateComplete(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilChangeSetCreateCompleteWithContext", reflect.TypeOf((*MockchangeSetAPI)(nil).WaitUntilChangeSetCreateCompleteWithContext), varargs...) + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilChangeSetCreateComplete", reflect.TypeOf((*MockchangeSetAPI)(nil).WaitUntilChangeSetCreateComplete), varargs...) } // Mockclient is a mock of client interface. @@ -139,242 +159,297 @@ func (m *Mockclient) EXPECT() *MockclientMockRecorder { } // CancelUpdateStack mocks base method. -func (m *Mockclient) CancelUpdateStack(in *cloudformation.CancelUpdateStackInput) (*cloudformation.CancelUpdateStackOutput, error) { +func (m *Mockclient) CancelUpdateStack(arg0 context.Context, arg1 *cloudformation.CancelUpdateStackInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.CancelUpdateStackOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CancelUpdateStack", in) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CancelUpdateStack", varargs...) ret0, _ := ret[0].(*cloudformation.CancelUpdateStackOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CancelUpdateStack indicates an expected call of CancelUpdateStack. -func (mr *MockclientMockRecorder) CancelUpdateStack(in interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) CancelUpdateStack(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelUpdateStack", reflect.TypeOf((*Mockclient)(nil).CancelUpdateStack), in) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelUpdateStack", reflect.TypeOf((*Mockclient)(nil).CancelUpdateStack), varargs...) } // CreateChangeSet mocks base method. -func (m *Mockclient) CreateChangeSet(arg0 *cloudformation.CreateChangeSetInput) (*cloudformation.CreateChangeSetOutput, error) { +func (m *Mockclient) CreateChangeSet(arg0 context.Context, arg1 *cloudformation.CreateChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.CreateChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.CreateChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateChangeSet indicates an expected call of CreateChangeSet. -func (mr *MockclientMockRecorder) CreateChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) CreateChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChangeSet", reflect.TypeOf((*Mockclient)(nil).CreateChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateChangeSet", reflect.TypeOf((*Mockclient)(nil).CreateChangeSet), varargs...) } // DeleteChangeSet mocks base method. -func (m *Mockclient) DeleteChangeSet(arg0 *cloudformation.DeleteChangeSetInput) (*cloudformation.DeleteChangeSetOutput, error) { +func (m *Mockclient) DeleteChangeSet(arg0 context.Context, arg1 *cloudformation.DeleteChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DeleteChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.DeleteChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteChangeSet indicates an expected call of DeleteChangeSet. -func (mr *MockclientMockRecorder) DeleteChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) DeleteChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeSet", reflect.TypeOf((*Mockclient)(nil).DeleteChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteChangeSet", reflect.TypeOf((*Mockclient)(nil).DeleteChangeSet), varargs...) } // DeleteStack mocks base method. -func (m *Mockclient) DeleteStack(arg0 *cloudformation.DeleteStackInput) (*cloudformation.DeleteStackOutput, error) { +func (m *Mockclient) DeleteStack(arg0 context.Context, arg1 *cloudformation.DeleteStackInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DeleteStackOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteStack", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteStack", varargs...) ret0, _ := ret[0].(*cloudformation.DeleteStackOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteStack indicates an expected call of DeleteStack. -func (mr *MockclientMockRecorder) DeleteStack(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) DeleteStack(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStack", reflect.TypeOf((*Mockclient)(nil).DeleteStack), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStack", reflect.TypeOf((*Mockclient)(nil).DeleteStack), varargs...) } // DescribeChangeSet mocks base method. -func (m *Mockclient) DescribeChangeSet(arg0 *cloudformation.DescribeChangeSetInput) (*cloudformation.DescribeChangeSetOutput, error) { +func (m *Mockclient) DescribeChangeSet(arg0 context.Context, arg1 *cloudformation.DescribeChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeChangeSet indicates an expected call of DescribeChangeSet. -func (mr *MockclientMockRecorder) DescribeChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) DescribeChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeChangeSet", reflect.TypeOf((*Mockclient)(nil).DescribeChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeChangeSet", reflect.TypeOf((*Mockclient)(nil).DescribeChangeSet), varargs...) } // DescribeStackEvents mocks base method. -func (m *Mockclient) DescribeStackEvents(arg0 *cloudformation.DescribeStackEventsInput) (*cloudformation.DescribeStackEventsOutput, error) { +func (m *Mockclient) DescribeStackEvents(arg0 context.Context, arg1 *cloudformation.DescribeStackEventsInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeStackEventsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeStackEvents", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStackEvents", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeStackEventsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeStackEvents indicates an expected call of DescribeStackEvents. -func (mr *MockclientMockRecorder) DescribeStackEvents(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) DescribeStackEvents(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackEvents", reflect.TypeOf((*Mockclient)(nil).DescribeStackEvents), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackEvents", reflect.TypeOf((*Mockclient)(nil).DescribeStackEvents), varargs...) } // DescribeStackResources mocks base method. -func (m *Mockclient) DescribeStackResources(input *cloudformation.DescribeStackResourcesInput) (*cloudformation.DescribeStackResourcesOutput, error) { +func (m *Mockclient) DescribeStackResources(arg0 context.Context, arg1 *cloudformation.DescribeStackResourcesInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeStackResourcesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeStackResources", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStackResources", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeStackResourcesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeStackResources indicates an expected call of DescribeStackResources. -func (mr *MockclientMockRecorder) DescribeStackResources(input interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) DescribeStackResources(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackResources", reflect.TypeOf((*Mockclient)(nil).DescribeStackResources), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackResources", reflect.TypeOf((*Mockclient)(nil).DescribeStackResources), varargs...) } // DescribeStacks mocks base method. -func (m *Mockclient) DescribeStacks(arg0 *cloudformation.DescribeStacksInput) (*cloudformation.DescribeStacksOutput, error) { +func (m *Mockclient) DescribeStacks(arg0 context.Context, arg1 *cloudformation.DescribeStacksInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeStacksOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeStacks", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStacks", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeStacksOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeStacks indicates an expected call of DescribeStacks. -func (mr *MockclientMockRecorder) DescribeStacks(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) DescribeStacks(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStacks", reflect.TypeOf((*Mockclient)(nil).DescribeStacks), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStacks", reflect.TypeOf((*Mockclient)(nil).DescribeStacks), varargs...) } // ExecuteChangeSet mocks base method. -func (m *Mockclient) ExecuteChangeSet(arg0 *cloudformation.ExecuteChangeSetInput) (*cloudformation.ExecuteChangeSetOutput, error) { +func (m *Mockclient) ExecuteChangeSet(arg0 context.Context, arg1 *cloudformation.ExecuteChangeSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.ExecuteChangeSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ExecuteChangeSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ExecuteChangeSet", varargs...) ret0, _ := ret[0].(*cloudformation.ExecuteChangeSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ExecuteChangeSet indicates an expected call of ExecuteChangeSet. -func (mr *MockclientMockRecorder) ExecuteChangeSet(arg0 interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) ExecuteChangeSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteChangeSet", reflect.TypeOf((*Mockclient)(nil).ExecuteChangeSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ExecuteChangeSet", reflect.TypeOf((*Mockclient)(nil).ExecuteChangeSet), varargs...) } // GetTemplate mocks base method. -func (m *Mockclient) GetTemplate(input *cloudformation.GetTemplateInput) (*cloudformation.GetTemplateOutput, error) { +func (m *Mockclient) GetTemplate(arg0 context.Context, arg1 *cloudformation.GetTemplateInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.GetTemplateOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTemplate", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetTemplate", varargs...) ret0, _ := ret[0].(*cloudformation.GetTemplateOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetTemplate indicates an expected call of GetTemplate. -func (mr *MockclientMockRecorder) GetTemplate(input interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) GetTemplate(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplate", reflect.TypeOf((*Mockclient)(nil).GetTemplate), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplate", reflect.TypeOf((*Mockclient)(nil).GetTemplate), varargs...) } // GetTemplateSummary mocks base method. -func (m *Mockclient) GetTemplateSummary(in *cloudformation.GetTemplateSummaryInput) (*cloudformation.GetTemplateSummaryOutput, error) { +func (m *Mockclient) GetTemplateSummary(arg0 context.Context, arg1 *cloudformation.GetTemplateSummaryInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.GetTemplateSummaryOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetTemplateSummary", in) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "GetTemplateSummary", varargs...) ret0, _ := ret[0].(*cloudformation.GetTemplateSummaryOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // GetTemplateSummary indicates an expected call of GetTemplateSummary. -func (mr *MockclientMockRecorder) GetTemplateSummary(in interface{}) *gomock.Call { +func (mr *MockclientMockRecorder) GetTemplateSummary(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateSummary", reflect.TypeOf((*Mockclient)(nil).GetTemplateSummary), in) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTemplateSummary", reflect.TypeOf((*Mockclient)(nil).GetTemplateSummary), varargs...) } -// WaitUntilChangeSetCreateCompleteWithContext mocks base method. -func (m *Mockclient) WaitUntilChangeSetCreateCompleteWithContext(arg0 aws.Context, arg1 *cloudformation.DescribeChangeSetInput, arg2 ...request.WaiterOption) error { +// WaitUntilChangeSetCreateComplete mocks base method. +func (m *Mockclient) WaitUntilChangeSetCreateComplete(arg0 context.Context, arg1 *cloudformation.DescribeChangeSetInput, arg2 time.Duration, arg3 ...func(*cloudformation.ChangeSetCreateCompleteWaiterOptions)) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "WaitUntilChangeSetCreateCompleteWithContext", varargs...) + ret := m.ctrl.Call(m, "WaitUntilChangeSetCreateComplete", varargs...) ret0, _ := ret[0].(error) return ret0 } -// WaitUntilChangeSetCreateCompleteWithContext indicates an expected call of WaitUntilChangeSetCreateCompleteWithContext. -func (mr *MockclientMockRecorder) WaitUntilChangeSetCreateCompleteWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// WaitUntilChangeSetCreateComplete indicates an expected call of WaitUntilChangeSetCreateComplete. +func (mr *MockclientMockRecorder) WaitUntilChangeSetCreateComplete(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilChangeSetCreateCompleteWithContext", reflect.TypeOf((*Mockclient)(nil).WaitUntilChangeSetCreateCompleteWithContext), varargs...) + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilChangeSetCreateComplete", reflect.TypeOf((*Mockclient)(nil).WaitUntilChangeSetCreateComplete), varargs...) } -// WaitUntilStackCreateCompleteWithContext mocks base method. -func (m *Mockclient) WaitUntilStackCreateCompleteWithContext(arg0 aws.Context, arg1 *cloudformation.DescribeStacksInput, arg2 ...request.WaiterOption) error { +// WaitUntilStackCreateComplete mocks base method. +func (m *Mockclient) WaitUntilStackCreateComplete(arg0 context.Context, arg1 *cloudformation.DescribeStacksInput, arg2 time.Duration, arg3 ...func(*cloudformation.StackCreateCompleteWaiterOptions)) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "WaitUntilStackCreateCompleteWithContext", varargs...) + ret := m.ctrl.Call(m, "WaitUntilStackCreateComplete", varargs...) ret0, _ := ret[0].(error) return ret0 } -// WaitUntilStackCreateCompleteWithContext indicates an expected call of WaitUntilStackCreateCompleteWithContext. -func (mr *MockclientMockRecorder) WaitUntilStackCreateCompleteWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// WaitUntilStackCreateComplete indicates an expected call of WaitUntilStackCreateComplete. +func (mr *MockclientMockRecorder) WaitUntilStackCreateComplete(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilStackCreateCompleteWithContext", reflect.TypeOf((*Mockclient)(nil).WaitUntilStackCreateCompleteWithContext), varargs...) + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilStackCreateComplete", reflect.TypeOf((*Mockclient)(nil).WaitUntilStackCreateComplete), varargs...) } -// WaitUntilStackDeleteCompleteWithContext mocks base method. -func (m *Mockclient) WaitUntilStackDeleteCompleteWithContext(arg0 aws.Context, arg1 *cloudformation.DescribeStacksInput, arg2 ...request.WaiterOption) error { +// WaitUntilStackDeleteComplete mocks base method. +func (m *Mockclient) WaitUntilStackDeleteComplete(arg0 context.Context, arg1 *cloudformation.DescribeStacksInput, arg2 time.Duration, arg3 ...func(*cloudformation.StackDeleteCompleteWaiterOptions)) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "WaitUntilStackDeleteCompleteWithContext", varargs...) + ret := m.ctrl.Call(m, "WaitUntilStackDeleteComplete", varargs...) ret0, _ := ret[0].(error) return ret0 } -// WaitUntilStackDeleteCompleteWithContext indicates an expected call of WaitUntilStackDeleteCompleteWithContext. -func (mr *MockclientMockRecorder) WaitUntilStackDeleteCompleteWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// WaitUntilStackDeleteComplete indicates an expected call of WaitUntilStackDeleteComplete. +func (mr *MockclientMockRecorder) WaitUntilStackDeleteComplete(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilStackDeleteCompleteWithContext", reflect.TypeOf((*Mockclient)(nil).WaitUntilStackDeleteCompleteWithContext), varargs...) + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilStackDeleteComplete", reflect.TypeOf((*Mockclient)(nil).WaitUntilStackDeleteComplete), varargs...) } -// WaitUntilStackUpdateCompleteWithContext mocks base method. -func (m *Mockclient) WaitUntilStackUpdateCompleteWithContext(arg0 aws.Context, arg1 *cloudformation.DescribeStacksInput, arg2 ...request.WaiterOption) error { +// WaitUntilStackUpdateComplete mocks base method. +func (m *Mockclient) WaitUntilStackUpdateComplete(arg0 context.Context, arg1 *cloudformation.DescribeStacksInput, arg2 time.Duration, arg3 ...func(*cloudformation.StackUpdateCompleteWaiterOptions)) error { m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { + varargs := []interface{}{arg0, arg1, arg2} + for _, a := range arg3 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "WaitUntilStackUpdateCompleteWithContext", varargs...) + ret := m.ctrl.Call(m, "WaitUntilStackUpdateComplete", varargs...) ret0, _ := ret[0].(error) return ret0 } -// WaitUntilStackUpdateCompleteWithContext indicates an expected call of WaitUntilStackUpdateCompleteWithContext. -func (mr *MockclientMockRecorder) WaitUntilStackUpdateCompleteWithContext(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// WaitUntilStackUpdateComplete indicates an expected call of WaitUntilStackUpdateComplete. +func (mr *MockclientMockRecorder) WaitUntilStackUpdateComplete(arg0, arg1, arg2 interface{}, arg3 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilStackUpdateCompleteWithContext", reflect.TypeOf((*Mockclient)(nil).WaitUntilStackUpdateCompleteWithContext), varargs...) + varargs := append([]interface{}{arg0, arg1, arg2}, arg3...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "WaitUntilStackUpdateComplete", reflect.TypeOf((*Mockclient)(nil).WaitUntilStackUpdateComplete), varargs...) } diff --git a/internal/pkg/aws/cloudformation/stack.go b/internal/pkg/aws/cloudformation/stack.go index 9e09250b0f3..49c065a81cc 100644 --- a/internal/pkg/aws/cloudformation/stack.go +++ b/internal/pkg/aws/cloudformation/stack.go @@ -4,8 +4,8 @@ package cloudformation import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + awsv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) // Stack represents a AWS CloudFormation stack. @@ -17,8 +17,8 @@ type Stack struct { type stackConfig struct { TemplateBody string TemplateURL string - Parameters []*cloudformation.Parameter - Tags []*cloudformation.Tag + Parameters []types.Parameter + Tags []types.Tag RoleARN *string DisableRollback bool } @@ -57,11 +57,11 @@ func NewStackWithURL(name, templateURL string, opts ...StackOption) *Stack { // WithParameters passes parameters to a stack. func WithParameters(params map[string]string) StackOption { return func(s *Stack) { - var flatParams []*cloudformation.Parameter + var flatParams []types.Parameter for k, v := range params { - flatParams = append(flatParams, &cloudformation.Parameter{ - ParameterKey: aws.String(k), - ParameterValue: aws.String(v), + flatParams = append(flatParams, types.Parameter{ + ParameterKey: awsv2.String(k), + ParameterValue: awsv2.String(v), }) } s.Parameters = flatParams @@ -71,11 +71,11 @@ func WithParameters(params map[string]string) StackOption { // WithTags applies the tags to a stack. func WithTags(tags map[string]string) StackOption { return func(s *Stack) { - var flatTags []*cloudformation.Tag + var flatTags []types.Tag for k, v := range tags { - flatTags = append(flatTags, &cloudformation.Tag{ - Key: aws.String(k), - Value: aws.String(v), + flatTags = append(flatTags, types.Tag{ + Key: awsv2.String(k), + Value: awsv2.String(v), }) } s.Tags = flatTags @@ -85,7 +85,7 @@ func WithTags(tags map[string]string) StackOption { // WithRoleARN specifies the role that CloudFormation will assume when creating the stack. func WithRoleARN(roleARN string) StackOption { return func(s *Stack) { - s.RoleARN = aws.String(roleARN) + s.RoleARN = awsv2.String(roleARN) } } @@ -97,16 +97,16 @@ func WithDisableRollback() StackOption { } // StackEvent is an alias the SDK's StackEvent type. -type StackEvent cloudformation.StackEvent +type StackEvent types.StackEvent // StackDescription is an alias the SDK's Stack type. -type StackDescription cloudformation.Stack +type StackDescription types.Stack // StackResource is an alias the SDK's StackResource type. -type StackResource cloudformation.StackResource +type StackResource types.StackResource // SDK returns the underlying struct from the AWS SDK. -func (d *StackDescription) SDK() *cloudformation.Stack { - raw := cloudformation.Stack(*d) +func (d *StackDescription) SDK() *types.Stack { + raw := types.Stack(*d) return &raw } diff --git a/internal/pkg/aws/cloudformation/stack_test.go b/internal/pkg/aws/cloudformation/stack_test.go index ec25d5cf22a..91bdbc90eb6 100644 --- a/internal/pkg/aws/cloudformation/stack_test.go +++ b/internal/pkg/aws/cloudformation/stack_test.go @@ -6,8 +6,8 @@ package cloudformation import ( "testing" - "github.com/aws/aws-sdk-go/aws" - "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/types" "github.com/stretchr/testify/require" ) @@ -25,13 +25,13 @@ func TestNewStack(t *testing.T) { // THEN require.Equal(t, "hello", s.Name) require.Equal(t, "world", s.TemplateBody) - require.Equal(t, []*cloudformation.Parameter{ + require.Equal(t, []types.Parameter{ { ParameterKey: aws.String("Port"), ParameterValue: aws.String("80"), }, }, s.Parameters) - require.Equal(t, []*cloudformation.Tag{ + require.Equal(t, []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String("phonetool"), @@ -54,13 +54,13 @@ func TestNewStackWithURL(t *testing.T) { // THEN require.Equal(t, "hello", s.Name) require.Equal(t, "worldlyURL", s.TemplateURL) - require.Equal(t, []*cloudformation.Parameter{ + require.Equal(t, []types.Parameter{ { ParameterKey: aws.String("Port"), ParameterValue: aws.String("80"), }, }, s.Parameters) - require.Equal(t, []*cloudformation.Tag{ + require.Equal(t, []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String("phonetool"), diff --git a/internal/pkg/aws/cloudformation/stackset/errors.go b/internal/pkg/aws/cloudformation/stackset/errors.go index 1b9e5d562c3..efad4d4602f 100644 --- a/internal/pkg/aws/cloudformation/stackset/errors.go +++ b/internal/pkg/aws/cloudformation/stackset/errors.go @@ -4,10 +4,11 @@ package stackset import ( + "errors" "fmt" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + "github.com/aws/smithy-go" ) // ErrStackSetOutOfDate occurs when we try to read and then update a StackSet but between reading it @@ -53,9 +54,10 @@ func (e *ErrStackSetInstancesNotFound) IsEmpty() bool { // isAlreadyExistingStackSet returns true if the underlying error is a stack already exists error. func isAlreadyExistingStackSet(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case cloudformation.ErrCodeNameAlreadyExistsException: + var aerr smithy.APIError + if ok := errors.As(err, &aerr); ok { + switch aerr.ErrorCode() { + case (*types.NameAlreadyExistsException)(nil).ErrorCode(): return true } } @@ -64,9 +66,10 @@ func isAlreadyExistingStackSet(err error) bool { // isOutdatedStackSet returns true if the underlying error is because the operation was already performed. func isOutdatedStackSet(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case cloudformation.ErrCodeOperationIdAlreadyExistsException, cloudformation.ErrCodeOperationInProgressException, cloudformation.ErrCodeStaleRequestException: + var aerr smithy.APIError + if ok := errors.As(err, &aerr); ok { + switch aerr.ErrorCode() { + case (*types.OperationIdAlreadyExistsException)(nil).ErrorCode(), (*types.OperationInProgressException)(nil).ErrorCode(), (*types.StaleRequestException)(nil).ErrorCode(): return true } } @@ -75,9 +78,10 @@ func isOutdatedStackSet(err error) bool { // isNotFoundStackSet returns true if the stack set does not exist. func isNotFoundStackSet(err error) bool { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case cloudformation.ErrCodeStackSetNotFoundException: + var aerr smithy.APIError + if ok := errors.As(err, &aerr); ok { + switch aerr.ErrorCode() { + case (*types.StackSetNotFoundException)(nil).ErrorCode(): return true } } diff --git a/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go b/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go index 23580b4eaf1..9d3ea9d82b6 100644 --- a/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go +++ b/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go @@ -1,13 +1,14 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./internal/pkg/aws/cloudformation/stackset/stackset.go +// Source: internal/pkg/aws/cloudformation/stackset/stackset.go // Package mocks is a generated GoMock package. package mocks import ( + context "context" reflect "reflect" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" gomock "github.com/golang/mock/gomock" ) @@ -35,136 +36,181 @@ func (m *Mockapi) EXPECT() *MockapiMockRecorder { } // CreateStackInstances mocks base method. -func (m *Mockapi) CreateStackInstances(arg0 *cloudformation.CreateStackInstancesInput) (*cloudformation.CreateStackInstancesOutput, error) { +func (m *Mockapi) CreateStackInstances(arg0 context.Context, arg1 *cloudformation.CreateStackInstancesInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.CreateStackInstancesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateStackInstances", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateStackInstances", varargs...) ret0, _ := ret[0].(*cloudformation.CreateStackInstancesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateStackInstances indicates an expected call of CreateStackInstances. -func (mr *MockapiMockRecorder) CreateStackInstances(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) CreateStackInstances(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStackInstances", reflect.TypeOf((*Mockapi)(nil).CreateStackInstances), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStackInstances", reflect.TypeOf((*Mockapi)(nil).CreateStackInstances), varargs...) } // CreateStackSet mocks base method. -func (m *Mockapi) CreateStackSet(arg0 *cloudformation.CreateStackSetInput) (*cloudformation.CreateStackSetOutput, error) { +func (m *Mockapi) CreateStackSet(arg0 context.Context, arg1 *cloudformation.CreateStackSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.CreateStackSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CreateStackSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "CreateStackSet", varargs...) ret0, _ := ret[0].(*cloudformation.CreateStackSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // CreateStackSet indicates an expected call of CreateStackSet. -func (mr *MockapiMockRecorder) CreateStackSet(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) CreateStackSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStackSet", reflect.TypeOf((*Mockapi)(nil).CreateStackSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStackSet", reflect.TypeOf((*Mockapi)(nil).CreateStackSet), varargs...) } // DeleteStackInstances mocks base method. -func (m *Mockapi) DeleteStackInstances(arg0 *cloudformation.DeleteStackInstancesInput) (*cloudformation.DeleteStackInstancesOutput, error) { +func (m *Mockapi) DeleteStackInstances(arg0 context.Context, arg1 *cloudformation.DeleteStackInstancesInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DeleteStackInstancesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteStackInstances", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteStackInstances", varargs...) ret0, _ := ret[0].(*cloudformation.DeleteStackInstancesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteStackInstances indicates an expected call of DeleteStackInstances. -func (mr *MockapiMockRecorder) DeleteStackInstances(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DeleteStackInstances(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStackInstances", reflect.TypeOf((*Mockapi)(nil).DeleteStackInstances), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStackInstances", reflect.TypeOf((*Mockapi)(nil).DeleteStackInstances), varargs...) } // DeleteStackSet mocks base method. -func (m *Mockapi) DeleteStackSet(arg0 *cloudformation.DeleteStackSetInput) (*cloudformation.DeleteStackSetOutput, error) { +func (m *Mockapi) DeleteStackSet(arg0 context.Context, arg1 *cloudformation.DeleteStackSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DeleteStackSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DeleteStackSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DeleteStackSet", varargs...) ret0, _ := ret[0].(*cloudformation.DeleteStackSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DeleteStackSet indicates an expected call of DeleteStackSet. -func (mr *MockapiMockRecorder) DeleteStackSet(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DeleteStackSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStackSet", reflect.TypeOf((*Mockapi)(nil).DeleteStackSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteStackSet", reflect.TypeOf((*Mockapi)(nil).DeleteStackSet), varargs...) } // DescribeStackSet mocks base method. -func (m *Mockapi) DescribeStackSet(arg0 *cloudformation.DescribeStackSetInput) (*cloudformation.DescribeStackSetOutput, error) { +func (m *Mockapi) DescribeStackSet(arg0 context.Context, arg1 *cloudformation.DescribeStackSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeStackSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeStackSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStackSet", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeStackSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeStackSet indicates an expected call of DescribeStackSet. -func (mr *MockapiMockRecorder) DescribeStackSet(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeStackSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackSet", reflect.TypeOf((*Mockapi)(nil).DescribeStackSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackSet", reflect.TypeOf((*Mockapi)(nil).DescribeStackSet), varargs...) } // DescribeStackSetOperation mocks base method. -func (m *Mockapi) DescribeStackSetOperation(arg0 *cloudformation.DescribeStackSetOperationInput) (*cloudformation.DescribeStackSetOperationOutput, error) { +func (m *Mockapi) DescribeStackSetOperation(arg0 context.Context, arg1 *cloudformation.DescribeStackSetOperationInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.DescribeStackSetOperationOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DescribeStackSetOperation", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "DescribeStackSetOperation", varargs...) ret0, _ := ret[0].(*cloudformation.DescribeStackSetOperationOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // DescribeStackSetOperation indicates an expected call of DescribeStackSetOperation. -func (mr *MockapiMockRecorder) DescribeStackSetOperation(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) DescribeStackSetOperation(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackSetOperation", reflect.TypeOf((*Mockapi)(nil).DescribeStackSetOperation), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeStackSetOperation", reflect.TypeOf((*Mockapi)(nil).DescribeStackSetOperation), varargs...) } // ListStackInstances mocks base method. -func (m *Mockapi) ListStackInstances(arg0 *cloudformation.ListStackInstancesInput) (*cloudformation.ListStackInstancesOutput, error) { +func (m *Mockapi) ListStackInstances(arg0 context.Context, arg1 *cloudformation.ListStackInstancesInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.ListStackInstancesOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListStackInstances", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListStackInstances", varargs...) ret0, _ := ret[0].(*cloudformation.ListStackInstancesOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListStackInstances indicates an expected call of ListStackInstances. -func (mr *MockapiMockRecorder) ListStackInstances(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListStackInstances(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackInstances", reflect.TypeOf((*Mockapi)(nil).ListStackInstances), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackInstances", reflect.TypeOf((*Mockapi)(nil).ListStackInstances), varargs...) } // ListStackSetOperations mocks base method. -func (m *Mockapi) ListStackSetOperations(input *cloudformation.ListStackSetOperationsInput) (*cloudformation.ListStackSetOperationsOutput, error) { +func (m *Mockapi) ListStackSetOperations(arg0 context.Context, arg1 *cloudformation.ListStackSetOperationsInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.ListStackSetOperationsOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListStackSetOperations", input) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "ListStackSetOperations", varargs...) ret0, _ := ret[0].(*cloudformation.ListStackSetOperationsOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // ListStackSetOperations indicates an expected call of ListStackSetOperations. -func (mr *MockapiMockRecorder) ListStackSetOperations(input interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) ListStackSetOperations(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackSetOperations", reflect.TypeOf((*Mockapi)(nil).ListStackSetOperations), input) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStackSetOperations", reflect.TypeOf((*Mockapi)(nil).ListStackSetOperations), varargs...) } // UpdateStackSet mocks base method. -func (m *Mockapi) UpdateStackSet(arg0 *cloudformation.UpdateStackSetInput) (*cloudformation.UpdateStackSetOutput, error) { +func (m *Mockapi) UpdateStackSet(arg0 context.Context, arg1 *cloudformation.UpdateStackSetInput, arg2 ...func(*cloudformation.Options)) (*cloudformation.UpdateStackSetOutput, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateStackSet", arg0) + varargs := []interface{}{arg0, arg1} + for _, a := range arg2 { + varargs = append(varargs, a) + } + ret := m.ctrl.Call(m, "UpdateStackSet", varargs...) ret0, _ := ret[0].(*cloudformation.UpdateStackSetOutput) ret1, _ := ret[1].(error) return ret0, ret1 } // UpdateStackSet indicates an expected call of UpdateStackSet. -func (mr *MockapiMockRecorder) UpdateStackSet(arg0 interface{}) *gomock.Call { +func (mr *MockapiMockRecorder) UpdateStackSet(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStackSet", reflect.TypeOf((*Mockapi)(nil).UpdateStackSet), arg0) + varargs := append([]interface{}{arg0, arg1}, arg2...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStackSet", reflect.TypeOf((*Mockapi)(nil).UpdateStackSet), varargs...) } diff --git a/internal/pkg/aws/cloudformation/stackset/stackset.go b/internal/pkg/aws/cloudformation/stackset/stackset.go index ac6140cae20..aee24a92cfa 100644 --- a/internal/pkg/aws/cloudformation/stackset/stackset.go +++ b/internal/pkg/aws/cloudformation/stackset/stackset.go @@ -5,26 +5,27 @@ package stackset import ( + "context" "errors" "fmt" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/cloudformation" + awsv2 "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" ) type api interface { - CreateStackSet(*cloudformation.CreateStackSetInput) (*cloudformation.CreateStackSetOutput, error) - UpdateStackSet(*cloudformation.UpdateStackSetInput) (*cloudformation.UpdateStackSetOutput, error) - ListStackSetOperations(input *cloudformation.ListStackSetOperationsInput) (*cloudformation.ListStackSetOperationsOutput, error) - DeleteStackSet(*cloudformation.DeleteStackSetInput) (*cloudformation.DeleteStackSetOutput, error) - DescribeStackSet(*cloudformation.DescribeStackSetInput) (*cloudformation.DescribeStackSetOutput, error) - DescribeStackSetOperation(*cloudformation.DescribeStackSetOperationInput) (*cloudformation.DescribeStackSetOperationOutput, error) - - CreateStackInstances(*cloudformation.CreateStackInstancesInput) (*cloudformation.CreateStackInstancesOutput, error) - DeleteStackInstances(*cloudformation.DeleteStackInstancesInput) (*cloudformation.DeleteStackInstancesOutput, error) - ListStackInstances(*cloudformation.ListStackInstancesInput) (*cloudformation.ListStackInstancesOutput, error) + CreateStackSet(context.Context, *cloudformation.CreateStackSetInput, ...func(*cloudformation.Options)) (*cloudformation.CreateStackSetOutput, error) + UpdateStackSet(context.Context, *cloudformation.UpdateStackSetInput, ...func(*cloudformation.Options)) (*cloudformation.UpdateStackSetOutput, error) + ListStackSetOperations(context.Context, *cloudformation.ListStackSetOperationsInput, ...func(*cloudformation.Options)) (*cloudformation.ListStackSetOperationsOutput, error) + DeleteStackSet(context.Context, *cloudformation.DeleteStackSetInput, ...func(*cloudformation.Options)) (*cloudformation.DeleteStackSetOutput, error) + DescribeStackSet(context.Context, *cloudformation.DescribeStackSetInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeStackSetOutput, error) + DescribeStackSetOperation(context.Context, *cloudformation.DescribeStackSetOperationInput, ...func(*cloudformation.Options)) (*cloudformation.DescribeStackSetOperationOutput, error) + + CreateStackInstances(context.Context, *cloudformation.CreateStackInstancesInput, ...func(*cloudformation.Options)) (*cloudformation.CreateStackInstancesOutput, error) + DeleteStackInstances(context.Context, *cloudformation.DeleteStackInstancesInput, ...func(*cloudformation.Options)) (*cloudformation.DeleteStackInstancesOutput, error) + ListStackInstances(context.Context, *cloudformation.ListStackInstancesInput, ...func(*cloudformation.Options)) (*cloudformation.ListStackInstancesOutput, error) } // StackSet represents an AWS CloudFormation client to interact with stack sets. @@ -33,9 +34,9 @@ type StackSet struct { } // New creates a new client to make requests against stack sets. -func New(s *session.Session) *StackSet { +func New(cfg awsv2.Config) *StackSet { return &StackSet{ - client: cloudformation.New(s), + client: cloudformation.NewFromConfig(cfg), } } @@ -45,13 +46,13 @@ type CreateOrUpdateOption func(interface{}) // Create creates a new stack set resource, if one already exists then do nothing. func (ss *StackSet) Create(name, template string, opts ...CreateOrUpdateOption) error { in := &cloudformation.CreateStackSetInput{ - StackSetName: aws.String(name), - TemplateBody: aws.String(template), + StackSetName: awsv2.String(name), + TemplateBody: awsv2.String(template), } for _, opt := range opts { opt(in) } - _, err := ss.client.CreateStackSet(in) + _, err := ss.client.CreateStackSet(context.Background(), in) if err != nil { if !isAlreadyExistingStackSet(err) { return fmt.Errorf("create stack set %s: %w", name, err) @@ -62,16 +63,16 @@ func (ss *StackSet) Create(name, template string, opts ...CreateOrUpdateOption) // Describe returns a description of a created stack set. func (ss *StackSet) Describe(name string) (Description, error) { - resp, err := ss.client.DescribeStackSet(&cloudformation.DescribeStackSetInput{ - StackSetName: aws.String(name), + resp, err := ss.client.DescribeStackSet(context.Background(), &cloudformation.DescribeStackSetInput{ + StackSetName: awsv2.String(name), }) if err != nil { return Description{}, fmt.Errorf("describe stack set %s: %w", name, err) } return Description{ - ID: aws.StringValue(resp.StackSet.StackSetId), - Name: aws.StringValue(resp.StackSet.StackSetName), - Template: aws.StringValue(resp.StackSet.TemplateBody), + ID: awsv2.ToString(resp.StackSet.StackSetId), + Name: awsv2.ToString(resp.StackSet.StackSetName), + Template: awsv2.ToString(resp.StackSet.TemplateBody), }, nil } @@ -84,17 +85,17 @@ type Operation struct { // DescribeOperation returns a description of the operation. func (ss *StackSet) DescribeOperation(name, opID string) (Operation, error) { - resp, err := ss.client.DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ - StackSetName: aws.String(name), - OperationId: aws.String(opID), + resp, err := ss.client.DescribeStackSetOperation(context.Background(), &cloudformation.DescribeStackSetOperationInput{ + StackSetName: awsv2.String(name), + OperationId: awsv2.String(opID), }) if err != nil { return Operation{}, fmt.Errorf("describe operation %s for stack set %s: %w", opID, name, err) } return Operation{ ID: opID, - Status: OpStatus(aws.StringValue(resp.StackSetOperation.Status)), - Reason: aws.StringValue(resp.StackSetOperation.StatusReason), + Status: OpStatus(resp.StackSetOperation.Status), + Reason: awsv2.ToString(resp.StackSetOperation.StatusReason), }, nil } @@ -137,17 +138,17 @@ func (ss *StackSet) getInstanceSummaries(name string) ([]InstanceSummary, error) // If there is no instance in the given account and region, this function will return an operation ID // but the API call will take no action. func (ss *StackSet) DeleteInstance(name, account, region string) (string, error) { - out, err := ss.client.DeleteStackInstances(&cloudformation.DeleteStackInstancesInput{ - StackSetName: aws.String(name), - Accounts: aws.StringSlice([]string{account}), - Regions: aws.StringSlice([]string{region}), - RetainStacks: aws.Bool(false), + out, err := ss.client.DeleteStackInstances(context.Background(), &cloudformation.DeleteStackInstancesInput{ + StackSetName: awsv2.String(name), + Accounts: []string{account}, + Regions: []string{region}, + RetainStacks: awsv2.Bool(false), }) if err != nil { return "", fmt.Errorf("delete stack instance in region %v for account %v for stackset %s: %w", region, account, name, err) } - return aws.StringValue(out.OperationId), nil + return awsv2.ToString(out.OperationId), nil } // DeleteAllInstances removes all stack instances from a stack set and returns the operation ID. @@ -177,23 +178,23 @@ func (ss *StackSet) DeleteAllInstances(name string) (string, error) { regions = append(regions, region) } - out, err := ss.client.DeleteStackInstances(&cloudformation.DeleteStackInstancesInput{ - StackSetName: aws.String(name), - Accounts: aws.StringSlice(accounts), - Regions: aws.StringSlice(regions), - RetainStacks: aws.Bool(false), + out, err := ss.client.DeleteStackInstances(context.Background(), &cloudformation.DeleteStackInstancesInput{ + StackSetName: awsv2.String(name), + Accounts: accounts, + Regions: regions, + RetainStacks: awsv2.Bool(false), }) if err != nil { return "", fmt.Errorf("delete stack instances in regions %v for accounts %v for stackset %s: %w", regions, accounts, name, err) } - return aws.StringValue(out.OperationId), nil + return awsv2.ToString(out.OperationId), nil } // Delete deletes the stack set, if the stack set does not exist then just return nil. func (ss *StackSet) Delete(name string) error { - if _, err := ss.client.DeleteStackSet(&cloudformation.DeleteStackSetInput{ - StackSetName: aws.String(name), + if _, err := ss.client.DeleteStackSet(context.Background(), &cloudformation.DeleteStackSetInput{ + StackSetName: awsv2.String(name), }); err != nil { if !isNotFoundStackSet(err) { return fmt.Errorf("delete stack set %s: %w", name, err) @@ -231,7 +232,7 @@ type InstanceSummariesOption func(input *cloudformation.ListStackInstancesInput) // InstanceSummaries returns a list of unique identifiers for all the stack instances in a stack set. func (ss *StackSet) InstanceSummaries(name string, opts ...InstanceSummariesOption) ([]InstanceSummary, error) { in := &cloudformation.ListStackInstancesInput{ - StackSetName: aws.String(name), + StackSetName: awsv2.String(name), } for _, opt := range opts { opt(in) @@ -239,18 +240,18 @@ func (ss *StackSet) InstanceSummaries(name string, opts ...InstanceSummariesOpti var summaries []InstanceSummary for { - resp, err := ss.client.ListStackInstances(in) + resp, err := ss.client.ListStackInstances(context.Background(), in) if err != nil { return nil, fmt.Errorf("list stack instances for stack set %s: %w", name, err) } for _, cfnSummary := range resp.Summaries { summary := InstanceSummary{ - StackID: aws.StringValue(cfnSummary.StackId), - Account: aws.StringValue(cfnSummary.Account), - Region: aws.StringValue(cfnSummary.Region), + StackID: awsv2.ToString(cfnSummary.StackId), + Account: awsv2.ToString(cfnSummary.Account), + Region: awsv2.ToString(cfnSummary.Region), } if status := cfnSummary.StackInstanceStatus; status != nil { - summary.Status = InstanceStatus(aws.StringValue(status.DetailedStatus)) + summary.Status = InstanceStatus(status.DetailedStatus) } summaries = append(summaries, summary) } @@ -264,16 +265,16 @@ func (ss *StackSet) InstanceSummaries(name string, opts ...InstanceSummariesOpti func (ss *StackSet) update(name, template string, opts ...CreateOrUpdateOption) (string, error) { in := &cloudformation.UpdateStackSetInput{ - StackSetName: aws.String(name), - TemplateBody: aws.String(template), - OperationPreferences: &cloudformation.StackSetOperationPreferences{ - RegionConcurrencyType: aws.String(cloudformation.RegionConcurrencyTypeParallel), + StackSetName: awsv2.String(name), + TemplateBody: awsv2.String(template), + OperationPreferences: &types.StackSetOperationPreferences{ + RegionConcurrencyType: types.RegionConcurrencyTypeParallel, }, } for _, opt := range opts { opt(in) } - resp, err := ss.client.UpdateStackSet(in) + resp, err := ss.client.UpdateStackSet(context.Background(), in) if err != nil { if isOutdatedStackSet(err) { return "", &ErrStackSetOutOfDate{ @@ -283,27 +284,27 @@ func (ss *StackSet) update(name, template string, opts ...CreateOrUpdateOption) } return "", fmt.Errorf("update stack set %s: %w", name, err) } - return aws.StringValue(resp.OperationId), nil + return awsv2.ToString(resp.OperationId), nil } func (ss *StackSet) createInstances(name string, accounts, regions []string) (string, error) { - resp, err := ss.client.CreateStackInstances(&cloudformation.CreateStackInstancesInput{ - StackSetName: aws.String(name), - Accounts: aws.StringSlice(accounts), - Regions: aws.StringSlice(regions), + resp, err := ss.client.CreateStackInstances(context.Background(), &cloudformation.CreateStackInstancesInput{ + StackSetName: awsv2.String(name), + Accounts: accounts, + Regions: regions, }) if err != nil { return "", fmt.Errorf("create stack instances for stack set %s in regions %v for accounts %v: %w", name, regions, accounts, err) } - return aws.StringValue(resp.OperationId), nil + return awsv2.ToString(resp.OperationId), nil } // WaitForStackSetLastOperationComplete waits until the stackset's last operation completes. func (ss *StackSet) WaitForStackSetLastOperationComplete(name string) error { for { - resp, err := ss.client.ListStackSetOperations(&cloudformation.ListStackSetOperationsInput{ - StackSetName: aws.String(name), + resp, err := ss.client.ListStackSetOperations(context.Background(), &cloudformation.ListStackSetOperationsInput{ + StackSetName: awsv2.String(name), }) if err != nil { return fmt.Errorf("list operations for stack set %s: %w", name, err) @@ -312,10 +313,10 @@ func (ss *StackSet) WaitForStackSetLastOperationComplete(name string) error { return nil } operation := resp.Summaries[0] - switch aws.StringValue(operation.Status) { - case cloudformation.StackSetOperationStatusRunning: - case cloudformation.StackSetOperationStatusStopping: - case cloudformation.StackSetOperationStatusQueued: + switch operation.Status { + case types.StackSetOperationStatusRunning: + case types.StackSetOperationStatusStopping: + case types.StackSetOperationStatusQueued: default: return nil } @@ -326,20 +327,20 @@ func (ss *StackSet) WaitForStackSetLastOperationComplete(name string) error { // WaitForOperation waits for the operation with opID to reaches a successful completion status. func (ss *StackSet) WaitForOperation(name, opID string) error { for { - response, err := ss.client.DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ - StackSetName: aws.String(name), - OperationId: aws.String(opID), + response, err := ss.client.DescribeStackSetOperation(context.Background(), &cloudformation.DescribeStackSetOperationInput{ + StackSetName: awsv2.String(name), + OperationId: awsv2.String(opID), }) if err != nil { return fmt.Errorf("describe operation %s for stack set %s: %w", opID, name, err) } - if aws.StringValue(response.StackSetOperation.Status) == opStatusSucceeded { + if OpStatus(response.StackSetOperation.Status) == opStatusSucceeded { return nil } - if aws.StringValue(response.StackSetOperation.Status) == opStatusStopped { + if OpStatus(response.StackSetOperation.Status) == opStatusStopped { return fmt.Errorf("operation %s for stack set %s was manually stopped", opID, name) } - if aws.StringValue(response.StackSetOperation.Status) == opStatusFailed { + if OpStatus(response.StackSetOperation.Status) == opStatusFailed { return fmt.Errorf("operation %s for stack set %s failed", opID, name) } time.Sleep(3 * time.Second) @@ -352,11 +353,11 @@ func WithDescription(description string) CreateOrUpdateOption { switch v := input.(type) { case *cloudformation.CreateStackSetInput: { - v.Description = aws.String(description) + v.Description = awsv2.String(description) } case *cloudformation.UpdateStackSetInput: { - v.Description = aws.String(description) + v.Description = awsv2.String(description) } } } @@ -368,11 +369,11 @@ func WithExecutionRoleName(roleName string) CreateOrUpdateOption { switch v := input.(type) { case *cloudformation.CreateStackSetInput: { - v.ExecutionRoleName = aws.String(roleName) + v.ExecutionRoleName = awsv2.String(roleName) } case *cloudformation.UpdateStackSetInput: { - v.ExecutionRoleName = aws.String(roleName) + v.ExecutionRoleName = awsv2.String(roleName) } } } @@ -384,11 +385,11 @@ func WithAdministrationRoleARN(roleARN string) CreateOrUpdateOption { switch v := input.(type) { case *cloudformation.CreateStackSetInput: { - v.AdministrationRoleARN = aws.String(roleARN) + v.AdministrationRoleARN = awsv2.String(roleARN) } case *cloudformation.UpdateStackSetInput: { - v.AdministrationRoleARN = aws.String(roleARN) + v.AdministrationRoleARN = awsv2.String(roleARN) } } } @@ -397,11 +398,11 @@ func WithAdministrationRoleARN(roleARN string) CreateOrUpdateOption { // WithTags sets tags to all the resources in a stack set. func WithTags(tags map[string]string) CreateOrUpdateOption { return func(input interface{}) { - var flatTags []*cloudformation.Tag + var flatTags []types.Tag for k, v := range tags { - flatTags = append(flatTags, &cloudformation.Tag{ - Key: aws.String(k), - Value: aws.String(v), + flatTags = append(flatTags, types.Tag{ + Key: awsv2.String(k), + Value: awsv2.String(v), }) } @@ -425,7 +426,7 @@ func WithOperationID(operationID string) CreateOrUpdateOption { switch v := input.(type) { case *cloudformation.UpdateStackSetInput: { - v.OperationId = aws.String(operationID) + v.OperationId = awsv2.String(operationID) } } } @@ -434,14 +435,14 @@ func WithOperationID(operationID string) CreateOrUpdateOption { // FilterSummariesByAccountID limits the accountID for the stack instance summaries to retrieve. func FilterSummariesByAccountID(accountID string) InstanceSummariesOption { return func(input *cloudformation.ListStackInstancesInput) { - input.StackInstanceAccount = aws.String(accountID) + input.StackInstanceAccount = awsv2.String(accountID) } } // FilterSummariesByRegion limits the region for the stack instance summaries to retrieve. func FilterSummariesByRegion(region string) InstanceSummariesOption { return func(input *cloudformation.ListStackInstancesInput) { - input.StackInstanceRegion = aws.String(region) + input.StackInstanceRegion = awsv2.String(region) } } @@ -449,9 +450,9 @@ func FilterSummariesByRegion(region string) InstanceSummariesOption { func FilterSummariesByDetailedStatus(values []InstanceStatus) InstanceSummariesOption { return func(input *cloudformation.ListStackInstancesInput) { for _, value := range values { - input.Filters = append(input.Filters, &cloudformation.StackInstanceFilter{ - Name: aws.String(cloudformation.StackInstanceFilterNameDetailedStatus), - Values: aws.String(string(value)), + input.Filters = append(input.Filters, types.StackInstanceFilter{ + Name: types.StackInstanceFilterNameDetailedStatus, + Values: awsv2.String(string(value)), }) } } diff --git a/internal/pkg/aws/cloudformation/stackset/stackset_test.go b/internal/pkg/aws/cloudformation/stackset/stackset_test.go index 5c3533a5252..b07d5730129 100644 --- a/internal/pkg/aws/cloudformation/stackset/stackset_test.go +++ b/internal/pkg/aws/cloudformation/stackset/stackset_test.go @@ -4,14 +4,16 @@ package stackset import ( + "context" "errors" "fmt" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation/stackset/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "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" + "github.com/aws/smithy-go" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -20,6 +22,12 @@ const testName = "stackset" var testError = errors.New("some error") +func apiErr(code string) error { + return &smithy.GenericAPIError{ + Code: code, + } +} + func TestStackSet_Create(t *testing.T) { const ( testTemplate = "body" @@ -37,12 +45,12 @@ func TestStackSet_Create(t *testing.T) { "succeeds if new stack set": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().CreateStackSet(&cloudformation.CreateStackSetInput{ + m.EXPECT().CreateStackSet(gomock.Any(), &cloudformation.CreateStackSetInput{ AdministrationRoleARN: aws.String(testAdministrationRole), Description: aws.String(testDescription), ExecutionRoleName: aws.String(testExecutionRole), StackSetName: aws.String(testName), - Tags: []*cloudformation.Tag{ + Tags: []types.Tag{ { Key: aws.String("owner"), Value: aws.String("boss"), @@ -56,14 +64,14 @@ func TestStackSet_Create(t *testing.T) { "succeeds if stack set already exists": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().CreateStackSet(gomock.Any()).Return(nil, awserr.New(cloudformation.ErrCodeNameAlreadyExistsException, "", nil)) + m.EXPECT().CreateStackSet(gomock.Any(), gomock.Any()).Return(nil, apiErr("NameAlreadyExistsException")) return m }, }, "wraps error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().CreateStackSet(gomock.Any()).Return(nil, testError) + m.EXPECT().CreateStackSet(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: fmt.Errorf("create stack set %s: %w", testName, testError), @@ -100,10 +108,10 @@ func TestStackSet_Describe(t *testing.T) { "succeeds": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSet(&cloudformation.DescribeStackSetInput{ + m.EXPECT().DescribeStackSet(gomock.Any(), &cloudformation.DescribeStackSetInput{ StackSetName: aws.String(testName), }).Return(&cloudformation.DescribeStackSetOutput{ - StackSet: &cloudformation.StackSet{ + StackSet: &types.StackSet{ StackSetId: aws.String(testName), StackSetName: aws.String(testName), TemplateBody: aws.String("body"), @@ -120,7 +128,7 @@ func TestStackSet_Describe(t *testing.T) { "wraps error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSet(gomock.Any()).Return(nil, testError) + m.EXPECT().DescribeStackSet(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: fmt.Errorf("describe stack set %s: %w", testName, testError), @@ -157,12 +165,12 @@ func TestStackSet_DescribeOperation(t *testing.T) { "returns the operation description on successful call": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ + m.EXPECT().DescribeStackSetOperation(gomock.Any(), &cloudformation.DescribeStackSetOperationInput{ StackSetName: aws.String(testName), OperationId: aws.String(testOpID), }).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(cloudformation.StackSetOperationStatusStopped), + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatusStopped, StatusReason: aws.String("manually stopped"), }, }, nil) @@ -170,14 +178,14 @@ func TestStackSet_DescribeOperation(t *testing.T) { }, wantedOp: Operation{ ID: testOpID, - Status: OpStatus(cloudformation.StackSetOperationStatusStopped), + Status: OpStatus(types.StackSetOperationStatusStopped), Reason: "manually stopped", }, }, "wraps error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSetOperation(gomock.Any()).Return(nil, testError) + m.EXPECT().DescribeStackSetOperation(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: errors.New("describe operation 1 for stack set stackset: some error"), @@ -219,9 +227,9 @@ func TestStackSet_Update(t *testing.T) { testTags = map[string]string{ "owner": "boss", } - errOpExists = awserr.New(cloudformation.ErrCodeOperationIdAlreadyExistsException, "", nil) - errOpInProg = awserr.New(cloudformation.ErrCodeOperationInProgressException, "", nil) - errOpStale = awserr.New(cloudformation.ErrCodeStaleRequestException, "", nil) + errOpExists = apiErr("OperationIdAlreadyExistsException") + errOpInProg = apiErr("OperationInProgressException") + errOpStale = apiErr("StaleRequestException") ) testCases := map[string]struct { @@ -233,20 +241,20 @@ func TestStackSet_Update(t *testing.T) { "updates stack with operation is valid": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(&cloudformation.UpdateStackSetInput{ + m.EXPECT().UpdateStackSet(gomock.Any(), &cloudformation.UpdateStackSetInput{ OperationId: aws.String(testOperationID), AdministrationRoleARN: aws.String(testAdministrationRole), Description: aws.String(testDescription), ExecutionRoleName: aws.String(testExecutionRole), StackSetName: aws.String(testName), - Tags: []*cloudformation.Tag{ + Tags: []types.Tag{ { Key: aws.String("owner"), Value: aws.String("boss"), }, }, - OperationPreferences: &cloudformation.StackSetOperationPreferences{ - RegionConcurrencyType: aws.String(cloudformation.RegionConcurrencyTypeParallel), + OperationPreferences: &types.StackSetOperationPreferences{ + RegionConcurrencyType: types.RegionConcurrencyTypeParallel, }, TemplateBody: aws.String(testTemplate), }).Return(&cloudformation.UpdateStackSetOutput{ @@ -259,7 +267,7 @@ func TestStackSet_Update(t *testing.T) { "returns ErrStackSetOutOfDate if operation exists already": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(nil, errOpExists) + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(nil, errOpExists) return m }, wantedError: &ErrStackSetOutOfDate{ @@ -270,7 +278,7 @@ func TestStackSet_Update(t *testing.T) { "returns ErrStackSetOutOfDate if operation in progress": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(nil, errOpInProg) + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(nil, errOpInProg) return m }, wantedError: &ErrStackSetOutOfDate{ @@ -281,7 +289,7 @@ func TestStackSet_Update(t *testing.T) { "returns ErrStackSetOutOfDate if operation is stale": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(nil, errOpStale) + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(nil, errOpStale) return m }, wantedError: &ErrStackSetOutOfDate{ @@ -292,7 +300,7 @@ func TestStackSet_Update(t *testing.T) { "wrap error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(nil, testError) + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: fmt.Errorf("update stack set %s: %w", testName, testError), @@ -336,15 +344,15 @@ func TestStackSet_UpdateAndWait(t *testing.T) { "waits until operation succeeds": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(&cloudformation.UpdateStackSetOutput{ + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(&cloudformation.UpdateStackSetOutput{ OperationId: aws.String("1"), }, nil) - m.EXPECT().DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ + m.EXPECT().DescribeStackSetOperation(gomock.Any(), &cloudformation.DescribeStackSetOperationInput{ StackSetName: aws.String(testName), OperationId: aws.String("1"), }).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(opStatusSucceeded), + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatus(opStatusSucceeded), }, }, nil) return m @@ -353,12 +361,12 @@ func TestStackSet_UpdateAndWait(t *testing.T) { "returns a wrapped error if operation stopped": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(&cloudformation.UpdateStackSetOutput{ + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(&cloudformation.UpdateStackSetOutput{ OperationId: aws.String("1"), }, nil) - m.EXPECT().DescribeStackSetOperation(gomock.Any()).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(opStatusStopped), + m.EXPECT().DescribeStackSetOperation(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackSetOperationOutput{ + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatus(opStatusStopped), }, }, nil) return m @@ -368,12 +376,12 @@ func TestStackSet_UpdateAndWait(t *testing.T) { "returns a wrapped error if operation failed": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().UpdateStackSet(gomock.Any()).Return(&cloudformation.UpdateStackSetOutput{ + m.EXPECT().UpdateStackSet(gomock.Any(), gomock.Any()).Return(&cloudformation.UpdateStackSetOutput{ OperationId: aws.String("1"), }, nil) - m.EXPECT().DescribeStackSetOperation(gomock.Any()).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(opStatusFailed), + m.EXPECT().DescribeStackSetOperation(gomock.Any(), gomock.Any()).Return(&cloudformation.DescribeStackSetOperationOutput{ + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatus(opStatusFailed), }, }, nil) return m @@ -413,7 +421,7 @@ func TestStackSet_DeleteInstance(t *testing.T) { "returns if the account and region aren't found in the list of instances": { mockClient: func(t *testing.T, ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DeleteStackInstances(gomock.Any()).Return(nil, fmt.Errorf("some error")) + m.EXPECT().DeleteStackInstances(gomock.Any(), gomock.Any()).Return(nil, fmt.Errorf("some error")) return m }, inputRegion: "us-west-1", @@ -424,12 +432,12 @@ func TestStackSet_DeleteInstance(t *testing.T) { "successfully deletes stack instance and returns the operation ID": { mockClient: func(t *testing.T, ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DeleteStackInstances(gomock.Any()). - DoAndReturn(func(in *cloudformation.DeleteStackInstancesInput) (*cloudformation.DeleteStackInstancesOutput, error) { - require.Equal(t, testName, aws.StringValue(in.StackSetName)) - require.ElementsMatch(t, []string{"1111"}, aws.StringValueSlice(in.Accounts)) - require.ElementsMatch(t, []string{"us-east-1"}, aws.StringValueSlice(in.Regions)) - require.False(t, aws.BoolValue(in.RetainStacks)) + m.EXPECT().DeleteStackInstances(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, in *cloudformation.DeleteStackInstancesInput, _ ...func(*cloudformation.Options)) (*cloudformation.DeleteStackInstancesOutput, error) { + require.Equal(t, testName, aws.ToString(in.StackSetName)) + require.ElementsMatch(t, []string{"1111"}, in.Accounts) + require.ElementsMatch(t, []string{"us-east-1"}, in.Regions) + require.False(t, aws.ToBool(in.RetainStacks)) return &cloudformation.DeleteStackInstancesOutput{ OperationId: aws.String("1"), }, nil @@ -473,21 +481,21 @@ func TestStackSet_WaitForStackSetLastOperationComplete(t *testing.T) { "waits until operation succeeds": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackSetOperations(&cloudformation.ListStackSetOperationsInput{ + m.EXPECT().ListStackSetOperations(gomock.Any(), &cloudformation.ListStackSetOperationsInput{ StackSetName: aws.String(testName), }).Return(&cloudformation.ListStackSetOperationsOutput{ - Summaries: []*cloudformation.StackSetOperationSummary{ + Summaries: []types.StackSetOperationSummary{ { - Status: aws.String(cloudformation.StackSetOperationStatusRunning), + Status: types.StackSetOperationStatusRunning, }, }, }, nil) - m.EXPECT().ListStackSetOperations(&cloudformation.ListStackSetOperationsInput{ + m.EXPECT().ListStackSetOperations(gomock.Any(), &cloudformation.ListStackSetOperationsInput{ StackSetName: aws.String(testName), }).Return(&cloudformation.ListStackSetOperationsOutput{ - Summaries: []*cloudformation.StackSetOperationSummary{ + Summaries: []types.StackSetOperationSummary{ { - Status: aws.String(cloudformation.StackSetOperationStatusSucceeded), + Status: types.StackSetOperationStatusSucceeded, }, }, }, nil) @@ -497,10 +505,10 @@ func TestStackSet_WaitForStackSetLastOperationComplete(t *testing.T) { "return if no operation": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackSetOperations(&cloudformation.ListStackSetOperationsInput{ + m.EXPECT().ListStackSetOperations(gomock.Any(), &cloudformation.ListStackSetOperationsInput{ StackSetName: aws.String(testName), }).Return(&cloudformation.ListStackSetOperationsOutput{ - Summaries: []*cloudformation.StackSetOperationSummary{}, + Summaries: []types.StackSetOperationSummary{}, }, nil) return m }, @@ -508,7 +516,7 @@ func TestStackSet_WaitForStackSetLastOperationComplete(t *testing.T) { "error if fail to list stackset operation": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackSetOperations(&cloudformation.ListStackSetOperationsInput{ + m.EXPECT().ListStackSetOperations(gomock.Any(), &cloudformation.ListStackSetOperationsInput{ StackSetName: aws.String(testName), }).Return(nil, errors.New("some error")) return m @@ -549,7 +557,7 @@ func TestStackSet_DeleteAllInstances(t *testing.T) { "return ErrStackSetNotFound if the stack set does not exist": { mockClient: func(t *testing.T, ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackInstances(gomock.Any()).Return(nil, awserr.New(cloudformation.ErrCodeStackSetNotFoundException, "", nil)) + m.EXPECT().ListStackInstances(gomock.Any(), gomock.Any()).Return(nil, apiErr("StackSetNotFoundException")) return m }, wantedError: &ErrStackSetNotFound{name: testName}, @@ -557,8 +565,8 @@ func TestStackSet_DeleteAllInstances(t *testing.T) { "returns ErrStackSetInstancesNotFound if there are no stack set instances": { mockClient: func(t *testing.T, ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackInstances(gomock.Any()).Return(&cloudformation.ListStackInstancesOutput{ - Summaries: []*cloudformation.StackInstanceSummary{}, + m.EXPECT().ListStackInstances(gomock.Any(), gomock.Any()).Return(&cloudformation.ListStackInstancesOutput{ + Summaries: []types.StackInstanceSummary{}, }, nil) return m }, @@ -567,8 +575,8 @@ func TestStackSet_DeleteAllInstances(t *testing.T) { "successfully deletes stack instances and returns the operation ID": { mockClient: func(t *testing.T, ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackInstances(gomock.Any()).Return(&cloudformation.ListStackInstancesOutput{ - Summaries: []*cloudformation.StackInstanceSummary{ + m.EXPECT().ListStackInstances(gomock.Any(), gomock.Any()).Return(&cloudformation.ListStackInstancesOutput{ + Summaries: []types.StackInstanceSummary{ { Account: aws.String("1111"), Region: aws.String("us-east-1"), @@ -583,12 +591,12 @@ func TestStackSet_DeleteAllInstances(t *testing.T) { }, }, }, nil) - m.EXPECT().DeleteStackInstances(gomock.Any()). - DoAndReturn(func(in *cloudformation.DeleteStackInstancesInput) (*cloudformation.DeleteStackInstancesOutput, error) { - require.Equal(t, testName, aws.StringValue(in.StackSetName)) - require.ElementsMatch(t, []string{"1111", "2222"}, aws.StringValueSlice(in.Accounts)) - require.ElementsMatch(t, []string{"us-east-1", "us-west-2"}, aws.StringValueSlice(in.Regions)) - require.False(t, aws.BoolValue(in.RetainStacks)) + m.EXPECT().DeleteStackInstances(gomock.Any(), gomock.Any()). + DoAndReturn(func(_ context.Context, in *cloudformation.DeleteStackInstancesInput, _ ...func(*cloudformation.Options)) (*cloudformation.DeleteStackInstancesOutput, error) { + require.Equal(t, testName, aws.ToString(in.StackSetName)) + require.ElementsMatch(t, []string{"1111", "2222"}, in.Accounts) + require.ElementsMatch(t, []string{"us-east-1", "us-west-2"}, in.Regions) + require.False(t, aws.ToBool(in.RetainStacks)) return &cloudformation.DeleteStackInstancesOutput{ OperationId: aws.String("1"), }, nil @@ -630,14 +638,14 @@ func TestStackSet_Delete(t *testing.T) { "successfully exits if stack set does not exist": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DeleteStackSet(gomock.Any()).Return(nil, awserr.New(cloudformation.ErrCodeStackSetNotFoundException, "", nil)) + m.EXPECT().DeleteStackSet(gomock.Any(), gomock.Any()).Return(nil, apiErr("StackSetNotFoundException")) return m }, }, "wraps error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DeleteStackSet(gomock.Any()).Return(nil, testError) + m.EXPECT().DeleteStackSet(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: fmt.Errorf("delete stack set %s: %w", testName, testError), @@ -676,10 +684,10 @@ func TestStackSet_CreateInstances(t *testing.T) { "successfully creates stack instances": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().CreateStackInstances(&cloudformation.CreateStackInstancesInput{ + m.EXPECT().CreateStackInstances(gomock.Any(), &cloudformation.CreateStackInstancesInput{ StackSetName: aws.String(testName), - Accounts: aws.StringSlice(testAccounts), - Regions: aws.StringSlice(testRegions), + Accounts: testAccounts, + Regions: testRegions, }).Return(&cloudformation.CreateStackInstancesOutput{ OperationId: aws.String("1"), }, nil) @@ -690,7 +698,7 @@ func TestStackSet_CreateInstances(t *testing.T) { "wraps error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().CreateStackInstances(gomock.Any()).Return(nil, testError) + m.EXPECT().CreateStackInstances(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: fmt.Errorf("create stack instances for stack set %s in regions %v for accounts %v: %w", @@ -737,12 +745,12 @@ func TestStackSet_InstanceSummaries(t *testing.T) { "returns summaries": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackInstances(&cloudformation.ListStackInstancesInput{ + m.EXPECT().ListStackInstances(gomock.Any(), &cloudformation.ListStackInstancesInput{ StackSetName: aws.String(testName), StackInstanceAccount: aws.String(testAccountID), StackInstanceRegion: aws.String(testRegion), }).Return(&cloudformation.ListStackInstancesOutput{ - Summaries: []*cloudformation.StackInstanceSummary{ + Summaries: []types.StackInstanceSummary{ { StackId: aws.String(testName), Account: aws.String(testAccountID), @@ -763,7 +771,7 @@ func TestStackSet_InstanceSummaries(t *testing.T) { "wraps error on unexpected failure": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().ListStackInstances(gomock.Any()).Return(nil, testError) + m.EXPECT().ListStackInstances(gomock.Any(), gomock.Any()).Return(nil, testError) return m }, wantedError: fmt.Errorf("list stack instances for stack set %s: %w", testName, testError), @@ -772,36 +780,36 @@ func TestStackSet_InstanceSummaries(t *testing.T) { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) gomock.InOrder( - m.EXPECT().ListStackInstances(&cloudformation.ListStackInstancesInput{ + m.EXPECT().ListStackInstances(gomock.Any(), &cloudformation.ListStackInstancesInput{ StackSetName: aws.String(testName), StackInstanceAccount: aws.String(testAccountID), StackInstanceRegion: aws.String(testRegion), }).Return(&cloudformation.ListStackInstancesOutput{ - Summaries: []*cloudformation.StackInstanceSummary{ + Summaries: []types.StackInstanceSummary{ { StackId: aws.String("1111"), Account: aws.String(testAccountID), Region: aws.String("us-west-2"), - StackInstanceStatus: &cloudformation.StackInstanceComprehensiveStatus{ - DetailedStatus: aws.String(instanceStatusRunning), + StackInstanceStatus: &types.StackInstanceComprehensiveStatus{ + DetailedStatus: types.StackInstanceDetailedStatus(instanceStatusRunning), }, }, }, NextToken: aws.String("token"), }, nil), - m.EXPECT().ListStackInstances(&cloudformation.ListStackInstancesInput{ + m.EXPECT().ListStackInstances(gomock.Any(), &cloudformation.ListStackInstancesInput{ StackSetName: aws.String(testName), StackInstanceAccount: aws.String(testAccountID), StackInstanceRegion: aws.String(testRegion), NextToken: aws.String("token"), }).Return(&cloudformation.ListStackInstancesOutput{ - Summaries: []*cloudformation.StackInstanceSummary{ + Summaries: []types.StackInstanceSummary{ { StackId: aws.String("2222"), Account: aws.String(testAccountID), Region: aws.String("us-east-1"), - StackInstanceStatus: &cloudformation.StackInstanceComprehensiveStatus{ - DetailedStatus: aws.String(instanceStatusSucceeded), + StackInstanceStatus: &types.StackInstanceComprehensiveStatus{ + DetailedStatus: types.StackInstanceDetailedStatus(instanceStatusSucceeded), }, }, }, @@ -861,12 +869,12 @@ func TestStackSet_WaitForOperation(t *testing.T) { "returns nil if the operation status is successful": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ + m.EXPECT().DescribeStackSetOperation(gomock.Any(), &cloudformation.DescribeStackSetOperationInput{ StackSetName: aws.String(testName), OperationId: aws.String(testOpID), }).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(cloudformation.StackSetOperationStatusSucceeded), + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatusSucceeded, }, }, nil) return m @@ -875,12 +883,12 @@ func TestStackSet_WaitForOperation(t *testing.T) { "returns an error if the operation stopped": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ + m.EXPECT().DescribeStackSetOperation(gomock.Any(), &cloudformation.DescribeStackSetOperationInput{ StackSetName: aws.String(testName), OperationId: aws.String(testOpID), }).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(cloudformation.StackSetOperationStatusStopped), + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatusStopped, }, }, nil) return m @@ -890,12 +898,12 @@ func TestStackSet_WaitForOperation(t *testing.T) { "returns an error if the operation failed": { mockClient: func(ctrl *gomock.Controller) api { m := mocks.NewMockapi(ctrl) - m.EXPECT().DescribeStackSetOperation(&cloudformation.DescribeStackSetOperationInput{ + m.EXPECT().DescribeStackSetOperation(gomock.Any(), &cloudformation.DescribeStackSetOperationInput{ StackSetName: aws.String(testName), OperationId: aws.String(testOpID), }).Return(&cloudformation.DescribeStackSetOperationOutput{ - StackSetOperation: &cloudformation.StackSetOperation{ - Status: aws.String(cloudformation.StackSetOperationStatusFailed), + StackSetOperation: &types.StackSetOperation{ + Status: types.StackSetOperationStatusFailed, }, }, nil) return m diff --git a/internal/pkg/aws/cloudformation/stackset/status.go b/internal/pkg/aws/cloudformation/stackset/status.go index 7d446166603..681f92e154c 100644 --- a/internal/pkg/aws/cloudformation/stackset/status.go +++ b/internal/pkg/aws/cloudformation/stackset/status.go @@ -3,24 +3,24 @@ package stackset -import "github.com/aws/aws-sdk-go/service/cloudformation" +import "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" const ( - opStatusSucceeded = cloudformation.StackSetOperationStatusSucceeded - opStatusStopped = cloudformation.StackSetOperationStatusStopped - opStatusFailed = cloudformation.StackSetOperationStatusFailed - opStatusRunning = cloudformation.StackSetOperationStatusRunning - opStatusStopping = cloudformation.StackSetOperationStatusStopping - opStatusQueued = cloudformation.StackSetOperationStatusQueued + opStatusSucceeded = OpStatus(types.StackSetOperationStatusSucceeded) + opStatusStopped = OpStatus(types.StackSetOperationStatusStopped) + opStatusFailed = OpStatus(types.StackSetOperationStatusFailed) + opStatusRunning = OpStatus(types.StackSetOperationStatusRunning) + opStatusStopping = OpStatus(types.StackSetOperationStatusStopping) + opStatusQueued = OpStatus(types.StackSetOperationStatusQueued) ) const ( - instanceStatusPending = cloudformation.StackInstanceDetailedStatusPending - instanceStatusRunning = cloudformation.StackInstanceDetailedStatusRunning - instanceStatusSucceeded = cloudformation.StackInstanceDetailedStatusSucceeded - instanceStatusFailed = cloudformation.StackInstanceDetailedStatusFailed - instanceStatusCancelled = cloudformation.StackInstanceDetailedStatusCancelled - instanceStatusInoperable = cloudformation.StackInstanceDetailedStatusInoperable + instanceStatusPending = InstanceStatus(types.StackInstanceDetailedStatusPending) + instanceStatusRunning = InstanceStatus(types.StackInstanceDetailedStatusRunning) + instanceStatusSucceeded = InstanceStatus(types.StackInstanceDetailedStatusSucceeded) + instanceStatusFailed = InstanceStatus(types.StackInstanceDetailedStatusFailed) + instanceStatusCancelled = InstanceStatus(types.StackInstanceDetailedStatusCancelled) + instanceStatusInoperable = InstanceStatus(types.StackInstanceDetailedStatusInoperable) ) // OpStatus represents a stack set operation status. diff --git a/internal/pkg/aws/cloudformation/stackset/status_test.go b/internal/pkg/aws/cloudformation/stackset/status_test.go index 8b770a65c5a..1cfcaf18416 100644 --- a/internal/pkg/aws/cloudformation/stackset/status_test.go +++ b/internal/pkg/aws/cloudformation/stackset/status_test.go @@ -6,7 +6,7 @@ package stackset import ( "testing" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/stretchr/testify/require" ) @@ -16,24 +16,24 @@ func TestOpStatus_IsCompleted(t *testing.T) { wanted bool }{ "false when queued": { - status: cloudformation.StackSetOperationStatusQueued, + status: string(types.StackSetOperationStatusQueued), }, "false when running": { - status: cloudformation.StackSetOperationStatusRunning, + status: string(types.StackSetOperationStatusRunning), }, "false when stopping": { - status: cloudformation.StackSetOperationStatusStopping, + status: string(types.StackSetOperationStatusStopping), }, "true when succeeded": { - status: cloudformation.StackSetOperationStatusSucceeded, + status: string(types.StackSetOperationStatusSucceeded), wanted: true, }, "true when stopped": { - status: cloudformation.StackSetOperationStatusStopped, + status: string(types.StackSetOperationStatusStopped), wanted: true, }, "true when failed": { - status: cloudformation.StackSetOperationStatusFailed, + status: string(types.StackSetOperationStatusFailed), wanted: true, }, } @@ -51,23 +51,23 @@ func TestOpStatus_IsSuccess(t *testing.T) { wanted bool }{ "false when queued": { - status: cloudformation.StackSetOperationStatusQueued, + status: string(types.StackSetOperationStatusQueued), }, "false when running": { - status: cloudformation.StackSetOperationStatusRunning, + status: string(types.StackSetOperationStatusRunning), }, "false when stopping": { - status: cloudformation.StackSetOperationStatusStopping, + status: string(types.StackSetOperationStatusStopping), }, "true when succeeded": { - status: cloudformation.StackSetOperationStatusSucceeded, + status: string(types.StackSetOperationStatusSucceeded), wanted: true, }, "false when stopped": { - status: cloudformation.StackSetOperationStatusStopped, + status: string(types.StackSetOperationStatusStopped), }, "false when failed": { - status: cloudformation.StackSetOperationStatusFailed, + status: string(types.StackSetOperationStatusFailed), }, } @@ -84,25 +84,25 @@ func TestOpStatus_InProgress(t *testing.T) { wanted bool }{ "true when queued": { - status: cloudformation.StackSetOperationStatusQueued, + status: string(types.StackSetOperationStatusQueued), wanted: true, }, "true when running": { - status: cloudformation.StackSetOperationStatusRunning, + status: string(types.StackSetOperationStatusRunning), wanted: true, }, "true when stopping": { - status: cloudformation.StackSetOperationStatusStopping, + status: string(types.StackSetOperationStatusStopping), wanted: true, }, "false when succeeded": { - status: cloudformation.StackSetOperationStatusSucceeded, + status: string(types.StackSetOperationStatusSucceeded), }, "false when stopped": { - status: cloudformation.StackSetOperationStatusStopped, + status: string(types.StackSetOperationStatusStopped), }, "false when failed": { - status: cloudformation.StackSetOperationStatusFailed, + status: string(types.StackSetOperationStatusFailed), }, } @@ -119,23 +119,23 @@ func TestOpStatus_IsFailure(t *testing.T) { wanted bool }{ "false when queued": { - status: cloudformation.StackSetOperationStatusQueued, + status: string(types.StackSetOperationStatusQueued), }, "false when running": { - status: cloudformation.StackSetOperationStatusRunning, + status: string(types.StackSetOperationStatusRunning), }, "false when stopping": { - status: cloudformation.StackSetOperationStatusStopping, + status: string(types.StackSetOperationStatusStopping), }, "false when succeeded": { - status: cloudformation.StackSetOperationStatusSucceeded, + status: string(types.StackSetOperationStatusSucceeded), }, "true when stopped": { - status: cloudformation.StackSetOperationStatusStopped, + status: string(types.StackSetOperationStatusStopped), wanted: true, }, "true when failed": { - status: cloudformation.StackSetOperationStatusFailed, + status: string(types.StackSetOperationStatusFailed), wanted: true, }, } @@ -158,25 +158,25 @@ func TestInstanceStatus_IsCompleted(t *testing.T) { wanted bool }{ "false when pending": { - status: cloudformation.StackInstanceDetailedStatusPending, + status: string(types.StackInstanceDetailedStatusPending), }, "false when running": { - status: cloudformation.StackInstanceDetailedStatusRunning, + status: string(types.StackInstanceDetailedStatusRunning), }, "true when succeeded": { - status: cloudformation.StackInstanceDetailedStatusSucceeded, + status: string(types.StackInstanceDetailedStatusSucceeded), wanted: true, }, "true when failed": { - status: cloudformation.StackInstanceDetailedStatusFailed, + status: string(types.StackInstanceDetailedStatusFailed), wanted: true, }, "true when cancelled": { - status: cloudformation.StackInstanceDetailedStatusCancelled, + status: string(types.StackInstanceDetailedStatusCancelled), wanted: true, }, "true when inoperable": { - status: cloudformation.StackInstanceDetailedStatusInoperable, + status: string(types.StackInstanceDetailedStatusInoperable), wanted: true, }, } @@ -194,24 +194,24 @@ func TestInstanceStatus_InProgress(t *testing.T) { wanted bool }{ "true when pending": { - status: cloudformation.StackInstanceDetailedStatusPending, + status: string(types.StackInstanceDetailedStatusPending), wanted: true, }, "true when running": { - status: cloudformation.StackInstanceDetailedStatusRunning, + status: string(types.StackInstanceDetailedStatusRunning), wanted: true, }, "false when succeeded": { - status: cloudformation.StackInstanceDetailedStatusSucceeded, + status: string(types.StackInstanceDetailedStatusSucceeded), }, "false when failed": { - status: cloudformation.StackInstanceDetailedStatusFailed, + status: string(types.StackInstanceDetailedStatusFailed), }, "false when cancelled": { - status: cloudformation.StackInstanceDetailedStatusCancelled, + status: string(types.StackInstanceDetailedStatusCancelled), }, "false when inoperable": { - status: cloudformation.StackInstanceDetailedStatusInoperable, + status: string(types.StackInstanceDetailedStatusInoperable), }, } @@ -228,23 +228,23 @@ func TestInstanceStatus_IsSuccess(t *testing.T) { wanted bool }{ "false when pending": { - status: cloudformation.StackInstanceDetailedStatusPending, + status: string(types.StackInstanceDetailedStatusPending), }, "false when running": { - status: cloudformation.StackInstanceDetailedStatusRunning, + status: string(types.StackInstanceDetailedStatusRunning), }, "true when succeeded": { - status: cloudformation.StackInstanceDetailedStatusSucceeded, + status: string(types.StackInstanceDetailedStatusSucceeded), wanted: true, }, "false when failed": { - status: cloudformation.StackInstanceDetailedStatusFailed, + status: string(types.StackInstanceDetailedStatusFailed), }, "false when cancelled": { - status: cloudformation.StackInstanceDetailedStatusCancelled, + status: string(types.StackInstanceDetailedStatusCancelled), }, "false when inoperable": { - status: cloudformation.StackInstanceDetailedStatusInoperable, + status: string(types.StackInstanceDetailedStatusInoperable), }, } @@ -261,24 +261,24 @@ func TestInstanceStatus_IsFailure(t *testing.T) { wanted bool }{ "false when pending": { - status: cloudformation.StackInstanceDetailedStatusPending, + status: string(types.StackInstanceDetailedStatusPending), }, "false when running": { - status: cloudformation.StackInstanceDetailedStatusRunning, + status: string(types.StackInstanceDetailedStatusRunning), }, "false when succeeded": { - status: cloudformation.StackInstanceDetailedStatusSucceeded, + status: string(types.StackInstanceDetailedStatusSucceeded), }, "true when failed": { - status: cloudformation.StackInstanceDetailedStatusFailed, + status: string(types.StackInstanceDetailedStatusFailed), wanted: true, }, "true when cancelled": { - status: cloudformation.StackInstanceDetailedStatusCancelled, + status: string(types.StackInstanceDetailedStatusCancelled), wanted: true, }, "true when inoperable": { - status: cloudformation.StackInstanceDetailedStatusInoperable, + status: string(types.StackInstanceDetailedStatusInoperable), wanted: true, }, } diff --git a/internal/pkg/aws/cloudformation/stackstatus.go b/internal/pkg/aws/cloudformation/stackstatus.go index b93e9474fdc..a5ab94953e2 100644 --- a/internal/pkg/aws/cloudformation/stackstatus.go +++ b/internal/pkg/aws/cloudformation/stackstatus.go @@ -6,31 +6,31 @@ package cloudformation import ( "strings" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) var ( successStackStatuses = []string{ - cloudformation.StackStatusCreateComplete, - cloudformation.StackStatusDeleteComplete, - cloudformation.StackStatusUpdateComplete, - cloudformation.StackStatusUpdateCompleteCleanupInProgress, - cloudformation.StackStatusImportComplete, + string(types.StackStatusCreateComplete), + string(types.StackStatusDeleteComplete), + string(types.StackStatusUpdateComplete), + string(types.StackStatusUpdateCompleteCleanupInProgress), + string(types.StackStatusImportComplete), } failureStackStatuses = []string{ - cloudformation.StackStatusCreateFailed, - cloudformation.StackStatusDeleteFailed, - cloudformation.ResourceStatusUpdateFailed, - cloudformation.StackStatusRollbackInProgress, - cloudformation.StackStatusRollbackComplete, - cloudformation.StackStatusRollbackFailed, - cloudformation.StackStatusUpdateRollbackComplete, - cloudformation.StackStatusUpdateRollbackCompleteCleanupInProgress, - cloudformation.StackStatusUpdateRollbackInProgress, - cloudformation.StackStatusUpdateRollbackFailed, - cloudformation.ResourceStatusImportRollbackInProgress, - cloudformation.ResourceStatusImportRollbackFailed, + string(types.StackStatusCreateFailed), + string(types.StackStatusDeleteFailed), + string(types.ResourceStatusUpdateFailed), + string(types.StackStatusRollbackInProgress), + string(types.StackStatusRollbackComplete), + string(types.StackStatusRollbackFailed), + string(types.StackStatusUpdateRollbackComplete), + string(types.StackStatusUpdateRollbackCompleteCleanupInProgress), + string(types.StackStatusUpdateRollbackInProgress), + string(types.StackStatusUpdateRollbackFailed), + string(types.ResourceStatusImportRollbackInProgress), + string(types.ResourceStatusImportRollbackFailed), } ) @@ -39,7 +39,7 @@ type StackStatus string // requiresCleanup returns true if the stack was created, but failed and should be deleted. func (ss StackStatus) requiresCleanup() bool { - return cloudformation.StackStatusRollbackComplete == string(ss) || cloudformation.StackStatusRollbackFailed == string(ss) + return string(types.StackStatusRollbackComplete) == string(ss) || string(types.StackStatusRollbackFailed) == string(ss) } // InProgress returns true if the stack is currently being updated. @@ -49,7 +49,7 @@ func (ss StackStatus) InProgress() bool { // UpsertInProgress returns true if the resource is updating or being created. func (ss StackStatus) UpsertInProgress() bool { - return ss == cloudformation.StackStatusCreateInProgress || ss == cloudformation.StackStatusUpdateInProgress + return ss == StackStatus(types.StackStatusCreateInProgress) || ss == StackStatus(types.StackStatusUpdateInProgress) } // IsSuccess returns true if the resource mutated successfully. diff --git a/internal/pkg/aws/cloudformation/stackstatus_test.go b/internal/pkg/aws/cloudformation/stackstatus_test.go index e929509d532..0a835f943d3 100644 --- a/internal/pkg/aws/cloudformation/stackstatus_test.go +++ b/internal/pkg/aws/cloudformation/stackstatus_test.go @@ -6,7 +6,7 @@ package cloudformation import ( "testing" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/stretchr/testify/require" ) @@ -17,23 +17,23 @@ func TestStackStatus_InProgress(t *testing.T) { wanted bool }{ "should be false if stack is created Successfully": { - status: cloudformation.StackStatusCreateComplete, + status: string(types.StackStatusCreateComplete), wanted: false, }, "should be false if stack creation failed": { - status: cloudformation.StackStatusCreateFailed, + status: string(types.StackStatusCreateFailed), wanted: false, }, "should be true if stack creation is in progress": { - status: cloudformation.StackStatusCreateInProgress, + status: string(types.StackStatusCreateInProgress), wanted: true, }, "should be true if stack update is in progress": { - status: cloudformation.StackStatusUpdateInProgress, + status: string(types.StackStatusUpdateInProgress), wanted: true, }, "should be true if stack deletion is in progress": { - status: cloudformation.StackStatusDeleteInProgress, + status: string(types.StackStatusDeleteInProgress), wanted: true, }, } @@ -53,15 +53,15 @@ func TestStackStatus_UpsertInProgress(t *testing.T) { wanted bool }{ "should be true for update in progress": { - status: cloudformation.StackStatusUpdateInProgress, + status: string(types.StackStatusUpdateInProgress), wanted: true, }, "should be true for create in progress": { - status: cloudformation.StackStatusCreateInProgress, + status: string(types.StackStatusCreateInProgress), wanted: true, }, "should be false if created": { - status: cloudformation.StackStatusCreateComplete, + status: string(types.StackStatusCreateComplete), wanted: false, }, } diff --git a/internal/pkg/cli/app_delete.go b/internal/pkg/cli/app_delete.go index 5589889c41a..04bcb8feae2 100644 --- a/internal/pkg/cli/app_delete.go +++ b/internal/pkg/cli/app_delete.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -19,7 +20,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -60,7 +61,7 @@ type deleteAppOpts struct { prompt prompter pipelineLister deployedPipelineLister sel appSelector - s3 func(session *session.Session) bucketEmptier + s3 func(aws.Config) bucketEmptier svcDeleteExecutor func(appName, svcName string) (executor, error) jobDeleteExecutor func(appName, jobName string) (executor, error) envDeleteExecutor func(appName, envName string) (executeAsker, error) @@ -85,10 +86,10 @@ func newDeleteAppOpts(vars deleteAppVars) (*deleteAppOpts, error) { spinner: termprogress.NewSpinner(log.DiagnosticWriter), store: store, sessProvider: provider, - cfn: cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)), + cfn: cloudformation.New(v2ConfigFromSessionRegion(defaultSession), cloudformation.WithProgressTracker(os.Stderr)), prompt: prompter, - s3: func(session *session.Session) bucketEmptier { - return s3.New(v2ConfigFromSessionRegion(session)) + s3: func(cfg aws.Config) bucketEmptier { + return s3.New(cfg) }, pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), sel: selector.NewAppEnvSelector(prompter, store), @@ -321,13 +322,13 @@ func (o *deleteAppOpts) emptyS3Bucket() error { } o.spinner.Start(deleteAppCleanResourcesStartMsg) for _, resource := range appResources { - sess, err := o.sessProvider.DefaultWithRegion(resource.Region) + cfg, err := o.sessProvider.DefaultConfigWithRegion(context.Background(), resource.Region) if err != nil { - return fmt.Errorf("default session with region %s: %w", resource.Region, err) + return fmt.Errorf("default config with region %s: %w", resource.Region, err) } // Empty pipeline buckets. - s3Client := o.s3(sess) + s3Client := o.s3(cfg) if err := s3Client.EmptyBucket(resource.S3Bucket); err != nil { o.spinner.Stop(log.Serrorln("Error cleaning up deployment resources.")) return fmt.Errorf("empty bucket %s: %w", resource.S3Bucket, err) diff --git a/internal/pkg/cli/app_delete_test.go b/internal/pkg/cli/app_delete_test.go index 51ce31ffe5b..08e90b72b3c 100644 --- a/internal/pkg/cli/app_delete_test.go +++ b/internal/pkg/cli/app_delete_test.go @@ -15,7 +15,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -295,7 +295,7 @@ func TestDeleteAppOpts_Execute(t *testing.T) { mockPipelineLister := mocks.NewMockdeployedPipelineLister(ctrl) mockBucketEmptier := mocks.NewMockbucketEmptier(ctrl) - mockGetBucketEmptier := func(session *session.Session) bucketEmptier { + mockGetBucketEmptier := func(aws.Config) bucketEmptier { return mockBucketEmptier } diff --git a/internal/pkg/cli/app_init.go b/internal/pkg/cli/app_init.go index 98e8cdbf9fa..931bf9275b4 100644 --- a/internal/pkg/cli/app_init.go +++ b/internal/pkg/cli/app_init.go @@ -13,9 +13,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/spf13/afero" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/spf13/cobra" @@ -78,9 +77,9 @@ func newInitAppOpts(vars initAppVars) (*initAppOpts, error) { return &initAppOpts{ initAppVars: vars, identity: identity, - store: config.NewSSMStore(identity, ssm.New(sess), aws.StringValue(sess.Config.Region)), + store: config.NewSSMStore(identity, config.NewSSMClient(cfg), aws.ToString(sess.Config.Region)), route53: route53.New(v2ConfigFromSessionRegion(sess)), - cfn: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), + cfn: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), prompt: prompt.New(), prog: termprogress.NewSpinner(log.DiagnosticWriter), iam: iamClient, diff --git a/internal/pkg/cli/app_upgrade.go b/internal/pkg/cli/app_upgrade.go index c27b5029c11..e300327b379 100644 --- a/internal/pkg/cli/app_upgrade.go +++ b/internal/pkg/cli/app_upgrade.go @@ -69,7 +69,7 @@ func newAppUpgradeOpts(vars appUpgradeVars) (*appUpgradeOpts, error) { identity: identity.New(cfg), route53: route53.New(v2ConfigFromSessionRegion(sess)), sel: selector.NewAppEnvSelector(prompt.New(), store), - upgrader: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), + upgrader: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), newVersionGetter: func(appName string) (versionGetter, error) { d, err := describe.NewAppDescriber(appName) if err != nil { diff --git a/internal/pkg/cli/cli.go b/internal/pkg/cli/cli.go index 3ac4a256c4b..5d21397bcf7 100644 --- a/internal/pkg/cli/cli.go +++ b/internal/pkg/cli/cli.go @@ -18,7 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/smithy-go" "github.com/spf13/cobra" ) @@ -78,14 +78,14 @@ func isStackSetNotExistsErr(err error) bool { if err == nil { return false } - aerr, ok := err.(awserr.Error) - if !ok { + var apiErr smithy.APIError + if !errors.As(err, &apiErr) { return isStackSetNotExistsErr(errors.Unwrap(err)) } - if aerr.Code() != "StackSetNotFoundException" { - return isStackSetNotExistsErr(errors.Unwrap(err)) + if apiErr.ErrorCode() == "StackSetNotFoundException" { + return true } - return true + return isStackSetNotExistsErr(errors.Unwrap(err)) } func run(cmd cmd) error { diff --git a/internal/pkg/cli/config_store.go b/internal/pkg/cli/config_store.go index 2e8af899c92..50543430727 100644 --- a/internal/pkg/cli/config_store.go +++ b/internal/pkg/cli/config_store.go @@ -2,26 +2,23 @@ package cli import ( "context" - "fmt" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" - awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" ) func newSSMConfigStore(sess *session.Session) (*config.Store, error) { - cfg, err := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) - if err != nil { - return nil, fmt.Errorf("create default config: %w", err) - } - return config.NewSSMStore(identity.New(cfg), ssm.New(sess), aws.StringValue(sess.Config.Region)), nil + return newSSMConfigStoreFromConfig(v2ConfigFromSessionRegion(sess)), nil } -func v2ConfigFromSessionRegion(sess *session.Session) awsv2.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) +func newSSMConfigStoreFromConfig(cfg aws.Config) *config.Store { + return config.NewSSMStore(identity.New(cfg), config.NewSSMClient(cfg), cfg.Region) +} + +func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(sess.Config.Region)) return cfg } diff --git a/internal/pkg/cli/deploy.go b/internal/pkg/cli/deploy.go index a08997f8c90..728ce741398 100644 --- a/internal/pkg/cli/deploy.go +++ b/internal/pkg/cli/deploy.go @@ -14,7 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/queue" "github.com/dustin/go-humanize" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/dustin/go-humanize/english" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -137,7 +137,7 @@ func newDeployOpts(vars deployVars) (*deployOpts, error) { newWorkloadAdder: func() wkldInitializerWithoutManifest { return &initialize.WorkloadInitializer{ Store: store, - Deployer: cloudformation.New(defaultSess), + Deployer: cloudformation.New(v2ConfigFromSessionRegion(defaultSess)), Ws: ws, Prog: termprogress.NewSpinner(log.DiagnosticWriter), } @@ -683,7 +683,7 @@ func (o *deployOpts) maybeInitEnv() error { o.yesInitEnv = aws.Bool(v) } - if aws.BoolValue(o.yesInitEnv) { + if aws.ToBool(o.yesInitEnv) { cmd, err := o.newInitEnvCmd(o) if err != nil { return fmt.Errorf("load env init command : %w", err) @@ -700,7 +700,7 @@ func (o *deployOpts) maybeInitEnv() error { if o.deployEnv == nil { log.Infof("Environment %q was just initialized. We'll deploy it now.\n", o.envName) o.deployEnv = aws.Bool(true) - } else if !aws.BoolValue(o.deployEnv) { + } else if !aws.ToBool(o.deployEnv) { log.Errorf("Environment is not deployed but --%s=false was specified. Deploy the environment with %s in order to deploy a workload to it.\n", deployEnvFlag, color.HighlightCode("copilot env deploy")) return fmt.Errorf("environment %s was initialized but has not been deployed", o.envName) } @@ -715,7 +715,7 @@ func (o *deployOpts) maybeDeployEnv() error { return nil } - if aws.BoolValue(o.deployEnv) { + if aws.ToBool(o.deployEnv) { cmd, err := o.newDeployEnvCmd(o) if err != nil { return fmt.Errorf("set up env deploy command: %w", err) diff --git a/internal/pkg/cli/deploy/aws_config.go b/internal/pkg/cli/deploy/aws_config.go deleted file mode 100644 index 0a06a56e74b..00000000000 --- a/internal/pkg/cli/deploy/aws_config.go +++ /dev/null @@ -1,15 +0,0 @@ -package deploy - -import ( - "context" - - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go-v2/aws" - awsv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" -) - -func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), awsv1.StringValue(sess.Config.Region)) - return cfg -} diff --git a/internal/pkg/cli/deploy/backend.go b/internal/pkg/cli/deploy/backend.go index 844bb8c793b..173c182cee6 100644 --- a/internal/pkg/cli/deploy/backend.go +++ b/internal/pkg/cli/deploy/backend.go @@ -5,8 +5,9 @@ package deploy import ( "fmt" + "github.com/aproint/copilot-cli/internal/pkg/aws/elbv2" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/aws/acm" awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -18,7 +19,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws/session" ) type backendSvcDeployer struct { @@ -44,9 +44,9 @@ func NewBackendDeployer(in *WorkloadDeployerInput) (*backendSvcDeployer, error) } return &backendSvcDeployer{ svcDeployer: svcDeployer, - elbGetter: elbv2.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), + elbGetter: elbv2.New(svcDeployer.envAWSConfig), backendMft: bsMft, - aliasCertValidator: acm.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), + aliasCertValidator: acm.New(svcDeployer.envAWSConfig), }, nil } @@ -100,7 +100,7 @@ func (d *backendSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) ( } var opts []stack.BackendServiceOption if d.backendMft.HTTP.ImportedALB != nil { - lb, err := d.elbGetter.LoadBalancer(aws.StringValue(d.backendMft.HTTP.ImportedALB)) + lb, err := d.elbGetter.LoadBalancer(aws.ToString(d.backendMft.HTTP.ImportedALB)) if err != nil { return nil, err } @@ -129,8 +129,8 @@ func (d *backendSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) ( return &svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), - svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return ecs.New(s, v2ConfigFromSessionRegion(s)) + svcUpdater: d.newSvcUpdater(func(cfg aws.Config) serviceForceUpdater { + return ecs.New(cfg) }), }, nil } @@ -157,12 +157,12 @@ func (d *backendSvcDeployer) validateImportedALBConfig() error { if d.backendMft.HTTP.ImportedALB == nil { return nil } - alb, err := d.elbGetter.LoadBalancer(aws.StringValue(d.backendMft.HTTP.ImportedALB)) + alb, err := d.elbGetter.LoadBalancer(aws.ToString(d.backendMft.HTTP.ImportedALB)) if err != nil { - return fmt.Errorf(`retrieve load balancer %q: %w`, aws.StringValue(d.backendMft.HTTP.ImportedALB), err) + return fmt.Errorf(`retrieve load balancer %q: %w`, aws.ToString(d.backendMft.HTTP.ImportedALB), err) } if alb.Scheme != "internal" { - return fmt.Errorf(`imported ALB %q for Backend Service %q should have "internal" Scheme value`, alb.ARN, aws.StringValue(d.backendMft.Name)) + return fmt.Errorf(`imported ALB %q for Backend Service %q should have "internal" Scheme value`, alb.ARN, aws.ToString(d.backendMft.Name)) } if len(alb.Listeners) == 0 { return fmt.Errorf(`imported ALB %q must have at least one listener. For two listeners, one must be of protocol HTTP and the other of protocol HTTPS`, alb.ARN) diff --git a/internal/pkg/cli/deploy/backend_test.go b/internal/pkg/cli/deploy/backend_test.go index 8261af28d36..504d8a1d164 100644 --- a/internal/pkg/cli/deploy/backend_test.go +++ b/internal/pkg/cli/deploy/backend_test.go @@ -19,8 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/cli/deploy/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -510,7 +509,7 @@ func TestBackendSvcDeployer_stackConfiguration(t *testing.T) { envConfig: tc.inEnvironmentConfig(), envVersionGetter: m.mockEnvVersionGetter, }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, }, @@ -550,7 +549,7 @@ func mockBackendServiceDeployer(opts ...func(*backendSvcDeployer)) *backendSvcDe envVersionGetter: &mockEnvVersionGetter{version: "v1.0.0"}, overrider: new(override.Noop), }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, now: func() time.Time { diff --git a/internal/pkg/cli/deploy/env.go b/internal/pkg/cli/deploy/env.go index 3852983e8db..81a07133638 100644 --- a/internal/pkg/cli/deploy/env.go +++ b/internal/pkg/cli/deploy/env.go @@ -36,7 +36,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template/diff" "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" - awscfn "github.com/aws/aws-sdk-go/service/cloudformation" + awscfn "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/spf13/afero" "golang.org/x/sync/errgroup" ) @@ -53,7 +53,7 @@ type appResourcesGetter interface { type environmentDeployer interface { UpdateAndRenderEnvironment(conf deploycfn.StackConfiguration, bucketARN string, detach bool, opts ...cloudformation.StackOption) error - DeployedEnvironmentParameters(app, env string) ([]*awscfn.Parameter, error) + DeployedEnvironmentParameters(app, env string) ([]awscfn.Parameter, error) ForceUpdateOutputID(app, env string) (string, error) } @@ -92,7 +92,7 @@ type envDeployer struct { envDeployer environmentDeployer tmplGetter deployedTemplateGetter patcher patcher - newStack func(input *cfnstack.EnvConfig, forceUpdateID string, prevParams []*awscfn.Parameter) (deploycfn.StackConfiguration, error) + newStack func(input *cfnstack.EnvConfig, forceUpdateID string, prevParams []awscfn.Parameter) (deploycfn.StackConfiguration, error) envDescriber envDescriber lbDescriber lbDescriber newServiceStackDescriber func(string) stackDescriber @@ -117,17 +117,17 @@ type NewEnvDeployerInput struct { // NewEnvDeployer constructs an environment deployer. func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { - defaultSession, err := in.SessionProvider.Default() + defaultConfig, err := in.SessionProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("get default session: %w", err) + return nil, fmt.Errorf("get default config: %w", err) } - envRegionSession, err := in.SessionProvider.DefaultWithRegion(in.Env.Region) + envRegionConfig, err := in.SessionProvider.DefaultConfigWithRegion(context.Background(), in.Env.Region) if err != nil { - return nil, fmt.Errorf("get default session in env region %s: %w", in.Env.Region, err) + return nil, fmt.Errorf("get default config in env region %s: %w", in.Env.Region, err) } - envManagerSession, err := in.SessionProvider.FromRole(in.Env.ManagerRoleARN, in.Env.Region) + envManagerConfig, err := in.SessionProvider.ConfigFromRole(context.Background(), in.Env.ManagerRoleARN, in.Env.Region) if err != nil { - return nil, fmt.Errorf("get env session: %w", err) + return nil, fmt.Errorf("get env config: %w", err) } envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ App: in.App.Name, @@ -141,16 +141,16 @@ func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { if overrider == nil { overrider = new(override.Noop) } - cfnClient := deploycfn.New(envManagerSession, deploycfn.WithProgressTracker(os.Stderr)) + cfnClient := deploycfn.New(envManagerConfig, deploycfn.WithProgressTracker(os.Stderr)) deployer := &envDeployer{ app: in.App, env: in.Env, templateFS: template.New(), - s3: awss3.New(v2ConfigFromSessionRegion(envManagerSession)), - prefixListGetter: ec2.New(v2ConfigFromSessionRegion(envRegionSession)), + s3: awss3.New(envManagerConfig), + prefixListGetter: ec2.New(envRegionConfig), - appCFN: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), + appCFN: deploycfn.New(defaultConfig, deploycfn.WithProgressTracker(os.Stderr)), envDeployer: cfnClient, tmplGetter: cfnClient, patcher: &patch.EnvironmentPatcher{ @@ -158,17 +158,17 @@ func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { TemplatePatcher: cfnClient, Env: in.Env, }, - newStack: func(in *cfnstack.EnvConfig, lastForceUpdateID string, oldParams []*awscfn.Parameter) (deploycfn.StackConfiguration, error) { - stack, err := cfnstack.NewEnvConfigFromExistingStack(in, lastForceUpdateID, oldParams) + newStack: func(in *cfnstack.EnvConfig, lastForceUpdateID string, oldParams []awscfn.Parameter) (deploycfn.StackConfiguration, error) { + stack, err := cfnstack.NewEnvConfigFromExistingStack(in, lastForceUpdateID, parameterPtrs(oldParams)) if err != nil { return nil, err } return deploycfn.WrapWithTemplateOverrider(stack, overrider), nil }, envDescriber: envDescriber, - lbDescriber: elbv2.New(v2ConfigFromSessionRegion(envManagerSession)), + lbDescriber: elbv2.New(envManagerConfig), newServiceStackDescriber: func(svc string) stackDescriber { - return stack.NewStackDescriber(cfnstack.NameForWorkload(in.App.Name, in.Env.Name, svc), envManagerSession) + return stack.NewStackDescriber(cfnstack.NameForWorkload(in.App.Name, in.Env.Name, svc), envManagerConfig) }, parseAddons: sync.OnceValues(func() (stackBuilder, error) { return addon.ParseFromEnv(in.Workspace) @@ -178,6 +178,14 @@ func NewEnvDeployer(in *NewEnvDeployerInput) (*envDeployer, error) { return deployer, nil } +func parameterPtrs(params []awscfn.Parameter) []*awscfn.Parameter { + out := make([]*awscfn.Parameter, 0, len(params)) + for i := range params { + out = append(out, ¶ms[i]) + } + return out +} + // Validate returns an error if the environment manifest is incompatible with services and application configurations. func (d *envDeployer) Validate(mft *manifest.Environment) error { return d.validateCDN(mft) diff --git a/internal/pkg/cli/deploy/env_test.go b/internal/pkg/cli/deploy/env_test.go index fca61746553..4850f0d0200 100644 --- a/internal/pkg/cli/deploy/env_test.go +++ b/internal/pkg/cli/deploy/env_test.go @@ -25,9 +25,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template/artifactpath" "github.com/aproint/copilot-cli/internal/pkg/term/log" + "github.com/aws/aws-sdk-go-v2/aws" + awscfn "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" awselb "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/aws/aws-sdk-go/aws" - awscfn "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -545,7 +545,7 @@ func TestEnvDeployer_GenerateCloudFormationTemplate(t *testing.T) { }, appCFN: m.appCFN, envDeployer: m.envDeployer, - newStack: func(_ *cfnstack.EnvConfig, _ string, _ []*awscfn.Parameter) (cloudformation.StackConfiguration, error) { + newStack: func(_ *cfnstack.EnvConfig, _ string, _ []awscfn.Parameter) (cloudformation.StackConfiguration, error) { return m.stackSerializer, nil }, parseAddons: m.parseAddons, @@ -707,7 +707,7 @@ func TestEnvDeployer_DeployEnvironment(t *testing.T) { envDeployer: m.envDeployer, prefixListGetter: m.prefixListGetter, parseAddons: m.parseAddons, - newStack: func(_ *cfnstack.EnvConfig, _ string, _ []*awscfn.Parameter) (cloudformation.StackConfiguration, error) { + newStack: func(_ *cfnstack.EnvConfig, _ string, _ []awscfn.Parameter) (cloudformation.StackConfiguration, error) { return m.stackSerializer, nil }, } @@ -1038,7 +1038,7 @@ If you'd like to use these services without a CDN, ensure each service's A recor d := &envDeployer{ app: tc.app, env: &config.Environment{ - Name: aws.StringValue(tc.mft.Name), + Name: aws.ToString(tc.mft.Name), }, envDescriber: m.envDescriber, lbDescriber: m.lbDescriber, diff --git a/internal/pkg/cli/deploy/job_test.go b/internal/pkg/cli/deploy/job_test.go index c084d4aee26..3bfeba03287 100644 --- a/internal/pkg/cli/deploy/job_test.go +++ b/internal/pkg/cli/deploy/job_test.go @@ -16,7 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/override" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) func TestJobDeployer_GenerateCloudFormationTemplate(t *testing.T) { diff --git a/internal/pkg/cli/deploy/lbws.go b/internal/pkg/cli/deploy/lbws.go index 22e852673d7..3c0077f52b2 100644 --- a/internal/pkg/cli/deploy/lbws.go +++ b/internal/pkg/cli/deploy/lbws.go @@ -24,8 +24,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) var ( @@ -80,13 +79,14 @@ func NewLBWSDeployer(in *WorkloadDeployerInput) (*lbWebSvcDeployer, error) { return &lbWebSvcDeployer{ svcDeployer: svcDeployer, appVersionGetter: versionGetter, - elbGetter: elbv2.New(v2ConfigFromSessionRegion(svcDeployer.envSess)), + elbGetter: elbv2.New(svcDeployer.envAWSConfig), lbMft: lbMft, newAliasCertValidator: func(optionalRegion *string) aliasCertValidator { - sess := svcDeployer.envSess.Copy(&aws.Config{ - Region: optionalRegion, - }) - return acm.New(v2ConfigFromSessionRegion(sess)) + cfg := svcDeployer.envAWSConfig + if optionalRegion != nil { + cfg.Region = aws.ToString(optionalRegion) + } + return acm.New(cfg) }, }, nil } @@ -144,7 +144,7 @@ func (d *lbWebSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) (*s } var opts []stack.LoadBalancedWebServiceOption if d.lbMft.HTTPOrBool.ImportedALB != nil { - lb, err := d.elbGetter.LoadBalancer(aws.StringValue(d.lbMft.HTTPOrBool.ImportedALB)) + lb, err := d.elbGetter.LoadBalancer(aws.ToString(d.lbMft.HTTPOrBool.ImportedALB)) if err != nil { return nil, err } @@ -174,8 +174,8 @@ func (d *lbWebSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) (*s return &svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), - svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return ecs.New(s, v2ConfigFromSessionRegion(s)) + svcUpdater: d.newSvcUpdater(func(cfg aws.Config) serviceForceUpdater { + return ecs.New(cfg) }), }, nil } @@ -205,9 +205,9 @@ func (d *lbWebSvcDeployer) validateImportedALBConfig() error { if d.lbMft.HTTPOrBool.ImportedALB == nil { return nil } - alb, err := d.elbGetter.LoadBalancer(aws.StringValue(d.lbMft.HTTPOrBool.ImportedALB)) + alb, err := d.elbGetter.LoadBalancer(aws.ToString(d.lbMft.HTTPOrBool.ImportedALB)) if err != nil { - return fmt.Errorf(`retrieve load balancer %q: %w`, aws.StringValue(d.lbMft.HTTPOrBool.ImportedALB), err) + return fmt.Errorf(`retrieve load balancer %q: %w`, aws.ToString(d.lbMft.HTTPOrBool.ImportedALB), err) } if len(alb.Listeners) == 0 || len(alb.Listeners) > 2 { return fmt.Errorf(`imported ALB %q must have either one or two listeners`, alb.ARN) @@ -277,7 +277,7 @@ func (d *lbWebSvcDeployer) validateRuntimeRoutingRule(rule manifest.RoutingRule) return nil } if d.app.Domain != "" { - err := validateMinAppVersion(d.app.Name, aws.StringValue(d.lbMft.Name), d.appVersionGetter, version.AppTemplateMinAlias) + err := validateMinAppVersion(d.app.Name, aws.ToString(d.lbMft.Name), d.appVersionGetter, version.AppTemplateMinAlias) if err != nil { return fmt.Errorf("alias not supported: %w", err) } @@ -303,7 +303,7 @@ func (d *lbWebSvcDeployer) validateNLBRuntime() error { log.Errorf(ecsNLBAliasUsedWithoutDomainFriendlyText) return fmt.Errorf("cannot specify nlb.alias when application is not associated with a domain") } - err := validateMinAppVersion(d.app.Name, aws.StringValue(d.lbMft.Name), d.appVersionGetter, version.AppTemplateMinAlias) + err := validateMinAppVersion(d.app.Name, aws.ToString(d.lbMft.Name), d.appVersionGetter, version.AppTemplateMinAlias) if err != nil { return fmt.Errorf("alias not supported: %w", err) } diff --git a/internal/pkg/cli/deploy/lbws_test.go b/internal/pkg/cli/deploy/lbws_test.go index 9c22d3340d6..8a188708897 100644 --- a/internal/pkg/cli/deploy/lbws_test.go +++ b/internal/pkg/cli/deploy/lbws_test.go @@ -21,8 +21,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) func TestLbWebSvcDeployer_GenerateCloudFormationTemplate(t *testing.T) { @@ -79,7 +78,7 @@ func mockLoadBalancedWebServiceDeployer(opts ...func(deployer *lbWebSvcDeployer) templateFS: template.New(), customResources: lbwsCustomResources, }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, now: func() time.Time { diff --git a/internal/pkg/cli/deploy/mocks/mock_env.go b/internal/pkg/cli/deploy/mocks/mock_env.go index f9b6ce710b5..a45e47ac925 100644 --- a/internal/pkg/cli/deploy/mocks/mock_env.go +++ b/internal/pkg/cli/deploy/mocks/mock_env.go @@ -14,7 +14,7 @@ import ( cloudformation0 "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" stack "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" stack0 "github.com/aproint/copilot-cli/internal/pkg/describe/stack" - cloudformation1 "github.com/aws/aws-sdk-go/service/cloudformation" + types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" gomock "github.com/golang/mock/gomock" ) @@ -203,10 +203,10 @@ func (m *MockenvironmentDeployer) EXPECT() *MockenvironmentDeployerMockRecorder } // DeployedEnvironmentParameters mocks base method. -func (m *MockenvironmentDeployer) DeployedEnvironmentParameters(app, env string) ([]*cloudformation1.Parameter, error) { +func (m *MockenvironmentDeployer) DeployedEnvironmentParameters(app, env string) ([]types.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeployedEnvironmentParameters", app, env) - ret0, _ := ret[0].([]*cloudformation1.Parameter) + ret0, _ := ret[0].([]types.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/internal/pkg/cli/deploy/patch/env.go b/internal/pkg/cli/deploy/patch/env.go index c5968df17a4..1692725b721 100644 --- a/internal/pkg/cli/deploy/patch/env.go +++ b/internal/pkg/cli/deploy/patch/env.go @@ -14,11 +14,12 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/endpoints" "golang.org/x/mod/semver" "gopkg.in/yaml.v3" ) +const awsPartitionID = "aws" + type environmentTemplateUpdateGetter interface { Template(stackName string) (string, error) UpdateEnvironmentTemplate(appName, envName, templateBody, cfnExecRoleARN string) error @@ -50,7 +51,7 @@ func (p *EnvironmentPatcher) EnsureManagerRoleIsAllowedToUpload(bucket string) e if ok { return nil } - return p.grantManagerRolePermissionToUpload(p.Env.App, p.Env.Name, p.Env.ExecutionRoleARN, body, s3.FormatARN(endpoints.AwsPartitionID, bucket)) + return p.grantManagerRolePermissionToUpload(p.Env.App, p.Env.Name, p.Env.ExecutionRoleARN, body, s3.FormatARN(awsPartitionID, bucket)) } func (p *EnvironmentPatcher) grantManagerRolePermissionToUpload(app, env, execRole, body, bucketARN string) error { diff --git a/internal/pkg/cli/deploy/rdws.go b/internal/pkg/cli/deploy/rdws.go index a86d3104b38..7f07c372dad 100644 --- a/internal/pkg/cli/deploy/rdws.go +++ b/internal/pkg/cli/deploy/rdws.go @@ -24,8 +24,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) var rdwsAliasUsedWithoutDomainFriendlyText = fmt.Sprintf("To use %s, your application must be associated with a domain: %s.\n", @@ -59,7 +58,7 @@ func NewRDWSDeployer(in *WorkloadDeployerInput) (*rdwsDeployer, error) { } return &rdwsDeployer{ svcDeployer: svcDeployer, - customResourceS3Client: s3.New(v2ConfigFromSessionRegion(svcDeployer.defaultSessWithEnvRegion)), + customResourceS3Client: s3.New(svcDeployer.defaultEnvRegionAWSConfig), appVersionGetter: versionGetter, rdwsMft: rdwsMft, }, nil @@ -165,25 +164,25 @@ func (d *rdwsDeployer) stackConfiguration(in *StackRuntimeConfiguration) (*rdwsS return &rdwsStackConfigurationOutput{ svcStackConfigurationOutput: svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), - svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return apprunner.New(s, v2ConfigFromSessionRegion(s)) + svcUpdater: d.newSvcUpdater(func(cfg aws.Config) serviceForceUpdater { + return apprunner.New(cfg) }), }, }, nil } if err = validateRDSvcAliasAndAppVersion(d.name, - aws.StringValue(d.rdwsMft.Alias), d.env.Name, d.app, d.appVersionGetter); err != nil { + aws.ToString(d.rdwsMft.Alias), d.env.Name, d.app, d.appVersionGetter); err != nil { return nil, err } return &rdwsStackConfigurationOutput{ svcStackConfigurationOutput: svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), - svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return apprunner.New(s, v2ConfigFromSessionRegion(s)) + svcUpdater: d.newSvcUpdater(func(cfg aws.Config) serviceForceUpdater { + return apprunner.New(cfg) }), }, - rdSvcAlias: aws.StringValue(d.rdwsMft.Alias), + rdSvcAlias: aws.ToString(d.rdwsMft.Alias), }, nil } diff --git a/internal/pkg/cli/deploy/rdws_test.go b/internal/pkg/cli/deploy/rdws_test.go index ac7868155ee..cdb7347c268 100644 --- a/internal/pkg/cli/deploy/rdws_test.go +++ b/internal/pkg/cli/deploy/rdws_test.go @@ -18,8 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -210,7 +209,7 @@ func TestSvcDeployOpts_rdWebServiceStackConfiguration(t *testing.T) { endpointGetter: m.mockEndpointGetter, envVersionGetter: m.mockEnvVersionGetter, }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, }, @@ -270,7 +269,7 @@ func mockRDWSDeployer(opts ...func(*rdwsDeployer)) *rdwsDeployer { envVersionGetter: &mockEnvVersionGetter{version: "v1.0.0"}, overrider: new(override.Noop), }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, now: func() time.Time { diff --git a/internal/pkg/cli/deploy/static_site_test.go b/internal/pkg/cli/deploy/static_site_test.go index df61e0150bd..2c71ff74cfc 100644 --- a/internal/pkg/cli/deploy/static_site_test.go +++ b/internal/pkg/cli/deploy/static_site_test.go @@ -15,8 +15,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/upload/customresource" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "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/types" "github.com/golang/mock/gomock" "github.com/spf13/afero" "github.com/stretchr/testify/require" @@ -472,8 +472,8 @@ func (o *mockOverrider) Override(body []byte) (out []byte, err error) { type mockStaticSite struct{} -func (s *mockStaticSite) Template() (string, error) { return "", nil } -func (s *mockStaticSite) StackName() string { return "" } -func (s *mockStaticSite) Parameters() ([]*cloudformation.Parameter, error) { return nil, nil } -func (s *mockStaticSite) Tags() []*cloudformation.Tag { return nil } -func (s *mockStaticSite) SerializedParameters() (string, error) { return "", nil } +func (s *mockStaticSite) Template() (string, error) { return "", nil } +func (s *mockStaticSite) StackName() string { return "" } +func (s *mockStaticSite) Parameters() ([]*types.Parameter, error) { return nil, nil } +func (s *mockStaticSite) Tags() []*types.Tag { return nil } +func (s *mockStaticSite) SerializedParameters() (string, error) { return "", nil } diff --git a/internal/pkg/cli/deploy/svc.go b/internal/pkg/cli/deploy/svc.go index 92fd55d7ddc..8d60da26431 100644 --- a/internal/pkg/cli/deploy/svc.go +++ b/internal/pkg/cli/deploy/svc.go @@ -11,7 +11,7 @@ import ( "regexp" "time" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "golang.org/x/mod/semver" awscloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" @@ -40,7 +40,7 @@ type aliasCertValidator interface { type svcDeployer struct { *workloadDeployer - newSvcUpdater func(func(*session.Session) serviceForceUpdater) serviceForceUpdater + newSvcUpdater func(func(aws.Config) serviceForceUpdater) serviceForceUpdater now func() time.Time } @@ -51,8 +51,8 @@ func newSvcDeployer(in *WorkloadDeployerInput) (*svcDeployer, error) { } return &svcDeployer{ workloadDeployer: wkldDeployer, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { - return f(wkldDeployer.envSess) + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { + return f(wkldDeployer.envAWSConfig) }, now: time.Now, }, nil diff --git a/internal/pkg/cli/deploy/worker.go b/internal/pkg/cli/deploy/worker.go index b856dd5c3fa..189559b15b5 100644 --- a/internal/pkg/cli/deploy/worker.go +++ b/internal/pkg/cli/deploy/worker.go @@ -19,9 +19,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/term/color" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" "golang.org/x/text/cases" "golang.org/x/text/language" ) @@ -144,8 +143,8 @@ func (d *workerSvcDeployOutput) buildWorkerQueueNames() string { if subscription.Queue.IsEmpty() { continue } - svc := template.StripNonAlphaNumFunc(aws.StringValue(subscription.Service)) - topic := template.StripNonAlphaNumFunc(aws.StringValue(subscription.Name)) + svc := template.StripNonAlphaNumFunc(aws.ToString(subscription.Service)) + topic := template.StripNonAlphaNumFunc(aws.ToString(subscription.Name)) queueNames = append(queueNames, fmt.Sprintf("%s%sEventsQueue", svc, cases.Title(language.English).String(topic))) } return strings.Join(queueNames, ", ") @@ -198,8 +197,8 @@ func (d *workerSvcDeployer) stackConfiguration(in *StackRuntimeConfiguration) (* return &workerSvcStackConfigurationOutput{ svcStackConfigurationOutput: svcStackConfigurationOutput{ conf: cloudformation.WrapWithTemplateOverrider(conf, d.overrider), - svcUpdater: d.newSvcUpdater(func(s *session.Session) serviceForceUpdater { - return ecs.New(s, v2ConfigFromSessionRegion(s)) + svcUpdater: d.newSvcUpdater(func(cfg aws.Config) serviceForceUpdater { + return ecs.New(cfg) }), }, subscriptions: subs, @@ -217,7 +216,7 @@ func validateTopicsExist(subscriptions []manifest.TopicSubscription, topicARNs [ } for _, ts := range subscriptions { - topicName := fmt.Sprintf(resourceNameFormat, app, env, aws.StringValue(ts.Service), aws.StringValue(ts.Name)) + topicName := fmt.Sprintf(resourceNameFormat, app, env, aws.ToString(ts.Service), aws.ToString(ts.Name)) if !slices.Contains(validTopicResources, topicName) { return fmt.Errorf(fmtErrTopicSubscriptionNotAllowed, topicName, env) } diff --git a/internal/pkg/cli/deploy/worker_test.go b/internal/pkg/cli/deploy/worker_test.go index b021a10c909..a8ccd8a45be 100644 --- a/internal/pkg/cli/deploy/worker_test.go +++ b/internal/pkg/cli/deploy/worker_test.go @@ -19,8 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -145,7 +144,7 @@ func TestSvcDeployOpts_stackConfiguration_worker(t *testing.T) { endpointGetter: m.mockEndpointGetter, envVersionGetter: m.mockEnvVersionGetter, }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, }, @@ -258,7 +257,7 @@ func mockWorkerServiceDeployer(opts ...func(*workerSvcDeployer)) *workerSvcDeplo envVersionGetter: &mockEnvVersionGetter{version: "v1.0.0"}, overrider: new(override.Noop), }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return nil }, now: func() time.Time { diff --git a/internal/pkg/cli/deploy/workload.go b/internal/pkg/cli/deploy/workload.go index a94f98c9686..47d18af0458 100644 --- a/internal/pkg/cli/deploy/workload.go +++ b/internal/pkg/cli/deploy/workload.go @@ -42,9 +42,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/syncbuffer" "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "golang.org/x/sync/errgroup" ) @@ -196,11 +194,11 @@ type workloadDeployer struct { labeledTermPrinter func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) LabeledTermPrinter // Cached variables. - defaultSess *session.Session - defaultSessWithEnvRegion *session.Session - envSess *session.Session - store *config.Store - envConfig *manifest.Environment + defaultAWSConfig aws.Config + defaultEnvRegionAWSConfig aws.Config + envAWSConfig aws.Config + store *config.Store + envConfig *manifest.Environment } // ImagePerContainer contains the contains name and its ImageURI @@ -254,23 +252,19 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { if err != nil { return nil, err } - defaultSession, err := in.SessionProvider.Default() - if err != nil { - return nil, fmt.Errorf("create default: %w", err) - } defaultConfig, err := in.SessionProvider.DefaultConfig(context.Background()) if err != nil { return nil, fmt.Errorf("create default config: %w", err) } - envSession, err := in.SessionProvider.FromRole(in.Env.ManagerRoleARN, in.Env.Region) + envAWSConfig, err := in.SessionProvider.ConfigFromRole(context.Background(), in.Env.ManagerRoleARN, in.Env.Region) if err != nil { - return nil, fmt.Errorf("create env session with region %s: %w", in.Env.Region, err) + return nil, fmt.Errorf("create env config with region %s: %w", in.Env.Region, err) } - defaultSessEnvRegion, err := in.SessionProvider.DefaultWithRegion(in.Env.Region) + defaultEnvRegionConfig, err := in.SessionProvider.DefaultConfigWithRegion(context.Background(), in.Env.Region) if err != nil { - return nil, fmt.Errorf("create default session with region %s: %w", in.Env.Region, err) + return nil, fmt.Errorf("create default config with region %s: %w", in.Env.Region, err) } - resources, err := cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(in.App, in.Env.Region) + resources, err := cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(in.App, in.Env.Region) if err != nil { return nil, fmt.Errorf("get application %s resources from region %s: %w", in.App.Name, in.Env.Region, err) } @@ -287,8 +281,8 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { repoName := RepoName(in.App.Name, in.Name) repository := repository.NewWithURI( - ecr.New(v2ConfigFromSessionRegion(defaultSessEnvRegion)), repoName, resources.RepositoryURLs[in.Name]) - store := config.NewSSMStore(identity.New(defaultConfig), ssm.New(defaultSession), aws.StringValue(defaultSession.Config.Region)) + ecr.New(defaultEnvRegionConfig), repoName, resources.RepositoryURLs[in.Name]) + store := config.NewSSMStore(identity.New(defaultConfig), config.NewSSMClient(defaultConfig), defaultConfig.Region) envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ App: in.App.Name, Env: in.Env.Name, @@ -307,38 +301,38 @@ func newWorkloadDeployer(in *WorkloadDeployerInput) (*workloadDeployer, error) { return nil, fmt.Errorf("unmarshal the manifest used to deploy environment %s: %w", in.Env.Name, err) } - cfn := cloudformation.New(envSession, cloudformation.WithProgressTracker(os.Stderr)) + cfn := cloudformation.New(envAWSConfig, cloudformation.WithProgressTracker(os.Stderr)) labeledTermPrinter := func(fw syncbuffer.FileWriter, bufs []*syncbuffer.LabeledSyncBuffer, opts ...syncbuffer.LabeledTermPrinterOption) LabeledTermPrinter { return syncbuffer.NewLabeledTermPrinter(fw, bufs, opts...) } docker := dockerengine.New(exec.NewCmd()) return &workloadDeployer{ - name: in.Name, - app: in.App, - env: in.Env, - image: in.Image, - resources: resources, - workspacePath: ws.Path(), - fs: afero.NewOsFs(), - s3Client: s3.New(v2ConfigFromSessionRegion(envSession)), - addons: addons, - repository: repository, - deployer: cfn, - tmplGetter: cfn, - endpointGetter: envDescriber, - spinner: termprogress.NewSpinner(log.DiagnosticWriter), - templateFS: template.New(), - envVersionGetter: in.EnvVersionGetter, - overrider: in.Overrider, - docker: docker, - customResources: in.customResources, - defaultSess: defaultSession, - defaultSessWithEnvRegion: defaultSessEnvRegion, - envSess: envSession, - store: store, - envConfig: envConfig, - labeledTermPrinter: labeledTermPrinter, + name: in.Name, + app: in.App, + env: in.Env, + image: in.Image, + resources: resources, + workspacePath: ws.Path(), + fs: afero.NewOsFs(), + s3Client: s3.New(envAWSConfig), + addons: addons, + repository: repository, + deployer: cfn, + tmplGetter: cfn, + endpointGetter: envDescriber, + spinner: termprogress.NewSpinner(log.DiagnosticWriter), + templateFS: template.New(), + envVersionGetter: in.EnvVersionGetter, + overrider: in.Overrider, + docker: docker, + customResources: in.customResources, + defaultAWSConfig: defaultConfig, + defaultEnvRegionAWSConfig: defaultEnvRegionConfig, + envAWSConfig: envAWSConfig, + store: store, + envConfig: envConfig, + labeledTermPrinter: labeledTermPrinter, mft: in.Mft, rawMft: in.RawMft, @@ -591,11 +585,11 @@ func buildArgsPerContainer(name, workspacePath string, img ContainerImageIdentif } labels[labelForContainerName] = container dArgs[container] = &dockerengine.BuildArguments{ - Dockerfile: aws.StringValue(buildArgs.Dockerfile), - Context: aws.StringValue(buildArgs.Context), + Dockerfile: aws.ToString(buildArgs.Dockerfile), + Context: aws.ToString(buildArgs.Context), Args: buildArgs.Args, CacheFrom: buildArgs.CacheFrom, - Target: aws.StringValue(buildArgs.Target), + Target: aws.ToString(buildArgs.Target), Platform: mf.ContainerPlatform(), Tags: tags, Labels: labels, diff --git a/internal/pkg/cli/deploy/workload_test.go b/internal/pkg/cli/deploy/workload_test.go index 58906cecd27..ce1263f3a65 100644 --- a/internal/pkg/cli/deploy/workload_test.go +++ b/internal/pkg/cli/deploy/workload_test.go @@ -31,9 +31,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/syncbuffer" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - sdkcfn "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + sdkcfn "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -1370,7 +1369,7 @@ func TestWorkloadDeployer_DeployWorkload(t *testing.T) { envVersionGetter: m.mockEnvVersionGetter, overrider: new(override.Noop), }, - newSvcUpdater: func(f func(*session.Session) serviceForceUpdater) serviceForceUpdater { + newSvcUpdater: func(f func(aws.Config) serviceForceUpdater) serviceForceUpdater { return m.mockServiceForceUpdater }, now: func() time.Time { diff --git a/internal/pkg/cli/deploy_test.go b/internal/pkg/cli/deploy_test.go index 4818b2c8d9e..dedf6456d7f 100644 --- a/internal/pkg/cli/deploy_test.go +++ b/internal/pkg/cli/deploy_test.go @@ -10,7 +10,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index 611e43f3901..c212b080b80 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -13,7 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" awscfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/iam" @@ -28,8 +29,9 @@ import ( termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types" "github.com/spf13/cobra" "gopkg.in/yaml.v3" ) @@ -63,6 +65,14 @@ type resourceGetter interface { GetResources(*resourcegroupstaggingapi.GetResourcesInput) (*resourcegroupstaggingapi.GetResourcesOutput, error) } +type resourceGroupsClient struct { + client *resourcegroupstaggingapi.Client +} + +func (c *resourceGroupsClient) GetResources(in *resourcegroupstaggingapi.GetResourcesInput) (*resourcegroupstaggingapi.GetResourcesOutput, error) { + return c.client.GetResources(context.Background(), in) +} + type deleteEnvVars struct { appName string name string @@ -123,12 +133,12 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { if err != nil { return fmt.Errorf("create session from environment manager role %s in region %s: %w", env.ManagerRoleARN, env.Region, err) } - o.rg = resourcegroupstaggingapi.New(sess) + o.rg = &resourceGroupsClient{client: resourcegroupstaggingapi.NewFromConfig(v2ConfigFromSessionRegion(sess))} o.iam = iam.New(v2ConfigFromSessionRegion(sess)) o.s3 = s3.New(v2ConfigFromSessionRegion(sess)) - o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), sess) - o.deployer = cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) - o.envDeleterFromApp = cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) + o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), v2ConfigFromSessionRegion(sess)) + o.deployer = cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)) + o.envDeleterFromApp = cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)) defaultV2Config := v2ConfigFromSessionRegion(defaultSess) o.pipelineGetter = codepipeline.New(defaultV2Config, defaultV2Config) o.deployedPipelineLister = deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSess))) @@ -270,19 +280,19 @@ func (o *deleteEnvOpts) askEnvName() error { func (o *deleteEnvOpts) validateNoRunningServices() error { stacks, err := o.rg.GetResources(&resourcegroupstaggingapi.GetResourcesInput{ - ResourceTypeFilters: []*string{aws.String("cloudformation")}, - TagFilters: []*resourcegroupstaggingapi.TagFilter{ + ResourceTypeFilters: []string{"cloudformation"}, + TagFilters: []types.TagFilter{ { Key: aws.String(deploy.ServiceTagKey), - Values: []*string{}, // Matches any service stack. + Values: []string{}, // Matches any service stack. }, { Key: aws.String(deploy.EnvTagKey), - Values: []*string{aws.String(o.name)}, + Values: []string{o.name}, }, { Key: aws.String(deploy.AppTagKey), - Values: []*string{aws.String(o.appName)}, + Values: []string{o.appName}, }, }, }) @@ -293,10 +303,10 @@ func (o *deleteEnvOpts) validateNoRunningServices() error { var svcNames []string for _, cfnStack := range stacks.ResourceTagMappingList { for _, t := range cfnStack.Tags { - if *t.Key != deploy.ServiceTagKey { + if aws.ToString(t.Key) != deploy.ServiceTagKey { continue } - svcNames = append(svcNames, *t.Value) + svcNames = append(svcNames, aws.ToString(t.Value)) } } return fmt.Errorf("service %q still exist within the environment %s", strings.Join(svcNames, ", "), o.name) @@ -402,23 +412,23 @@ func (o *deleteEnvOpts) ensureRolesAreRetained() error { // emptyBuckets returns nil if buckets were deleted successfully. Otherwise, returns the error. func (o *deleteEnvOpts) emptyBuckets() error { s3buckets, err := o.rg.GetResources(&resourcegroupstaggingapi.GetResourcesInput{ - ResourceTypeFilters: aws.StringSlice([]string{"s3:bucket"}), - TagFilters: []*resourcegroupstaggingapi.TagFilter{ + ResourceTypeFilters: []string{"s3:bucket"}, + TagFilters: []types.TagFilter{ { Key: aws.String(stack.StackNameTagKey), - Values: []*string{aws.String(stack.NameForEnv(o.appName, o.name))}, + Values: []string{stack.NameForEnv(o.appName, o.name)}, }, { Key: aws.String(stack.LogicalIDTagKey), - Values: aws.StringSlice(stack.EnvManagedS3BucketLogicalIds), + Values: stack.EnvManagedS3BucketLogicalIds, }, { Key: aws.String(deploy.EnvTagKey), - Values: []*string{aws.String(o.name)}, + Values: []string{o.name}, }, { Key: aws.String(deploy.AppTagKey), - Values: []*string{aws.String(o.appName)}, + Values: []string{o.appName}, }, }, }) @@ -442,9 +452,9 @@ func (o *deleteEnvOpts) emptyBuckets() error { var failedBuckets []string var bucketErrors []error for _, resourceTagMapping := range s3buckets.ResourceTagMappingList { - bucketARN, err := arn.Parse(aws.StringValue(resourceTagMapping.ResourceARN)) + bucketARN, err := arn.Parse(aws.ToString(resourceTagMapping.ResourceARN)) if err != nil { - return fmt.Errorf("parse the arn %s: %w", aws.StringValue(resourceTagMapping.ResourceARN), err) + return fmt.Errorf("parse the arn %s: %w", aws.ToString(resourceTagMapping.ResourceARN), err) } // Attempt to empty all buckets found via GetResources API call diff --git a/internal/pkg/cli/env_delete_test.go b/internal/pkg/cli/env_delete_test.go index 9e13781006e..1d3503fec68 100644 --- a/internal/pkg/cli/env_delete_test.go +++ b/internal/pkg/cli/env_delete_test.go @@ -17,8 +17,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" stackdescr "github.com/aproint/copilot-cli/internal/pkg/describe/stack" "github.com/aproint/copilot-cli/internal/pkg/term/log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi" + "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -199,9 +200,9 @@ func TestDeleteEnvOpts_Execute(t *testing.T) { given: func(t *testing.T, ctrl *gomock.Controller) *deleteEnvOpts { m := mocks.NewMockresourceGetter(ctrl) m.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{ + ResourceTagMappingList: []types.ResourceTagMapping{ { - Tags: []*resourcegroupstaggingapi.Tag{ + Tags: []types.Tag{ { Key: aws.String(deploy.ServiceTagKey), Value: aws.String("frontend"), @@ -231,7 +232,7 @@ func TestDeleteEnvOpts_Execute(t *testing.T) { given: func(t *testing.T, ctrl *gomock.Controller) *deleteEnvOpts { rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}, + ResourceTagMappingList: []types.ResourceTagMapping{}, }, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) @@ -269,7 +270,7 @@ func TestDeleteEnvOpts_Execute(t *testing.T) { given: func(t *testing.T, ctrl *gomock.Controller) *deleteEnvOpts { rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) lister.EXPECT().ListDeployedPipelines("phonetool").Return([]deploy.Pipeline{}, nil) @@ -333,7 +334,7 @@ Resources: given: func(t *testing.T, ctrl *gomock.Controller) *deleteEnvOpts { rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) lister.EXPECT().ListDeployedPipelines("phonetool").Return([]deploy.Pipeline{}, nil) @@ -354,7 +355,7 @@ Resources: descr.EXPECT().Resources().Return([]*stackdescr.Resource{}, nil) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) deployer.EXPECT().DeleteEnvironment(gomock.Any(), gomock.Any(), gomock.Any()).Return(errors.New("some error")) @@ -392,7 +393,7 @@ Resources: } rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) lister.EXPECT().ListDeployedPipelines("phonetool").Return([]deploy.Pipeline{}, nil) @@ -416,7 +417,7 @@ Resources: descr.EXPECT().Resources().Return([]*stackdescr.Resource{}, nil) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) deployer.EXPECT().DeleteEnvironment("phonetool", "test", "execARN").Return(nil) @@ -480,7 +481,7 @@ Resources: } rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) lister.EXPECT().ListDeployedPipelines("phonetool").Return([]deploy.Pipeline{}, nil) @@ -569,7 +570,7 @@ Resources: } rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) lister.EXPECT().ListDeployedPipelines("phonetool").Return([]deploy.Pipeline{}, nil) @@ -657,7 +658,7 @@ Resources: } rg := mocks.NewMockresourceGetter(ctrl) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{}}, nil) + ResourceTagMappingList: []types.ResourceTagMapping{}}, nil) lister := mocks.NewMockdeployedPipelineLister(ctrl) lister.EXPECT().ListDeployedPipelines("phonetool").Return([]deploy.Pipeline{}, nil) @@ -691,10 +692,10 @@ Resources: ) rg.EXPECT().GetResources(gomock.Any()).Return(&resourcegroupstaggingapi.GetResourcesOutput{ - ResourceTagMappingList: []*resourcegroupstaggingapi.ResourceTagMapping{ + ResourceTagMappingList: []types.ResourceTagMapping{ { ResourceARN: aws.String("arn:aws:s3:::mockapp-mockenv-mockbucket"), - Tags: []*resourcegroupstaggingapi.Tag{ + Tags: []types.Tag{ { Key: aws.String(stack.StackNameTagKey), Value: aws.String("mockapp-mockenv"), diff --git a/internal/pkg/cli/env_deploy_test.go b/internal/pkg/cli/env_deploy_test.go index 6aa30a02d7a..e9dd21c118e 100644 --- a/internal/pkg/cli/env_deploy_test.go +++ b/internal/pkg/cli/env_deploy_test.go @@ -14,7 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/cli/env_init.go b/internal/pkg/cli/env_init.go index b03acc6e766..a905d535916 100644 --- a/internal/pkg/cli/env_init.go +++ b/internal/pkg/cli/env_init.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "net" @@ -37,8 +38,7 @@ import ( termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" "github.com/spf13/pflag" ) @@ -177,7 +177,7 @@ type initEnvOpts struct { manifestWriter environmentManifestWriter envLister wsEnvironmentsLister - sess *session.Session // Session pointing to environment's AWS account and region. + cfg aws.Config // Config pointing to environment's AWS account and region. // Cached variables. wsAppName string @@ -206,7 +206,7 @@ func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { initEnvVars: vars, sessProvider: sessProvider, store: store, - appDeployer: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), + appDeployer: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), identity: identity.New(v2ConfigFromSessionRegion(defaultSession)), prog: termprogress.NewSpinner(log.DiagnosticWriter), prompt: prompter, @@ -225,7 +225,7 @@ func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { return describe.NewAppDescriber(appName) }, selApp: selector.NewAppEnvSelector(prompt.New(), store), - appCFN: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), + appCFN: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), manifestWriter: ws, envLister: ws, @@ -317,7 +317,7 @@ func (o *initEnvOpts) Execute() error { if err := o.addToStackset(&deploycfn.AddEnvToAppOpts{ App: app, EnvName: o.name, - EnvRegion: aws.StringValue(o.sess.Config.Region), + EnvRegion: o.cfg.Region, EnvAccountID: envCaller.Account, }); err != nil { return err @@ -354,16 +354,16 @@ func (o *initEnvOpts) RecommendActions() error { func (o *initEnvOpts) initRuntimeClients() error { // Initialize environment clients if not set. if o.envIdentity == nil { - o.envIdentity = identity.New(v2ConfigFromSessionRegion(o.sess)) + o.envIdentity = identity.New(o.cfg) } if o.envDeployer == nil { - o.envDeployer = deploycfn.New(o.sess, deploycfn.WithProgressTracker(os.Stderr)) + o.envDeployer = deploycfn.New(o.cfg, deploycfn.WithProgressTracker(os.Stderr)) } if o.cfn == nil { - o.cfn = cloudformation.New(o.sess) + o.cfn = cloudformation.New(o.cfg) } if o.iam == nil { - o.iam = iam.New(v2ConfigFromSessionRegion(o.sess)) + o.iam = iam.New(o.cfg) } return nil } @@ -415,43 +415,43 @@ func (o *initEnvOpts) askEnvName() error { func (o *initEnvOpts) askEnvSession() error { if o.profile != "" { - sess, err := o.sessProvider.FromProfile(o.profile) + cfg, err := o.sessProvider.ConfigFromProfile(context.Background(), o.profile) if err != nil { - return fmt.Errorf("create session from profile %s: %w", o.profile, err) + return fmt.Errorf("create config from profile %s: %w", o.profile, err) } - o.sess = sess + o.cfg = cfg return nil } if o.tempCreds.isSet() { - sess, err := o.sessProvider.FromStaticCreds(o.tempCreds.AccessKeyID, o.tempCreds.SecretAccessKey, o.tempCreds.SessionToken) + cfg, err := o.sessProvider.ConfigFromStaticCreds(o.tempCreds.AccessKeyID, o.tempCreds.SecretAccessKey, o.tempCreds.SessionToken) if err != nil { return err } - o.sess = sess + o.cfg = cfg return nil } selCreds, err := o.selCreds() if err != nil { errRetrieveCreds := err - sess, err := o.sessProvider.Default() + cfg, err := o.sessProvider.DefaultConfig(context.Background()) if err != nil { return errors.Join(errRetrieveCreds, fmt.Errorf("falling back on default credentials: %w", err)) } - o.sess = sess + o.cfg = cfg return nil } - sess, err := selCreds.Creds(fmt.Sprintf(fmtEnvInitCredsPrompt, color.HighlightUserInput(o.name)), envInitCredsHelpPrompt) + cfg, err := selCreds.Creds(fmt.Sprintf(fmtEnvInitCredsPrompt, color.HighlightUserInput(o.name)), envInitCredsHelpPrompt) if err != nil { return fmt.Errorf("select creds: %w", err) } - o.sess = sess + o.cfg = cfg return nil } func (o *initEnvOpts) askEnvRegion() error { - region := aws.StringValue(o.sess.Config.Region) + region := o.cfg.Region if o.region != "" { region = o.region } @@ -462,7 +462,7 @@ func (o *initEnvOpts) askEnvRegion() error { } region = v } - o.sess.Config.Region = aws.String(region) + o.cfg.Region = region return nil } @@ -500,7 +500,7 @@ func (o *initEnvOpts) askCustomizedResources() error { func (o *initEnvOpts) askImportResources() error { if o.selVPC == nil { - o.selVPC = selector.NewEC2Select(o.prompt, ec2.New(v2ConfigFromSessionRegion(o.sess))) + o.selVPC = selector.NewEC2Select(o.prompt, ec2.New(o.cfg)) } if o.importVPC.ID == "" { vpcID, err := o.selVPC.VPC(envInitVPCSelectPrompt, "") @@ -516,7 +516,7 @@ func (o *initEnvOpts) askImportResources() error { o.importVPC.ID = vpcID } if o.ec2Client == nil { - o.ec2Client = ec2.New(v2ConfigFromSessionRegion(o.sess)) + o.ec2Client = ec2.New(o.cfg) } dnsSupport, err := o.ec2Client.HasDNSSupport(o.importVPC.ID) if err != nil { @@ -633,11 +633,11 @@ func (o *initEnvOpts) askAZs() ([]string, error) { return o.adjustVPC.AZs, nil } if o.ec2Client == nil { - o.ec2Client = ec2.New(v2ConfigFromSessionRegion(o.sess)) + o.ec2Client = ec2.New(o.cfg) } azs, err := o.ec2Client.ListAZs() if err != nil { - return nil, fmt.Errorf("list availability zones for region %s: %v", aws.StringValue(o.sess.Config.Region), err) + return nil, fmt.Errorf("list availability zones for region %s: %v", o.cfg.Region, err) } var options []string @@ -646,7 +646,7 @@ func (o *initEnvOpts) askAZs() ([]string, error) { } const minAZs = 2 if len(options) < minAZs { - return nil, fmt.Errorf("requires at least %d availability zones (%s) in region %s", minAZs, strings.Join(options, ", "), aws.StringValue(o.sess.Config.Region)) + return nil, fmt.Errorf("requires at least %d availability zones (%s) in region %s", minAZs, strings.Join(options, ", "), o.cfg.Region) } defaultOptions := make([]string, minAZs) for i := 0; i < minAZs; i += 1 { @@ -722,7 +722,7 @@ func (o *initEnvOpts) adjustVPCConfig() *config.AdjustVPC { } func (o *initEnvOpts) deployEnv(app *config.Application) error { - envRegion := aws.StringValue(o.sess.Config.Region) + envRegion := o.cfg.Region resources, err := o.appCFN.GetAppResourcesByRegion(app, envRegion) if err != nil { return fmt.Errorf("get app resources: %w", err) diff --git a/internal/pkg/cli/env_init_test.go b/internal/pkg/cli/env_init_test.go index 50540e3b57a..d6effb34648 100644 --- a/internal/pkg/cli/env_init_test.go +++ b/internal/pkg/cli/env_init_test.go @@ -22,8 +22,7 @@ import ( deploycfn "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/term/log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -342,11 +341,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { mockRegion = "us-west-2" ) mockErr := errors.New("some error") - mockSession := &session.Session{ - Config: &aws.Config{ - Region: aws.String(mockRegion), - }, - } + mockConfig := aws.Config{Region: mockRegion} mockPublicSubnetInput := selector.SubnetsInput{ Msg: envInitPublicSubnetsSelectPrompt, Help: "", @@ -411,11 +406,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { Return("test", nil), m.store.EXPECT().GetEnvironment(mockApp, mockEnv).Return(nil, nil), m.envLister.EXPECT().ListEnvironments().Return([]string{mockEnv}, nil), - m.sessProvider.EXPECT().FromProfile(mockProfile).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("us-west-2"), - }, - }, nil).AnyTimes(), + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), mockProfile).Return(aws.Config{Region: "us-west-2"}, nil).AnyTimes(), ) }, }, @@ -425,11 +416,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inProfile: mockProfile, inDefault: true, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(mockProfile).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("us-west-2"), - }, - }, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), mockProfile).Return(aws.Config{Region: "us-west-2"}, nil) }, }, "should create a session from temporary creds if flags are provided": { @@ -441,7 +428,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { }, inDefault: true, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromStaticCreds("abcd", "efgh", "").Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromStaticCreds("abcd", "efgh", "").Return(mockConfig, nil) }, }, "should prompt for credentials if no profile or temp creds flags are provided": { @@ -449,7 +436,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inDefault: true, setupMocks: func(m initEnvMocks) { - m.selCreds.EXPECT().Creds("Which credentials would you like to use to create test?", gomock.Any()).Return(mockSession, nil) + m.selCreds.EXPECT().Creds("Which credentials would you like to use to create test?", gomock.Any()).Return(mockConfig, nil) }, }, "should fallback on default session if credentials cant be found": { @@ -460,11 +447,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { return nil, mockErr }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("us-west-2"), - }, - }, nil) + m.sessProvider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: "us-west-2"}, nil) }, }, "should prompt for region if user configuration does not have one": { @@ -473,9 +456,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inProfile: mockProfile, inDefault: true, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(&session.Session{ - Config: &aws.Config{}, - }, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.prompt.EXPECT().Get("Which region?", gomock.Any(), nil, gomock.Any(), gomock.Any()).Return("us-west-2", nil) }, }, @@ -486,9 +467,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inRegion: mockRegion, inDefault: true, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(&session.Session{ - Config: &aws.Config{}, - }, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.prompt.EXPECT().Get("Which region?", gomock.Any(), nil, gomock.Any(), gomock.Any()).Times(0) }, }, @@ -498,7 +477,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inProfile: mockProfile, inDefault: true, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, }, @@ -507,7 +486,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return("", mockErr) }, @@ -518,7 +497,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitDefaultConfigSelectOption, nil) }, @@ -528,7 +507,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("", mockErr) @@ -540,7 +519,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -553,7 +532,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -566,7 +545,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -581,7 +560,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -596,7 +575,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -613,7 +592,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -630,7 +609,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -646,7 +625,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -662,7 +641,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitImportEnvResourcesSelectOption, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) @@ -683,7 +662,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { PublicSubnetIDs: []string{"mockPublicSubnetID", "anotherMockPublicSubnetID"}, }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) m.ec2Client.EXPECT().HasDNSSupport("mockVPCID").Return(true, nil) }, @@ -696,7 +675,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { ID: "mockVPC", }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) m.selVPC.EXPECT().Subnets(mockPublicSubnetInput). Return([]string{"mockPublicSubnet", "anotherMockPublicSubnet"}, nil) @@ -713,7 +692,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { PublicSubnetIDs: []string{"mockPublicSubnetID", "anotherMockPublicSubnetID"}, }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) }, @@ -727,7 +706,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { PrivateSubnetIDs: []string{"mockPrivateSubnetID", "anotherMockPrivateSubnetID"}, }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) m.selVPC.EXPECT().Subnets(mockPublicSubnetInput). Return([]string{"mockPublicSubnet", "anotherMockPublicSubnet"}, nil) @@ -742,7 +721,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { PublicSubnetIDs: []string{"mockPublicSubnetID", "anotherMockPublicSubnetID"}, }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) m.selVPC.EXPECT().Subnets(mockPrivateSubnetInput). Return([]string{"mockPrivateSubnet", "anotherMockPrivateSubnet"}, nil) @@ -757,7 +736,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { }, inInternalALBSubnets: []string{"nonexistentSubnet", "anotherNonexistentSubnet"}, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) m.selVPC.EXPECT().Subnets(mockPublicSubnetInput). Return([]string{"mockPublicSubnet", "anotherMockPublicSubnet"}, nil) @@ -775,7 +754,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { ID: "mockVPC", }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) m.selVPC.EXPECT().Subnets(mockPublicSubnetInput). Return(nil, nil) @@ -790,7 +769,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inProfile: mockProfile, inInternalALBSubnets: []string{"mockPrivateSubnet", "anotherMockPrivateSubnet"}, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.selVPC.EXPECT().VPC(envInitVPCSelectPrompt, "").Return("mockVPC", nil) m.ec2Client.EXPECT().HasDNSSupport("mockVPC").Return(true, nil) m.selVPC.EXPECT().Subnets(mockPublicSubnetInput). @@ -804,7 +783,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitAdjustEnvResourcesSelectOption, nil) m.prompt.EXPECT().Get(envInitVPCCIDRPrompt, envInitVPCCIDRPromptHelp, gomock.Any(), gomock.Any()). @@ -817,7 +796,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()). Return(envInitAdjustEnvResourcesSelectOption, nil) m.prompt.EXPECT().Get(envInitVPCCIDRPrompt, gomock.Any(), gomock.Any(), gomock.Any()). @@ -831,7 +810,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()). Return(envInitAdjustEnvResourcesSelectOption, nil) m.prompt.EXPECT().Get(envInitVPCCIDRPrompt, gomock.Any(), gomock.Any(), gomock.Any()). @@ -849,7 +828,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()). Return(envInitAdjustEnvResourcesSelectOption, nil) m.prompt.EXPECT().Get(envInitVPCCIDRPrompt, gomock.Any(), gomock.Any(), gomock.Any()). @@ -874,7 +853,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()). Return(envInitAdjustEnvResourcesSelectOption, nil) m.prompt.EXPECT().Get(envInitVPCCIDRPrompt, gomock.Any(), gomock.Any(), gomock.Any()). @@ -901,7 +880,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { inEnv: mockEnv, inProfile: mockProfile, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, "", envInitCustomizedEnvTypes, gomock.Any()). Return(envInitAdjustEnvResourcesSelectOption, nil) m.prompt.EXPECT().Get(envInitVPCCIDRPrompt, envInitVPCCIDRPromptHelp, gomock.Any(), gomock.Any()). @@ -936,7 +915,7 @@ func TestInitEnvOpts_Ask(t *testing.T) { PublicSubnetCIDRs: []string{"mockPublicCIDR1", "mockPublicCIDR2"}, }, setupMocks: func(m initEnvMocks) { - m.sessProvider.EXPECT().FromProfile(gomock.Any()).Return(mockSession, nil) + m.sessProvider.EXPECT().ConfigFromProfile(gomock.Any(), gomock.Any()).Return(mockConfig, nil) m.prompt.EXPECT().SelectOne(envInitDefaultEnvConfirmPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Times(0) }, }, @@ -1347,7 +1326,7 @@ func TestInitEnvOpts_Execute(t *testing.T) { iam: m.iam, cfn: m.cfn, prog: m.progress, - sess: sess, + cfg: v2ConfigFromSessionRegion(sess), appCFN: m.appCFN, newAppVersionGetter: func(appName string) (versionGetter, error) { return m.appVersionGetter, nil diff --git a/internal/pkg/cli/env_package_test.go b/internal/pkg/cli/env_package_test.go index 92bad68e712..3f536c0477f 100644 --- a/internal/pkg/cli/env_package_test.go +++ b/internal/pkg/cli/env_package_test.go @@ -11,7 +11,7 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/cli/deploy" diff --git a/internal/pkg/cli/init.go b/internal/pkg/cli/init.go index d125e034884..0a27cf94b4c 100644 --- a/internal/pkg/cli/init.go +++ b/internal/pkg/cli/init.go @@ -34,7 +34,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -120,7 +120,7 @@ func newInitOpts(vars initVars) (*initOpts, error) { snsSel := selector.NewDeploySelect(prompt, configStore, deployStore) spin := termprogress.NewSpinner(log.DiagnosticWriter) id := identity.New(v2ConfigFromSessionRegion(defaultSess)) - deployer := cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)) + deployer := cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)) iamClient := iam.New(v2ConfigFromSessionRegion(defaultSess)) initAppCmd := &initAppOpts{ initAppVars: initAppVars{ @@ -152,8 +152,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { newAppVersionGetter: func(appName string) (versionGetter, error) { return describe.NewAppDescriber(appName) }, - appCFN: cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)), - sess: defaultSess, + appCFN: cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)), + cfg: v2ConfigFromSessionRegion(defaultSess), templateVersion: version.LatestTemplateVersion(), } deployEnvCmd := &deployEnvOpts{ @@ -483,7 +483,7 @@ func (o *initOpts) deployEnv() error { if err := o.askShouldDeploy(); err != nil { return err } - if !aws.BoolValue(o.shouldDeploy) { + if !aws.ToBool(o.shouldDeploy) { // User chose not to deploy the service, exit. return nil } @@ -514,7 +514,7 @@ func (o *initOpts) deployEnv() error { } func (o *initOpts) deploySvc() error { - if !aws.BoolValue(o.shouldDeploy) { + if !aws.ToBool(o.shouldDeploy) { return nil } if deployOpts, ok := o.deploySvcCmd.(*deploySvcOpts); ok { @@ -537,7 +537,7 @@ func (o *initOpts) deploySvc() error { } func (o *initOpts) deployJob() error { - if !aws.BoolValue(o.shouldDeploy) { + if !aws.ToBool(o.shouldDeploy) { return nil } if deployOpts, ok := o.deployJobCmd.(*deployJobOpts); ok { @@ -643,7 +643,7 @@ func BuildInitCmd() *cobra.Command { } // ShouldDeploy will always be set after flags or prompting. - if !aws.BoolValue(opts.shouldDeploy) { + if !aws.ToBool(opts.shouldDeploy) { log.Info("\nNo problem, you can deploy your service later:\n") log.Infof("- Run %s to create your environment.\n", color.HighlightCode("copilot env init")) log.Infof("- Run %s to deploy your service.\n", color.HighlightCode("copilot deploy")) diff --git a/internal/pkg/cli/init_test.go b/internal/pkg/cli/init_test.go index bf5e7567f49..befb8f76874 100644 --- a/internal/pkg/cli/init_test.go +++ b/internal/pkg/cli/init_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/config" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" awscfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" diff --git a/internal/pkg/cli/interfaces.go b/internal/pkg/cli/interfaces.go index bd9b9cbf8b0..a638d98c2c4 100644 --- a/internal/pkg/cli/interfaces.go +++ b/internal/pkg/cli/interfaces.go @@ -8,7 +8,7 @@ import ( "encoding" "io" - sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + sdkcloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" awscloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/codepipeline" @@ -204,6 +204,7 @@ type eventsWriter interface { type defaultSessionProvider interface { Default() (*session.Session, error) + DefaultConfig(ctx context.Context) (awsv2.Config, error) } type regionalSessionProvider interface { @@ -218,10 +219,12 @@ type sessionFromRoleProvider interface { type sessionFromStaticProvider interface { FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) + ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (awsv2.Config, error) } type sessionFromProfileProvider interface { FromProfile(name string) (*session.Session, error) + ConfigFromProfile(ctx context.Context, name string) (awsv2.Config, error) } type sessionProvider interface { @@ -587,7 +590,7 @@ type ec2Selector interface { } type credsSelector interface { - Creds(prompt, help string) (*session.Session, error) + Creds(prompt, help string) (awsv2.Config, error) } type ec2Client interface { diff --git a/internal/pkg/cli/job_delete.go b/internal/pkg/cli/job_delete.go index 048a078a26c..0161a1e8028 100644 --- a/internal/pkg/cli/job_delete.go +++ b/internal/pkg/cli/job_delete.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -25,7 +26,7 @@ import ( termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -64,9 +65,9 @@ type deleteJobOpts struct { sess sessionProvider spinner progress appCFN jobRemoverFromApp - newWlDeleter func(sess *session.Session) wlDeleter - newImageRemover func(sess *session.Session) imageRemover - newTaskStopper func(sess *session.Session) taskStopper + newWlDeleter func(aws.Config) wlDeleter + newImageRemover func(aws.Config) imageRemover + newTaskStopper func(aws.Config) taskStopper } func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { @@ -88,15 +89,15 @@ func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { prompt: prompt.New(), sel: selector.NewConfigSelector(prompter, store), sess: provider, - appCFN: cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)), - newWlDeleter: func(session *session.Session) wlDeleter { - return cloudformation.New(session, cloudformation.WithProgressTracker(os.Stderr)) + appCFN: cloudformation.New(v2ConfigFromSessionRegion(defaultSession), cloudformation.WithProgressTracker(os.Stderr)), + newWlDeleter: func(cfg aws.Config) wlDeleter { + return cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) }, - newImageRemover: func(session *session.Session) imageRemover { - return ecr.New(v2ConfigFromSessionRegion(session)) + newImageRemover: func(cfg aws.Config) imageRemover { + return ecr.New(cfg) }, - newTaskStopper: func(session *session.Session) taskStopper { - return ecs.New(session, v2ConfigFromSessionRegion(session)) + newTaskStopper: func(cfg aws.Config) taskStopper { + return ecs.New(cfg) }, }, nil } @@ -248,24 +249,24 @@ func (o *deleteJobOpts) appEnvironments() ([]*config.Environment, error) { func (o *deleteJobOpts) deleteJobs(envs []*config.Environment) error { for _, env := range envs { - sess, err := o.sess.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := o.sess.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } // Delete job stack - if err = o.deleteStack(sess, env); err != nil { + if err = o.deleteStack(cfg, env); err != nil { return err } // Delete orphan tasks - if err = o.deleteTasks(sess, env.Name); err != nil { + if err = o.deleteTasks(cfg, env.Name); err != nil { return err } } return nil } -func (o *deleteJobOpts) deleteStack(sess *session.Session, env *config.Environment) error { - cfClient := o.newWlDeleter(sess) +func (o *deleteJobOpts) deleteStack(cfg aws.Config, env *config.Environment) error { + cfClient := o.newWlDeleter(cfg) if err := cfClient.DeleteWorkload(deploy.DeleteWorkloadInput{ Name: o.name, EnvName: env.Name, @@ -277,9 +278,9 @@ func (o *deleteJobOpts) deleteStack(sess *session.Session, env *config.Environme return nil } -func (o *deleteJobOpts) deleteTasks(sess *session.Session, env string) error { +func (o *deleteJobOpts) deleteTasks(cfg aws.Config, env string) error { o.spinner.Start(fmt.Sprintf(fmtJobTasksStopStart, o.name, env)) - if err := o.newTaskStopper(sess).StopWorkloadTasks(o.appName, env, o.name); err != nil { + if err := o.newTaskStopper(cfg).StopWorkloadTasks(o.appName, env, o.name); err != nil { o.spinner.Stop(log.Serrorf(fmtJobTasksStopFailed, o.name, env, err)) return fmt.Errorf("stop tasks for environment %s: %w", env, err) } @@ -306,11 +307,11 @@ func (o *deleteJobOpts) emptyECRRepos(envs []*config.Environment) error { repoName := clideploy.RepoName(o.appName, o.name) for _, region := range uniqueRegions { - sess, err := o.sess.DefaultWithRegion(region) + cfg, err := o.sess.DefaultConfigWithRegion(context.Background(), region) if err != nil { return err } - client := o.newImageRemover(sess) + client := o.newImageRemover(cfg) if err := client.ClearRepository(repoName); err != nil { return err } diff --git a/internal/pkg/cli/job_delete_test.go b/internal/pkg/cli/job_delete_test.go index 066816942ca..cf2d355e5cb 100644 --- a/internal/pkg/cli/job_delete_test.go +++ b/internal/pkg/cli/job_delete_test.go @@ -8,9 +8,7 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" @@ -336,7 +334,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { // appEnvironments mocks.store.EXPECT().ListEnvironments(gomock.Eq(mockAppName)).Times(1).Return(mockEnvs, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), // delete orphan tasks @@ -344,7 +342,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { mocks.ecs.EXPECT().StopWorkloadTasks(mockAppName, mockEnvName, mockJobName).Return(nil), mocks.spinner.EXPECT().Stop(log.Ssuccessf(fmtJobTasksStopComplete, mockJobName, mockEnvName)), - mocks.sessProvider.EXPECT().DefaultWithRegion(gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().DefaultConfigWithRegion(gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // emptyECRRepos mocks.ecr.EXPECT().ClearRepository(mockRepo).Return(nil), // removeJobFromApp @@ -368,7 +366,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { gomock.InOrder( // appEnvironments mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), // delete orphan tasks @@ -396,11 +394,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { gomock.InOrder( // appEnvironments mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(testError), ) @@ -415,11 +409,7 @@ func TestDeleteJobOpts_Execute(t *testing.T) { gomock.InOrder( // appEnvironments mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), // deleteStacks mocks.jobCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), // delete orphan tasks @@ -446,13 +436,13 @@ func TestDeleteJobOpts_Execute(t *testing.T) { mockSpinner := mocks.NewMockprogress(ctrl) mockImageRemover := mocks.NewMockimageRemover(ctrl) mockTaskStopper := mocks.NewMocktaskStopper(ctrl) - mockGetJobCFN := func(_ *session.Session) wlDeleter { + mockGetJobCFN := func(_ aws.Config) wlDeleter { return mockJobCFN } - mockGetImageRemover := func(_ *session.Session) imageRemover { + mockGetImageRemover := func(_ aws.Config) imageRemover { return mockImageRemover } - mockNewTaskStopper := func(_ *session.Session) taskStopper { + mockNewTaskStopper := func(_ aws.Config) taskStopper { return mockTaskStopper } diff --git a/internal/pkg/cli/job_deploy.go b/internal/pkg/cli/job_deploy.go index 6c2abcdb216..b26c2ae5845 100644 --- a/internal/pkg/cli/job_deploy.go +++ b/internal/pkg/cli/job_deploy.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -11,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" deploycfn "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" @@ -54,7 +55,7 @@ type deployJobOpts struct { // cached variables targetApp *config.Application targetEnv *config.Environment - envSess *session.Session + envConfig aws.Config rawMft string // Content of the environment manifest with env var interpolation only. appliedDynamicMft manifest.DynamicWorkload rootUserARN string @@ -181,7 +182,7 @@ func (o *deployJobOpts) Execute() error { ws: o.ws, interpolator: o.newInterpolator(o.appName, o.envName), unmarshal: o.unmarshal, - sess: o.envSess, + cfg: o.envConfig, }) if err != nil { return err @@ -297,18 +298,18 @@ func (o *deployJobOpts) configureClients() error { o.targetApp = app // client to retrieve an application's resources created with CloudFormation - defaultSess, err := o.sessProvider.Default() + defaultConfig, err := o.sessProvider.DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("create default session: %w", err) + return fmt.Errorf("create default config: %w", err) } - envSess, err := o.sessProvider.FromRole(env.ManagerRoleARN, env.Region) + envConfig, err := o.sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } - o.envSess = envSess + o.envConfig = envConfig // client to retrieve caller identity. - caller, err := identity.New(v2ConfigFromSessionRegion(defaultSess)).Get() + caller, err := identity.New(defaultConfig).Get() if err != nil { return fmt.Errorf("get identity: %w", err) } diff --git a/internal/pkg/cli/job_init.go b/internal/pkg/cli/job_init.go index 5b06591f598..b9ad10250e7 100644 --- a/internal/pkg/cli/job_init.go +++ b/internal/pkg/cli/job_init.go @@ -108,7 +108,7 @@ func newInitJobOpts(vars initJobVars) (*initJobOpts, error) { Store: store, Ws: ws, Prog: termprogress.NewSpinner(log.DiagnosticWriter), - Deployer: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), + Deployer: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), } prompter := prompt.New() diff --git a/internal/pkg/cli/job_logs.go b/internal/pkg/cli/job_logs.go index 1444876b5ec..39d792d0eea 100644 --- a/internal/pkg/cli/job_logs.go +++ b/internal/pkg/cli/job_logs.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" @@ -14,7 +15,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" ) @@ -71,12 +72,12 @@ func newJobLogOpts(vars jobLogsVars) (*jobLogsOpts, error) { if err != nil { return fmt.Errorf("get environment: %w", err) } - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } opts.logsSvc = logging.NewJobLogger(&logging.NewWorkloadLoggerOpts{ - Sess: sess, + Cfg: cfg, App: opts.appName, Env: opts.envName, Name: opts.name, diff --git a/internal/pkg/cli/job_run.go b/internal/pkg/cli/job_run.go index a0bb23711db..479ddc245d9 100644 --- a/internal/pkg/cli/job_run.go +++ b/internal/pkg/cli/job_run.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" @@ -17,7 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -70,7 +71,7 @@ func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { sessProvider: sessProvider, } opts.newRunner = func() (runner, error) { - sess, err := opts.envSession() + cfg, err := opts.envConfig() if err != nil { return nil, err } @@ -80,8 +81,8 @@ func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { Env: opts.envName, Job: opts.jobName, - CFN: cloudformation.New(sess), - StateMachine: stepfunctions.New(v2ConfigFromSessionRegion(sess)), + CFN: cloudformation.New(cfg), + StateMachine: stepfunctions.New(cfg), }), nil } opts.newEnvCompatibilityChecker = func() (versionCompatibilityChecker, error) { @@ -191,12 +192,12 @@ func (o *jobRunOpts) getTargetEnv() (*config.Environment, error) { return o.targetEnv, nil } -func (o *jobRunOpts) envSession() (*session.Session, error) { +func (o *jobRunOpts) envConfig() (aws.Config, error) { env, err := o.getTargetEnv() if err != nil { - return nil, err + return aws.Config{}, err } - return o.sessProvider.FromRole(env.ManagerRoleARN, env.Region) + return o.sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) } func (o *jobRunOpts) validateEnvCompatible() error { diff --git a/internal/pkg/cli/mocks/mock_interfaces.go b/internal/pkg/cli/mocks/mock_interfaces.go index 9ac0805d1e2..b2189d5d5bc 100644 --- a/internal/pkg/cli/mocks/mock_interfaces.go +++ b/internal/pkg/cli/mocks/mock_interfaces.go @@ -36,8 +36,8 @@ import ( selector "github.com/aproint/copilot-cli/internal/pkg/term/selector" workspace "github.com/aproint/copilot-cli/internal/pkg/workspace" aws "github.com/aws/aws-sdk-go-v2/aws" + types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" session "github.com/aws/aws-sdk-go/aws/session" - cloudformation1 "github.com/aws/aws-sdk-go/service/cloudformation" gomock "github.com/golang/mock/gomock" ) @@ -2067,6 +2067,21 @@ func (m *MocksessionFromStaticProvider) EXPECT() *MocksessionFromStaticProviderM return m.recorder } +// ConfigFromStaticCreds mocks base method. +func (m *MocksessionFromStaticProvider) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFromStaticCreds", accessKeyID, secretAccessKey, sessionToken) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConfigFromStaticCreds indicates an expected call of ConfigFromStaticCreds. +func (mr *MocksessionFromStaticProviderMockRecorder) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromStaticCreds", reflect.TypeOf((*MocksessionFromStaticProvider)(nil).ConfigFromStaticCreds), accessKeyID, secretAccessKey, sessionToken) +} + // FromStaticCreds mocks base method. func (m *MocksessionFromStaticProvider) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) { m.ctrl.T.Helper() @@ -2105,6 +2120,21 @@ func (m *MocksessionFromProfileProvider) EXPECT() *MocksessionFromProfileProvide return m.recorder } +// ConfigFromProfile mocks base method. +func (m *MocksessionFromProfileProvider) ConfigFromProfile(ctx context.Context, name string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFromProfile", ctx, name) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConfigFromProfile indicates an expected call of ConfigFromProfile. +func (mr *MocksessionFromProfileProviderMockRecorder) ConfigFromProfile(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromProfile", reflect.TypeOf((*MocksessionFromProfileProvider)(nil).ConfigFromProfile), ctx, name) +} + // FromProfile mocks base method. func (m *MocksessionFromProfileProvider) FromProfile(name string) (*session.Session, error) { m.ctrl.T.Helper() @@ -2158,6 +2188,36 @@ func (mr *MocksessionProviderMockRecorder) ConfigFromRole(ctx, roleARN, region i return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromRole), ctx, roleARN, region) } +// ConfigFromProfile mocks base method. +func (m *MocksessionProvider) ConfigFromProfile(ctx context.Context, name string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFromProfile", ctx, name) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConfigFromProfile indicates an expected call of ConfigFromProfile. +func (mr *MocksessionProviderMockRecorder) ConfigFromProfile(ctx, name interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromProfile", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromProfile), ctx, name) +} + +// ConfigFromStaticCreds mocks base method. +func (m *MocksessionProvider) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConfigFromStaticCreds", accessKeyID, secretAccessKey, sessionToken) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConfigFromStaticCreds indicates an expected call of ConfigFromStaticCreds. +func (mr *MocksessionProviderMockRecorder) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromStaticCreds", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromStaticCreds), accessKeyID, secretAccessKey, sessionToken) +} + // Default mocks base method. func (m *MocksessionProvider) Default() (*session.Session, error) { m.ctrl.T.Helper() @@ -2173,6 +2233,21 @@ func (mr *MocksessionProviderMockRecorder) Default() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Default", reflect.TypeOf((*MocksessionProvider)(nil).Default)) } +// DefaultConfig mocks base method. +func (m *MocksessionProvider) DefaultConfig(ctx context.Context) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultConfig", ctx) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DefaultConfig indicates an expected call of DefaultConfig. +func (mr *MocksessionProviderMockRecorder) DefaultConfig(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfig", reflect.TypeOf((*MocksessionProvider)(nil).DefaultConfig), ctx) +} + // DefaultConfigWithRegion mocks base method. func (m *MocksessionProvider) DefaultConfigWithRegion(ctx context.Context, region string) (aws.Config, error) { m.ctrl.T.Helper() @@ -6544,10 +6619,10 @@ func (m *MockcredsSelector) EXPECT() *MockcredsSelectorMockRecorder { } // Creds mocks base method. -func (m *MockcredsSelector) Creds(prompt, help string) (*session.Session, error) { +func (m *MockcredsSelector) Creds(prompt, help string) (aws.Config, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Creds", prompt, help) - ret0, _ := ret[0].(*session.Session) + ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -8197,10 +8272,10 @@ func (m *MockstackConfiguration) EXPECT() *MockstackConfigurationMockRecorder { } // Parameters mocks base method. -func (m *MockstackConfiguration) Parameters() ([]*cloudformation1.Parameter, error) { +func (m *MockstackConfiguration) Parameters() ([]*types.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Parameters") - ret0, _ := ret[0].([]*cloudformation1.Parameter) + ret0, _ := ret[0].([]*types.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -8241,10 +8316,10 @@ func (mr *MockstackConfigurationMockRecorder) StackName() *gomock.Call { } // Tags mocks base method. -func (m *MockstackConfiguration) Tags() []*cloudformation1.Tag { +func (m *MockstackConfiguration) Tags() []*types.Tag { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Tags") - ret0, _ := ret[0].([]*cloudformation1.Tag) + ret0, _ := ret[0].([]*types.Tag) return ret0 } diff --git a/internal/pkg/cli/mocks/mock_rg.go b/internal/pkg/cli/mocks/mock_rg.go index 8c71c68f69b..2f9479314ce 100644 --- a/internal/pkg/cli/mocks/mock_rg.go +++ b/internal/pkg/cli/mocks/mock_rg.go @@ -7,7 +7,7 @@ package mocks import ( reflect "reflect" - resourcegroupstaggingapi "github.com/aws/aws-sdk-go/service/resourcegroupstaggingapi" + resourcegroupstaggingapi "github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi" gomock "github.com/golang/mock/gomock" ) diff --git a/internal/pkg/cli/pipeline_delete.go b/internal/pkg/cli/pipeline_delete.go index 8b5b1ef0668..fdbb0b8a19f 100644 --- a/internal/pkg/cli/pipeline_delete.go +++ b/internal/pkg/cli/pipeline_delete.go @@ -22,7 +22,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -98,7 +98,7 @@ func newDeletePipelineOpts(vars deletePipelineVars) (*deletePipelineOpts, error) prog: termprogress.NewSpinner(log.DiagnosticWriter), prompt: prompter, secretsmanager: secretsmanager.New(v2Config), - pipelineDeployer: cloudformation.New(defaultSess, cloudformation.WithProgressTracker(os.Stderr)), + pipelineDeployer: cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)), deployedPipelineLister: pipelineLister, ws: ws, store: ssmStore, @@ -228,7 +228,7 @@ func (o *deletePipelineOpts) getSecret() error { } for _, tag := range output.Tags { - if aws.StringValue(tag.Key) == deploy.AppTagKey && aws.StringValue(tag.Value) == output.CreatedDate.UTC().Format(time.UnixDate) { + if aws.ToString(tag.Key) == deploy.AppTagKey && aws.ToString(tag.Value) == output.CreatedDate.UTC().Format(time.UnixDate) { return nil } } diff --git a/internal/pkg/cli/pipeline_delete_test.go b/internal/pkg/cli/pipeline_delete_test.go index 5dfbeb7457e..6a99c8f29c6 100644 --- a/internal/pkg/cli/pipeline_delete_test.go +++ b/internal/pkg/cli/pipeline_delete_test.go @@ -11,8 +11,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/secretsmanager" "github.com/aproint/copilot-cli/internal/pkg/deploy" + "github.com/aws/aws-sdk-go-v2/aws" secretsmanagertypes "github.com/aws/aws-sdk-go-v2/service/secretsmanager/types" - "github.com/aws/aws-sdk-go/aws" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/term/log" diff --git a/internal/pkg/cli/pipeline_deploy.go b/internal/pkg/cli/pipeline_deploy.go index 0322212cea6..2e3b2c11f1c 100644 --- a/internal/pkg/cli/pipeline_deploy.go +++ b/internal/pkg/cli/pipeline_deploy.go @@ -37,7 +37,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" @@ -139,8 +139,8 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) opts := &deployPipelineOpts{ ws: ws, - pipelineDeployer: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), - region: aws.StringValue(defaultSession.Config.Region), + pipelineDeployer: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), + region: aws.ToString(defaultSession.Config.Region), deployPipelineVars: vars, store: store, prog: termprogress.NewSpinner(log.DiagnosticWriter), diff --git a/internal/pkg/cli/pipeline_init.go b/internal/pkg/cli/pipeline_init.go index 480c66f1794..8c3fde20ab0 100644 --- a/internal/pkg/cli/pipeline_init.go +++ b/internal/pkg/cli/pipeline_init.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "errors" "fmt" "os" @@ -23,8 +24,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/exec" - "github.com/aws/aws-sdk-go/aws" - "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/version" @@ -222,16 +221,12 @@ func newInitPipelineOpts(vars initPipelineVars) (*initPipelineOpts, error) { } p := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline init")) - defaultSession, err := p.Default() + v2Config, err := p.DefaultConfig(context.Background()) if err != nil { return nil, err } - ssmStore, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } - v2Config := v2ConfigFromSessionRegion(defaultSession) + ssmStore := newSSMConfigStoreFromConfig(v2Config) prompter := prompt.New() wsAppName := tryReadingAppName() @@ -245,7 +240,7 @@ func newInitPipelineOpts(vars initPipelineVars) (*initPipelineOpts, error) { secretsmanager: secretsmanager.New(v2Config), parser: template.New(), sessProvider: p, - cfnClient: cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)), + cfnClient: cloudformation.New(v2Config, cloudformation.WithProgressTracker(os.Stderr)), store: ssmStore, prompt: prompter, sel: selector.NewAppEnvSelector(prompter, ssmStore), @@ -530,11 +525,11 @@ func (o *initPipelineOpts) parseCodeCommitRepoDetails() error { o.ccRegion = repoDetails.region // If the CodeCommit region is different than that of the app, pipeline init errors out. - sess, err := o.sessProvider.Default() + cfg, err := o.sessProvider.DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("retrieve default session: %w", err) + return fmt.Errorf("retrieve default config: %w", err) } - region := aws.StringValue(sess.Config.Region) + region := cfg.Region if o.ccRegion == "" { o.ccRegion = region } diff --git a/internal/pkg/cli/pipeline_init_test.go b/internal/pkg/cli/pipeline_init_test.go index 3c172a6272c..8bc0d33ddcb 100644 --- a/internal/pkg/cli/pipeline_init_test.go +++ b/internal/pkg/cli/pipeline_init_test.go @@ -17,8 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template" templatemocks "github.com/aproint/copilot-cli/internal/pkg/template/mocks" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -120,11 +119,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inRepoURL: "codecommit::us-west-2://repo-man", setupMocks: func(m pipelineInitMocks) { m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) - m.sessProvider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("us-east-1"), - }, - }, nil) + m.sessProvider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: "us-east-1"}, nil) }, expectedError: errors.New("repository repo-man is in us-west-2, but app my-app is in us-east-1; they must be in the same region"), }, @@ -296,11 +291,7 @@ func TestInitPipelineOpts_Ask(t *testing.T) { inGitBranch: "main", setupMocks: func(m pipelineInitMocks) { m.store.EXPECT().GetApplication(mockAppName).Return(mockApp, nil) - m.sessProvider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("us-west-2"), - }, - }, nil) + m.sessProvider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: "us-west-2"}, nil) m.prompt.EXPECT().SelectOption(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes() m.store.EXPECT().GetEnvironment("my-app", "test").Return( &config.Environment{ @@ -586,11 +577,7 @@ func TestInitPipelineOpts_Execute(t *testing.T) { S3Bucket: "gooseBucket", }, }, nil) - m.sessProvider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("us-west-2"), - }, - }, nil) + m.sessProvider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: "us-west-2"}, nil) }, expectedError: nil, }, diff --git a/internal/pkg/cli/pipeline_package.go b/internal/pkg/cli/pipeline_package.go index de5821543c4..9f672accaec 100644 --- a/internal/pkg/cli/pipeline_package.go +++ b/internal/pkg/cli/pipeline_package.go @@ -71,7 +71,7 @@ func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, err } opts := &packagePipelineOpts{ packagePipelineVars: vars, - pipelineDeployer: deploycfn.New(defaultSession, deploycfn.WithProgressTracker(os.Stderr)), + pipelineDeployer: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), tmplWriter: os.Stdout, ws: ws, store: store, diff --git a/internal/pkg/cli/run_local.go b/internal/pkg/cli/run_local.go index 66ff23b5d40..3dec311562e 100644 --- a/internal/pkg/cli/run_local.go +++ b/internal/pkg/cli/run_local.go @@ -51,14 +51,10 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/syncbuffer" "github.com/aproint/copilot-cli/internal/pkg/workspace" awsv2 "github.com/aws/aws-sdk-go-v2/aws" + awsarn "github.com/aws/aws-sdk-go-v2/aws/arn" sdkecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/rds" - sdksecretsmanager "github.com/aws/aws-sdk-go/service/secretsmanager" - sdkssm "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/rds" + rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types" "github.com/fsnotify/fsnotify" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -90,8 +86,8 @@ type taggedResourceGetter interface { } type rdsDescriber interface { - DescribeDBInstancesPagesWithContext(context.Context, *rds.DescribeDBInstancesInput, func(*rds.DescribeDBInstancesOutput, bool) bool, ...request.Option) error - DescribeDBClustersPagesWithContext(context.Context, *rds.DescribeDBClustersInput, func(*rds.DescribeDBClustersOutput, bool) bool, ...request.Option) error + DescribeDBInstances(context.Context, *rds.DescribeDBInstancesInput, ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) + DescribeDBClusters(context.Context, *rds.DescribeDBClustersInput, ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) } type recursiveWatcher interface { @@ -117,27 +113,27 @@ type runLocalVars struct { type runLocalOpts struct { runLocalVars - sel deploySelector - ecsClient ecsClient - ecsExecutor ecsCommandExecutor - ssm secretGetter - secretsManager secretGetter - sessProvider sessionProvider - sess *session.Session - envManagerSess *session.Session - targetEnv *config.Environment - targetApp *config.Application - store store - ws wsWlDirReader - cmd execRunner - dockerEngine dockerEngineRunner - repository repositoryService - prog progress - orchestrator containerOrchestrator - hostFinder hostFinder - envChecker versionCompatibilityChecker - debounceTime time.Duration - dockerExcludes []string + sel deploySelector + ecsClient ecsClient + ecsExecutor ecsCommandExecutor + ssm secretGetter + secretsManager secretGetter + sessProvider sessionProvider + defaultConfig awsv2.Config + envManagerConfig awsv2.Config + targetEnv *config.Environment + targetApp *config.Application + store store + ws wsWlDirReader + cmd execRunner + dockerEngine dockerEngineRunner + repository repositoryService + prog progress + orchestrator containerOrchestrator + hostFinder hostFinder + envChecker versionCompatibilityChecker + debounceTime time.Duration + dockerExcludes []string newRecursiveWatcher func() (recursiveWatcher, error) buildContainerImages func(mft manifest.DynamicWorkload) (map[string]string, error) @@ -152,15 +148,12 @@ type runLocalOpts struct { func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("run local")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { return nil, err @@ -181,44 +174,37 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { newInterpolator: newManifestInterpolator, sessProvider: sessProvider, unmarshal: manifest.UnmarshalWorkload, - sess: defaultSess, + defaultConfig: defaultConfig, cmd: exec.NewCmd(), dockerEngine: dockerengine.New(exec.NewCmd()), labeledTermPrinter: labeledTermPrinter, prog: termprogress.NewSpinner(log.DiagnosticWriter), } o.configureClients = func() error { - defaultSessEnvRegion, err := o.sessProvider.DefaultWithRegion(o.targetEnv.Region) - if err != nil { - return fmt.Errorf("create default session with region %s: %w", o.targetEnv.Region, err) - } defaultConfigEnvRegion, err := o.sessProvider.DefaultConfigWithRegion(context.Background(), o.targetEnv.Region) if err != nil { return fmt.Errorf("create default config with region %s: %w", o.targetEnv.Region, err) } - o.envManagerSess, err = o.sessProvider.FromRole(o.targetEnv.ManagerRoleARN, o.targetEnv.Region) - if err != nil { - return fmt.Errorf("create env manager session %s: %w", o.targetEnv.Region, err) - } envManagerConfig, err := o.sessProvider.ConfigFromRole(context.Background(), o.targetEnv.ManagerRoleARN, o.targetEnv.Region) if err != nil { return fmt.Errorf("create env manager config %s: %w", o.targetEnv.Region, err) } + o.envManagerConfig = envManagerConfig // EnvManagerRole has permissions to get task def and get SSM values. // However, it doesn't have permissions to get secrets from secrets manager, - // so use the default sess and *hope* they have permissions. - o.ecsClient = ecs.New(o.envManagerSess, envManagerConfig) + // so use the default config and *hope* it has permissions. + o.ecsClient = ecs.New(envManagerConfig) o.ssm = ssm.New(envManagerConfig) o.ecsExecutor = awsecs.New(envManagerConfig) o.secretsManager = secretsmanager.New(defaultConfigEnvRegion) - resources, err := cloudformation.New(o.sess, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(o.targetApp, o.targetEnv.Region) + resources, err := cloudformation.New(o.defaultConfig, cloudformation.WithProgressTracker(os.Stderr)).GetAppResourcesByRegion(o.targetApp, o.targetEnv.Region) if err != nil { return fmt.Errorf("get application %s resources from region %s: %w", o.appName, o.envName, err) } repoName := clideploy.RepoName(o.appName, o.wkldName) - o.repository = repository.NewWithURI(ecr.New(v2ConfigFromSessionRegion(defaultSessEnvRegion)), repoName, resources.RepositoryURLs[o.wkldName]) + o.repository = repository.NewWithURI(ecr.New(defaultConfigEnvRegion), repoName, resources.RepositoryURLs[o.wkldName]) idPrefix := fmt.Sprintf("%s-%s-%s-", o.appName, o.envName, o.wkldName) colorGen := termcolor.ColorGenerator() @@ -234,9 +220,9 @@ func newRunLocalOpts(vars runLocalVars) (*runLocalOpts, error) { app: o.appName, env: o.envName, wkld: o.wkldName, - ecs: ecs.New(o.envManagerSess, envManagerConfig), + ecs: ecs.New(envManagerConfig), rg: resourcegroups.New(envManagerConfig), - rds: rds.New(o.envManagerSess), + rds: rds.NewFromConfig(envManagerConfig), } envDesc, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ App: o.appName, @@ -468,7 +454,7 @@ func (o *runLocalOpts) getSSMTarget(ctx context.Context) (string, error) { for _, task := range svc.Tasks { // TaskArn should have the format: arn:aws:ecs:us-west-2:123456789:task/clusterName/taskName - taskARN, err := arn.Parse(aws.StringValue(task.TaskArn)) + taskARN, err := awsarn.Parse(awsv2.ToString(task.TaskArn)) if err != nil { return "", fmt.Errorf("parse task arn: %w", err) } @@ -480,12 +466,12 @@ func (o *runLocalOpts) getSSMTarget(ctx context.Context) (string, error) { taskName := split[2] for _, ctr := range task.Containers { - id := aws.StringValue(ctr.RuntimeId) + id := awsv2.ToString(ctr.RuntimeId) hasECSExec := slices.ContainsFunc(ctr.ManagedAgents, func(a sdkecs.ManagedAgent) bool { - return string(a.Name) == "ExecuteCommandAgent" && aws.StringValue(a.LastStatus) == "RUNNING" + return string(a.Name) == "ExecuteCommandAgent" && awsv2.ToString(a.LastStatus) == "RUNNING" }) - if id != "" && hasECSExec && aws.StringValue(ctr.LastStatus) == "RUNNING" { - return fmt.Sprintf("ecs:%s_%s_%s", svc.ClusterName, taskName, aws.StringValue(ctr.RuntimeId)), nil + if id != "" && hasECSExec && awsv2.ToString(ctr.LastStatus) == "RUNNING" { + return fmt.Sprintf("ecs:%s_%s_%s", svc.ClusterName, taskName, awsv2.ToString(ctr.RuntimeId)), nil } } } @@ -528,7 +514,7 @@ func (o *runLocalOpts) getTask(ctx context.Context) (orchestrator.Task, error) { } if o.proxy { - pauseSecrets, err := sessionEnvVars(ctx, o.envManagerSess) + pauseSecrets, err := configEnvVars(ctx, o.envManagerConfig) if err != nil { return orchestrator.Task{}, fmt.Errorf("get pause container secrets: %w", err) } @@ -536,9 +522,9 @@ func (o *runLocalOpts) getTask(ctx context.Context) (orchestrator.Task, error) { } for _, ctr := range td.ContainerDefinitions { - name := aws.StringValue(ctr.Name) + name := awsv2.ToString(ctr.Name) def := orchestrator.ContainerDefinition{ - ImageURI: aws.StringValue(ctr.Image), + ImageURI: awsv2.ToString(ctr.Image), EnvVars: envVars[name].EnvVars(), Secrets: envVars[name].Secrets(), Ports: make(map[string]string, len(ctr.PortMappings)), @@ -582,7 +568,7 @@ func (o *runLocalOpts) prepareTask(ctx context.Context) (orchestrator.Task, erro ws: o.ws, interpolator: o.newInterpolator(o.appName, o.envName), unmarshal: o.unmarshal, - sess: o.envManagerSess, + cfg: o.envManagerConfig, }) if err != nil { return orchestrator.Task{}, err @@ -727,8 +713,8 @@ func (o *runLocalOpts) watchLocalFiles(stopCh <-chan struct{}) (<-chan interface return watchCh, watchErrCh, nil } -func sessionEnvVars(ctx context.Context, sess *session.Session) (map[string]string, error) { - creds, err := sess.Config.Credentials.GetWithContext(ctx) +func configEnvVars(ctx context.Context, cfg awsv2.Config) (map[string]string, error) { + creds, err := cfg.Credentials.Retrieve(ctx) if err != nil { return nil, fmt.Errorf("get IAM credentials: %w", err) } @@ -738,28 +724,27 @@ func sessionEnvVars(ctx context.Context, sess *session.Session) (map[string]stri "AWS_SECRET_ACCESS_KEY": creds.SecretAccessKey, "AWS_SESSION_TOKEN": creds.SessionToken, } - if sess.Config.Region != nil { - env["AWS_DEFAULT_REGION"] = aws.StringValue(sess.Config.Region) - env["AWS_REGION"] = aws.StringValue(sess.Config.Region) + if cfg.Region != "" { + env["AWS_DEFAULT_REGION"] = cfg.Region + env["AWS_REGION"] = cfg.Region } return env, nil } func (o *runLocalOpts) taskRoleCredentials(ctx context.Context) (map[string]string, error) { - // assumeRoleMethod tries to directly call sts:AssumeRole for TaskRole using default session - // calls sts:AssumeRole through aws-sdk-go here https://github.com/aws/aws-sdk-go/blob/ac58203a9054cc9d901429bdd94edfc0a7a1de46/aws/credentials/stscreds/assume_role_provider.go#L352 + // assumeRoleMethod tries to directly call sts:AssumeRole for TaskRole using the default config. assumeRoleMethod := func() (map[string]string, error) { taskDef, err := o.ecsClient.TaskDefinition(o.appName, o.envName, o.wkldName) if err != nil { return nil, err } - taskRoleSess, err := o.sessProvider.FromRole(aws.StringValue(taskDef.TaskRoleArn), o.targetEnv.Region) + taskRoleConfig, err := o.sessProvider.ConfigFromRole(ctx, awsv2.ToString(taskDef.TaskRoleArn), o.targetEnv.Region) if err != nil { return nil, err } - return sessionEnvVars(ctx, taskRoleSess) + return configEnvVars(ctx, taskRoleConfig) } // ecsExecMethod tries to use ECS Exec to retrive credentials from running container @@ -779,14 +764,14 @@ func (o *runLocalOpts) taskRoleCredentials(ctx context.Context) (map[string]stri var wg sync.WaitGroup containerErr := make(chan error) for _, task := range svcDesc.Tasks { - taskID, err := awsecs.TaskID(aws.StringValue(task.TaskArn)) + taskID, err := awsecs.TaskID(awsv2.ToString(task.TaskArn)) if err != nil { return nil, err } for _, container := range task.Containers { wg.Add(1) - containerName := aws.StringValue(container.Name) + containerName := awsv2.ToString(container.Name) go func() { defer wg.Done() err := o.ecsExecutor.ExecuteCommand(awsecs.ExecuteCommandInput{ @@ -928,7 +913,7 @@ func (c containerEnv) Secrets() map[string]string { func (o *runLocalOpts) getEnvVars(ctx context.Context, taskDef *awsecs.TaskDefinition) (map[string]containerEnv, error) { envVars := make(map[string]containerEnv, len(taskDef.ContainerDefinitions)) for _, ctr := range taskDef.ContainerDefinitions { - envVars[aws.StringValue(ctr.Name)] = make(map[string]envVarValue) + envVars[awsv2.ToString(ctr.Name)] = make(map[string]envVarValue) } for _, e := range taskDef.EnvironmentVariables() { @@ -946,7 +931,7 @@ func (o *runLocalOpts) getEnvVars(ctx context.Context, taskDef *awsecs.TaskDefin } // inject session variables if they haven't been already set - sessionVars, err := sessionEnvVars(ctx, o.sess) + sessionVars, err := configEnvVars(ctx, o.defaultConfig) if err != nil { return nil, err } @@ -1061,11 +1046,11 @@ func (o *runLocalOpts) getSecret(ctx context.Context, valueFrom string) (string, // SSM secrets can be specified as parameter name instead of an ARN. // Default to ssm if valueFrom is not an ARN. getter := o.ssm - if parsed, err := arn.Parse(valueFrom); err == nil { // only overwrite if successful + if parsed, err := awsarn.Parse(valueFrom); err == nil { // only overwrite if successful switch parsed.Service { - case sdkssm.ServiceName: + case "ssm": getter = o.ssm - case sdksecretsmanager.ServiceName: + case "secretsmanager": getter = o.secretsManager default: return "", fmt.Errorf("invalid ARN; not a SSM or Secrets Manager ARN") @@ -1084,13 +1069,13 @@ func (o *runLocalOpts) getContainerDependencies(taskDef *awsecs.TaskDefinition) dependencies := make(map[string]containerDependency, len(taskDef.ContainerDefinitions)) for _, ctr := range taskDef.ContainerDefinitions { dep := containerDependency{ - isEssential: aws.BoolValue(ctr.Essential), + isEssential: awsv2.ToBool(ctr.Essential), dependsOn: make(map[string]string), } for _, containerDep := range ctr.DependsOn { - dep.dependsOn[aws.StringValue(containerDep.ContainerName)] = strings.ToLower(string(containerDep.Condition)) + dep.dependsOn[awsv2.ToString(containerDep.ContainerName)] = strings.ToLower(string(containerDep.Condition)) } - dependencies[aws.StringValue(ctr.Name)] = dep + dependencies[awsv2.ToString(ctr.Name)] = dep } return dependencies } @@ -1115,7 +1100,7 @@ func (h *hostDiscoverer) Hosts(ctx context.Context) ([]orchestrator.Host, error) for _, svc := range svcs { // find the primary deployment with Service Connect enabled idx := slices.IndexFunc(svc.Deployments, func(dep sdkecs.Deployment) bool { - return aws.StringValue(dep.Status) == "PRIMARY" && dep.ServiceConnectConfiguration.Enabled + return awsv2.ToString(dep.Status) == "PRIMARY" && dep.ServiceConnectConfiguration.Enabled }) if idx == -1 { continue @@ -1124,7 +1109,7 @@ func (h *hostDiscoverer) Hosts(ctx context.Context) ([]orchestrator.Host, error) for _, sc := range svc.Deployments[idx].ServiceConnectConfiguration.Services { for _, alias := range sc.ClientAliases { hosts = append(hosts, orchestrator.Host{ - Name: aws.StringValue(alias.DnsName), + Name: awsv2.ToString(alias.DnsName), Port: uint16(awsv2.ToInt32(alias.Port)), }) } @@ -1155,11 +1140,11 @@ func (h *hostDiscoverer) rdsHosts(ctx context.Context) ([]orchestrator.Host, err return nil, nil } - dbFilter := &rds.Filter{ - Name: aws.String("db-instance-id"), + dbFilter := &rdstypes.Filter{ + Name: awsv2.String("db-instance-id"), } - clusterFilter := &rds.Filter{ - Name: aws.String("db-cluster-id"), + clusterFilter := &rdstypes.Filter{ + Name: awsv2.String("db-cluster-id"), } for i := range resources { // we don't want resources that belong to other services @@ -1168,48 +1153,54 @@ func (h *hostDiscoverer) rdsHosts(ctx context.Context) ([]orchestrator.Host, err continue } - arn, err := arn.Parse(resources[i].ARN) + arn, err := awsarn.Parse(resources[i].ARN) if err != nil { return nil, fmt.Errorf("invalid arn %q: %w", resources[i].ARN, err) } switch { case strings.HasPrefix(arn.Resource, "db:"): - dbFilter.Values = append(dbFilter.Values, aws.String(resources[i].ARN)) + dbFilter.Values = append(dbFilter.Values, resources[i].ARN) case strings.HasPrefix(arn.Resource, "cluster:"): - clusterFilter.Values = append(clusterFilter.Values, aws.String(resources[i].ARN)) + clusterFilter.Values = append(clusterFilter.Values, resources[i].ARN) } } if len(dbFilter.Values) > 0 { - err = h.rds.DescribeDBInstancesPagesWithContext(ctx, &rds.DescribeDBInstancesInput{ - Filters: []*rds.Filter{dbFilter}, - }, func(out *rds.DescribeDBInstancesOutput, lastPage bool) bool { + paginator := rds.NewDescribeDBInstancesPaginator(h.rds, &rds.DescribeDBInstancesInput{ + Filters: []rdstypes.Filter{*dbFilter}, + }) + for paginator.HasMorePages() { + out, err := paginator.NextPage(ctx) + if err != nil { + return nil, fmt.Errorf("describe instances: %w", err) + } for _, db := range out.DBInstances { if db.Endpoint != nil { hosts = append(hosts, orchestrator.Host{ - Name: aws.StringValue(db.Endpoint.Address), - Port: uint16(aws.Int64Value(db.Endpoint.Port)), + Name: awsv2.ToString(db.Endpoint.Address), + Port: uint16(awsv2.ToInt32(db.Endpoint.Port)), }) } } - return true - }) - if err != nil { - return nil, fmt.Errorf("describe instances: %w", err) } } if len(clusterFilter.Values) > 0 { - err = h.rds.DescribeDBClustersPagesWithContext(ctx, &rds.DescribeDBClustersInput{ - Filters: []*rds.Filter{clusterFilter}, - }, func(out *rds.DescribeDBClustersOutput, lastPage bool) bool { + paginator := rds.NewDescribeDBClustersPaginator(h.rds, &rds.DescribeDBClustersInput{ + Filters: []rdstypes.Filter{*clusterFilter}, + }) + for paginator.HasMorePages() { + out, err := paginator.NextPage(ctx) + if err != nil { + return nil, fmt.Errorf("describe clusters: %w", err) + } for _, db := range out.DBClusters { add := func(s *string) { if s != nil { hosts = append(hosts, orchestrator.Host{ - Name: aws.StringValue(s), - Port: uint16(aws.Int64Value(db.Port)), + Name: awsv2.ToString(s), + Port: uint16(awsv2.ToInt32(db.Port)), }) } } @@ -1217,13 +1208,9 @@ func (h *hostDiscoverer) rdsHosts(ctx context.Context) ([]orchestrator.Host, err add(db.Endpoint) add(db.ReaderEndpoint) for i := range db.CustomEndpoints { - add(db.CustomEndpoints[i]) + add(&db.CustomEndpoints[i]) } } - return true - }) - if err != nil { - return nil, fmt.Errorf("describe clusters: %w", err) } } diff --git a/internal/pkg/cli/run_local_test.go b/internal/pkg/cli/run_local_test.go index adf2da57ef8..b3b28a78b4a 100644 --- a/internal/pkg/cli/run_local_test.go +++ b/internal/pkg/cli/run_local_test.go @@ -23,12 +23,10 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/term/selector" + "github.com/aws/aws-sdk-go-v2/aws" sdkecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/rds" + "github.com/aws/aws-sdk-go-v2/service/rds" + rdstypes "github.com/aws/aws-sdk-go-v2/service/rds/types" "github.com/fsnotify/fsnotify" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -205,7 +203,7 @@ type runLocalExecuteMocks struct { ecsClient *mocks.MockecsClient ecsExecutor *mocks.MockecsCommandExecutor store *mocks.Mockstore - sessCreds credentials.Provider + sessCreds aws.CredentialsProvider sessProvider *mocks.MocksessionProvider interpolator *mocks.Mockinterpolator ws *mocks.MockwsWlDirReader @@ -223,15 +221,24 @@ type runLocalExecuteMocks struct { } type mockProvider struct { - FnRetrieve func() (credentials.Value, error) + FnRetrieve func(context.Context) (aws.Credentials, error) } -func (m *mockProvider) Retrieve() (credentials.Value, error) { - return m.FnRetrieve() +func (m *mockProvider) Retrieve(ctx context.Context) (aws.Credentials, error) { + return m.FnRetrieve(ctx) } -func (m *mockProvider) IsExpired() bool { - return false +func staticConfig(accessKeyID, secretAccessKey, sessionToken, region string) aws.Config { + return aws.Config{ + Credentials: aws.CredentialsProviderFunc(func(context.Context) (aws.Credentials, error) { + return aws.Credentials{ + AccessKeyID: accessKeyID, + SecretAccessKey: secretAccessKey, + SessionToken: sessionToken, + }, nil + }), + Region: region, + } } type hostFinderDouble struct { @@ -532,7 +539,7 @@ func TestRunLocalOpts_Execute(t *testing.T) { m.ecsClient.EXPECT().TaskDefinition(testAppName, testEnvName, testWkldName).Return(taskDef, nil) m.ssm.EXPECT().GetSecretValue(gomock.Any(), "mysecret").Return("secretvalue", nil) m.ecsClient.EXPECT().TaskDefinition(testAppName, testEnvName, testWkldName).Return(taskDef, nil) - m.sessProvider.EXPECT().FromRole("mock-arn", testRegion).Return(nil, errors.New("some error")) + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), "mock-arn", testRegion).Return(aws.Config{}, errors.New("some error")) m.ecsClient.EXPECT().DescribeService(testAppName, testEnvName, testWkldName).Return(&ecs.ServiceDesc{ Tasks: []*awsecs.Task{ { @@ -842,13 +849,8 @@ ecs exec: all containers failed to retrieve credentials`), m.ecsClient.EXPECT().TaskDefinition(testAppName, testEnvName, testWkldName).Return(taskDef, nil) m.ssm.EXPECT().GetSecretValue(gomock.Any(), "mysecret").Return("secretvalue", nil) m.ecsClient.EXPECT().TaskDefinition(testAppName, testEnvName, testWkldName).Return(taskDef, nil) - taskRoleSess := &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewStaticCredentials("myID", "mySecret", "myToken"), - Region: aws.String(testRegion), - }, - } - m.sessProvider.EXPECT().FromRole("mock-arn", testRegion).Return(taskRoleSess, nil) + taskRoleConfig := staticConfig("myID", "mySecret", "myToken", testRegion) + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), "mock-arn", testRegion).Return(taskRoleConfig, nil) m.ws.EXPECT().ReadWorkloadManifest(testWkldName).Return([]byte(""), nil) m.interpolator.EXPECT().Interpolate("").Return("", nil) @@ -876,7 +878,7 @@ ecs exec: all containers failed to retrieve credentials`), m.ecsClient.EXPECT().TaskDefinition(testAppName, testEnvName, testWkldName).Return(taskDef, nil) m.ssm.EXPECT().GetSecretValue(gomock.Any(), "mysecret").Return("secretvalue", nil) m.ecsClient.EXPECT().TaskDefinition(testAppName, testEnvName, testWkldName).Return(taskDef, nil) - m.sessProvider.EXPECT().FromRole("mock-arn", testRegion).Return(nil, errors.New("some error")) + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), "mock-arn", testRegion).Return(aws.Config{}, errors.New("some error")) m.ecsClient.EXPECT().DescribeService(testAppName, testEnvName, testWkldName).Return(&ecs.ServiceDesc{ Tasks: []*awsecs.Task{ { @@ -1181,34 +1183,26 @@ ecs exec: all containers failed to retrieve credentials`), buildContainerImages: func(mft manifest.DynamicWorkload) (map[string]string, error) { return mockContainerURIs, tc.buildImagesError }, - ws: m.ws, - ecsClient: m.ecsClient, - ecsExecutor: m.ecsExecutor, - ssm: m.ssm, - secretsManager: m.secretsManager, - store: m.store, - sessProvider: m.sessProvider, - sess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewStaticCredentials("myID", "mySecret", "myToken"), - }, - }, - envManagerSess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewStaticCredentials("myEnvID", "myEnvSecret", "myEnvToken"), - }, - }, - cmd: m.mockRunner, - dockerEngine: m.dockerEngine, - repository: m.repository, - targetEnv: &mockEnv, - targetApp: &mockApp, - prog: m.prog, - orchestrator: m.orchestrator, - hostFinder: m.hostFinder, - envChecker: m.envChecker, - debounceTime: 0, // disable debounce during testing - dockerExcludes: tc.inputDockerExcludes, + ws: m.ws, + ecsClient: m.ecsClient, + ecsExecutor: m.ecsExecutor, + ssm: m.ssm, + secretsManager: m.secretsManager, + store: m.store, + sessProvider: m.sessProvider, + defaultConfig: staticConfig("myID", "mySecret", "myToken", ""), + envManagerConfig: staticConfig("myEnvID", "myEnvSecret", "myEnvToken", ""), + cmd: m.mockRunner, + dockerEngine: m.dockerEngine, + repository: m.repository, + targetEnv: &mockEnv, + targetApp: &mockApp, + prog: m.prog, + orchestrator: m.orchestrator, + hostFinder: m.hostFinder, + envChecker: m.envChecker, + debounceTime: 0, // disable debounce during testing + dockerExcludes: tc.inputDockerExcludes, newRecursiveWatcher: func() (recursiveWatcher, error) { return m.watcher, nil }, @@ -1591,8 +1585,8 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { ssm: mocks.NewMocksecretGetter(ctrl), secretsManager: mocks.NewMocksecretGetter(ctrl), sessCreds: &mockProvider{ - FnRetrieve: func() (credentials.Value, error) { - return credentials.Value{ + FnRetrieve: func(context.Context) (aws.Credentials, error) { + return aws.Credentials{ AccessKeyID: "myID", SecretAccessKey: "mySecret", SessionToken: "myToken", @@ -1608,11 +1602,9 @@ func TestRunLocalOpts_getEnvVars(t *testing.T) { runLocalVars: runLocalVars{ envOverrides: tc.envOverrides, }, - sess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(m.sessCreds), - Region: tc.region, - }, + defaultConfig: aws.Config{ + Credentials: m.sessCreds, + Region: aws.ToString(tc.region), }, ssm: m.ssm, secretsManager: m.secretsManager, @@ -1641,22 +1633,22 @@ func (d *taggedResourceGetterDouble) GetResourcesByTags(resourceType string, tag } type rdsDescriberDouble struct { - DescribeDBInstancesPagesWithContextFn func(context.Context, *rds.DescribeDBInstancesInput, func(*rds.DescribeDBInstancesOutput, bool) bool, ...request.Option) error - DescribeDBClustersPagesWithContextFn func(context.Context, *rds.DescribeDBClustersInput, func(*rds.DescribeDBClustersOutput, bool) bool, ...request.Option) error + DescribeDBInstancesFn func(context.Context, *rds.DescribeDBInstancesInput, ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) + DescribeDBClustersFn func(context.Context, *rds.DescribeDBClustersInput, ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) } -func (d *rdsDescriberDouble) DescribeDBInstancesPagesWithContext(ctx context.Context, in *rds.DescribeDBInstancesInput, fn func(*rds.DescribeDBInstancesOutput, bool) bool, opts ...request.Option) error { - if d.DescribeDBInstancesPagesWithContextFn == nil { - return nil +func (d *rdsDescriberDouble) DescribeDBInstances(ctx context.Context, in *rds.DescribeDBInstancesInput, opts ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) { + if d.DescribeDBInstancesFn == nil { + return &rds.DescribeDBInstancesOutput{}, nil } - return d.DescribeDBInstancesPagesWithContextFn(ctx, in, fn, opts...) + return d.DescribeDBInstancesFn(ctx, in, opts...) } -func (d *rdsDescriberDouble) DescribeDBClustersPagesWithContext(ctx context.Context, in *rds.DescribeDBClustersInput, fn func(*rds.DescribeDBClustersOutput, bool) bool, opts ...request.Option) error { - if d.DescribeDBClustersPagesWithContextFn == nil { - return nil +func (d *rdsDescriberDouble) DescribeDBClusters(ctx context.Context, in *rds.DescribeDBClustersInput, opts ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) { + if d.DescribeDBClustersFn == nil { + return &rds.DescribeDBClustersOutput{}, nil } - return d.DescribeDBClustersPagesWithContextFn(ctx, in, fn, opts...) + return d.DescribeDBClustersFn(ctx, in, opts...) } func TestRunLocal_HostDiscovery(t *testing.T) { @@ -1793,8 +1785,8 @@ func TestRunLocal_HostDiscovery(t *testing.T) { }, }, nil } - m.rds.DescribeDBInstancesPagesWithContextFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, f func(*rds.DescribeDBInstancesOutput, bool) bool, o ...request.Option) error { - return errors.New("some error") + m.rds.DescribeDBInstancesFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, o ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) { + return nil, errors.New("some error") } }, wantError: "get rds hosts: describe instances: some error", @@ -1812,18 +1804,17 @@ func TestRunLocal_HostDiscovery(t *testing.T) { }, }, nil } - m.rds.DescribeDBInstancesPagesWithContextFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, f func(*rds.DescribeDBInstancesOutput, bool) bool, o ...request.Option) error { - f(&rds.DescribeDBInstancesOutput{ - DBInstances: []*rds.DBInstance{ + m.rds.DescribeDBInstancesFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, o ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) { + return &rds.DescribeDBInstancesOutput{ + DBInstances: []rdstypes.DBInstance{ { - Endpoint: &rds.Endpoint{ + Endpoint: &rdstypes.Endpoint{ Address: aws.String("db"), - Port: aws.Int64(3306), + Port: aws.Int32(3306), }, }, }, - }, true) - return nil + }, nil } }, wantHosts: []orchestrator.Host{ @@ -1853,21 +1844,20 @@ func TestRunLocal_HostDiscovery(t *testing.T) { }, }, nil } - m.rds.DescribeDBInstancesPagesWithContextFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, f func(*rds.DescribeDBInstancesOutput, bool) bool, o ...request.Option) error { - f(&rds.DescribeDBInstancesOutput{ - DBInstances: []*rds.DBInstance{ + m.rds.DescribeDBInstancesFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, o ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) { + return &rds.DescribeDBInstancesOutput{ + DBInstances: []rdstypes.DBInstance{ { - Endpoint: &rds.Endpoint{ + Endpoint: &rdstypes.Endpoint{ Address: aws.String("db"), - Port: aws.Int64(3306), + Port: aws.Int32(3306), }, }, }, - }, true) - return nil + }, nil } - m.rds.DescribeDBClustersPagesWithContextFn = func(ctx context.Context, ddi *rds.DescribeDBClustersInput, f func(*rds.DescribeDBClustersOutput, bool) bool, o ...request.Option) error { - return errors.New("some error") + m.rds.DescribeDBClustersFn = func(ctx context.Context, ddi *rds.DescribeDBClustersInput, o ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) { + return nil, errors.New("some error") } }, wantError: "get rds hosts: describe clusters: some error", @@ -1897,33 +1887,31 @@ func TestRunLocal_HostDiscovery(t *testing.T) { }, }, nil } - m.rds.DescribeDBInstancesPagesWithContextFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, f func(*rds.DescribeDBInstancesOutput, bool) bool, o ...request.Option) error { - f(&rds.DescribeDBInstancesOutput{ - DBInstances: []*rds.DBInstance{ + m.rds.DescribeDBInstancesFn = func(ctx context.Context, ddi *rds.DescribeDBInstancesInput, o ...func(*rds.Options)) (*rds.DescribeDBInstancesOutput, error) { + return &rds.DescribeDBInstancesOutput{ + DBInstances: []rdstypes.DBInstance{ { - Endpoint: &rds.Endpoint{ + Endpoint: &rdstypes.Endpoint{ Address: aws.String("db"), - Port: aws.Int64(3306), + Port: aws.Int32(3306), }, }, }, - }, true) - return nil + }, nil } - m.rds.DescribeDBClustersPagesWithContextFn = func(ctx context.Context, ddi *rds.DescribeDBClustersInput, f func(*rds.DescribeDBClustersOutput, bool) bool, o ...request.Option) error { - require.NotContains(t, ddi.Filters[0].Values, aws.String("arn:aws:rds:us-west-2:123456789:cluster:otherServiceCluster")) + m.rds.DescribeDBClustersFn = func(ctx context.Context, ddi *rds.DescribeDBClustersInput, o ...func(*rds.Options)) (*rds.DescribeDBClustersOutput, error) { + require.NotContains(t, ddi.Filters[0].Values, "arn:aws:rds:us-west-2:123456789:cluster:otherServiceCluster") - f(&rds.DescribeDBClustersOutput{ - DBClusters: []*rds.DBCluster{ + return &rds.DescribeDBClustersOutput{ + DBClusters: []rdstypes.DBCluster{ { Endpoint: aws.String("cluster"), - Port: aws.Int64(5432), + Port: aws.Int32(5432), ReaderEndpoint: aws.String("cluster-ro"), - CustomEndpoints: []*string{aws.String("cluster-custom")}, + CustomEndpoints: []string{"cluster-custom"}, }, }, - }, true) - return nil + }, nil } }, wantHosts: []orchestrator.Host{ diff --git a/internal/pkg/cli/svc_delete.go b/internal/pkg/cli/svc_delete.go index d97808d0ddd..696908a49f7 100644 --- a/internal/pkg/cli/svc_delete.go +++ b/internal/pkg/cli/svc_delete.go @@ -6,6 +6,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -29,7 +30,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" - awssession "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" ) @@ -66,9 +67,9 @@ type deleteSvcOpts struct { prompt prompter sel configSelector appCFN svcRemoverFromApp - getSvcCFN func(sess *awssession.Session) wlDeleter - getECR func(sess *awssession.Session) imageRemover - newSvcCleaner func(sess *awssession.Session, env *config.Environment, manifestType string) cleaner + getSvcCFN func(aws.Config) wlDeleter + getECR func(aws.Config) imageRemover + newSvcCleaner func(cfg aws.Config, env *config.Environment, manifestType string) cleaner } func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { @@ -91,17 +92,17 @@ func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { prompt: prompter, sess: sessProvider, sel: selector.NewConfigSelector(prompter, store), - appCFN: cloudformation.New(defaultSession, cloudformation.WithProgressTracker(os.Stderr)), - getSvcCFN: func(sess *awssession.Session) wlDeleter { - return cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) + appCFN: cloudformation.New(v2ConfigFromSessionRegion(defaultSession), cloudformation.WithProgressTracker(os.Stderr)), + getSvcCFN: func(cfg aws.Config) wlDeleter { + return cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) }, - getECR: func(sess *awssession.Session) imageRemover { - return ecr.New(v2ConfigFromSessionRegion(sess)) + getECR: func(cfg aws.Config) imageRemover { + return ecr.New(cfg) }, } - opts.newSvcCleaner = func(sess *awssession.Session, env *config.Environment, manifestType string) cleaner { + opts.newSvcCleaner = func(cfg aws.Config, env *config.Environment, manifestType string) cleaner { if manifestType == manifestinfo.StaticSiteType { - return clean.StaticSite(opts.appName, env.Name, opts.name, s3.New(sess, v2ConfigFromSessionRegion(sess)), awss3.New(v2ConfigFromSessionRegion(sess))) + return clean.StaticSite(opts.appName, env.Name, opts.name, s3.New(cfg), awss3.New(cfg)) } return &clean.NoOp{} } @@ -271,16 +272,16 @@ func (o *deleteSvcOpts) appEnvironments() ([]*config.Environment, error) { func (o *deleteSvcOpts) deleteStacks(wkldType string, envs []*config.Environment) error { for _, env := range envs { - sess, err := o.sess.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := o.sess.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } - if err := o.newSvcCleaner(sess, env, wkldType).Clean(); err != nil { + if err := o.newSvcCleaner(cfg, env, wkldType).Clean(); err != nil { return fmt.Errorf("clean resources: %w", err) } - cfClient := o.getSvcCFN(sess) + cfClient := o.getSvcCFN(cfg) if err := cfClient.DeleteWorkload(deploy.DeleteWorkloadInput{ Name: o.name, EnvName: env.Name, @@ -305,11 +306,11 @@ func (o *deleteSvcOpts) emptyECRRepos(envs []*config.Environment) error { // TODO: centralized ECR repo name repoName := clideploy.RepoName(o.appName, o.name) for _, region := range uniqueRegions { - sess, err := o.sess.DefaultWithRegion(region) + cfg, err := o.sess.DefaultConfigWithRegion(context.Background(), region) if err != nil { return err } - client := o.getECR(sess) + client := o.getECR(cfg) if err := client.ClearRepository(repoName); err != nil { return err } diff --git a/internal/pkg/cli/svc_delete_test.go b/internal/pkg/cli/svc_delete_test.go index 411f844531b..095c7018108 100644 --- a/internal/pkg/cli/svc_delete_test.go +++ b/internal/pkg/cli/svc_delete_test.go @@ -12,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -349,7 +349,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { appName: mockAppName, name: mockSvcName, }, - newSvcCleaner: func(*session.Session, *config.Environment, string) cleaner { + newSvcCleaner: func(aws.Config, *config.Environment, string) cleaner { return &cleantest.Succeeds{} }, }, @@ -362,11 +362,11 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { // appEnvironments mocks.store.EXPECT().ListEnvironments(gomock.Eq(mockAppName)).Times(1).Return(mockEnvs, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks mocks.svcCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), - mocks.sessProvider.EXPECT().DefaultWithRegion(gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().DefaultConfigWithRegion(gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // emptyECRRepos mocks.ecr.EXPECT().ClearRepository(mockRepo).Return(nil), @@ -391,7 +391,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { envName: mockEnvName, name: mockSvcName, }, - newSvcCleaner: func(*session.Session, *config.Environment, string) cleaner { + newSvcCleaner: func(aws.Config, *config.Environment, string) cleaner { return &cleantest.Succeeds{} }, }, @@ -404,7 +404,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { // appEnvironments mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks mocks.svcCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(nil), @@ -441,7 +441,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { envName: mockEnvName, name: mockSvcName, }, - newSvcCleaner: func(*session.Session, *config.Environment, string) cleaner { + newSvcCleaner: func(aws.Config, *config.Environment, string) cleaner { return &cleantest.Fails{} }, }, @@ -451,7 +451,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { Type: manifestinfo.LoadBalancedWebServiceType, }, nil), mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), ) }, wantedError: errors.New("clean resources: an error"), @@ -463,7 +463,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { envName: mockEnvName, name: mockSvcName, }, - newSvcCleaner: func(*session.Session, *config.Environment, string) cleaner { + newSvcCleaner: func(aws.Config, *config.Environment, string) cleaner { return &cleantest.Succeeds{} }, }, @@ -476,7 +476,7 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { // appEnvironments mocks.store.EXPECT().GetEnvironment(mockAppName, mockEnvName).Times(1).Return(mockEnv, nil), - mocks.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil), + mocks.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil), // deleteStacks mocks.svcCFN.EXPECT().DeleteWorkload(gomock.Any()).Return(testError), ) @@ -506,10 +506,10 @@ func TestDeleteSvcOpts_Execute(t *testing.T) { tc.opts.sess = mocks.sessProvider tc.opts.spinner = mocks.spinner tc.opts.appCFN = mocks.appCFN - tc.opts.getSvcCFN = func(_ *session.Session) wlDeleter { + tc.opts.getSvcCFN = func(_ aws.Config) wlDeleter { return mocks.svcCFN } - tc.opts.getECR = func(_ *session.Session) imageRemover { + tc.opts.getECR = func(_ aws.Config) imageRemover { return mocks.ecr } diff --git a/internal/pkg/cli/svc_deploy.go b/internal/pkg/cli/svc_deploy.go index cdbb9c5bdc1..65399f7ffdd 100644 --- a/internal/pkg/cli/svc_deploy.go +++ b/internal/pkg/cli/svc_deploy.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -20,7 +21,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "golang.org/x/mod/semver" @@ -79,7 +80,7 @@ type deploySvcOpts struct { // cached variables targetApp *config.Application targetEnv *config.Environment - envSess *session.Session + envConfig aws.Config svcType string appliedDynamicMft manifest.DynamicWorkload rawMft string @@ -226,7 +227,7 @@ func (o *deploySvcOpts) Execute() error { ws: o.ws, interpolator: o.newInterpolator(o.appName, o.envName), unmarshal: o.unmarshal, - sess: o.envSess, + cfg: o.envConfig, }) if err != nil { return err @@ -443,18 +444,18 @@ func (o *deploySvcOpts) configureClients() error { o.targetEnv = env // client to retrieve an application's resources created with CloudFormation. - defaultSess, err := o.sessProvider.Default() + defaultConfig, err := o.sessProvider.DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("create default session: %w", err) + return fmt.Errorf("create default config: %w", err) } - envSess, err := o.sessProvider.FromRole(env.ManagerRoleARN, env.Region) + envConfig, err := o.sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } - o.envSess = envSess + o.envConfig = envConfig // client to retrieve caller identity. - caller, err := identity.New(v2ConfigFromSessionRegion(defaultSess)).Get() + caller, err := identity.New(defaultConfig).Get() if err != nil { return fmt.Errorf("get identity: %w", err) } @@ -489,7 +490,7 @@ type workloadManifestInput struct { envName string ws wsWlDirReader interpolator interpolator - sess *session.Session + cfg aws.Config unmarshal func([]byte) (manifest.DynamicWorkload, error) } @@ -513,7 +514,7 @@ func workloadManifest(in *workloadManifestInput) (manifest.DynamicWorkload, stri if err := envMft.Validate(); err != nil { return nil, "", fmt.Errorf("validate manifest against environment %q: %w", in.envName, err) } - if err := envMft.Load(in.sess); err != nil { + if err := envMft.Load(in.cfg); err != nil { return nil, "", fmt.Errorf("load dynamic content: %w", err) } return envMft, interpolated, nil diff --git a/internal/pkg/cli/svc_deploy_test.go b/internal/pkg/cli/svc_deploy_test.go index 22d714a511c..d078b39a081 100644 --- a/internal/pkg/cli/svc_deploy_test.go +++ b/internal/pkg/cli/svc_deploy_test.go @@ -14,7 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" @@ -634,7 +634,7 @@ func (m *mockWorkloadMft) Validate() error { return nil } -func (m *mockWorkloadMft) Load(sess *session.Session) error { +func (m *mockWorkloadMft) Load(cfg aws.Config) error { return nil } diff --git a/internal/pkg/cli/svc_exec.go b/internal/pkg/cli/svc_exec.go index f53ae0cb15e..b3df4f1541b 100644 --- a/internal/pkg/cli/svc_exec.go +++ b/internal/pkg/cli/svc_exec.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "math/rand" @@ -21,8 +22,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" ) @@ -47,8 +47,8 @@ type svcExecOpts struct { execVars store store sel deploySelector - newSvcDescriber func(*session.Session) serviceDescriber - newCommandExecutor func(*session.Session) ecsCommandExecutor + newSvcDescriber func(aws.Config) serviceDescriber + newCommandExecutor func(aws.Config) ecsCommandExecutor ssmPluginManager ssmPluginManager prompter prompter sessProvider sessionProvider @@ -74,11 +74,11 @@ func newSvcExecOpts(vars execVars) (*svcExecOpts, error) { execVars: vars, store: ssmStore, sel: selector.NewDeploySelect(prompt.New(), ssmStore, deployStore), - newSvcDescriber: func(s *session.Session) serviceDescriber { - return ecs.New(s, v2ConfigFromSessionRegion(s)) + newSvcDescriber: func(cfg aws.Config) serviceDescriber { + return ecs.New(cfg) }, - newCommandExecutor: func(s *session.Session) ecsCommandExecutor { - return awsecs.New(v2ConfigFromSessionRegion(s)) + newCommandExecutor: func(cfg aws.Config) ecsCommandExecutor { + return awsecs.New(cfg) }, randInt: func(x int) int { return rand.Intn(x) @@ -114,11 +114,11 @@ func (o *svcExecOpts) Execute() error { if wkld.Type == manifestinfo.RequestDrivenWebServiceType { return fmt.Errorf("executing a command in a running container part of a service is not supported for services with type: '%s'", manifestinfo.RequestDrivenWebServiceType) } - sess, err := o.envSession() + cfg, err := o.envConfig() if err != nil { return err } - svcDesc, err := o.newSvcDescriber(sess).DescribeService(o.appName, o.envName, o.name) + svcDesc, err := o.newSvcDescriber(cfg).DescribeService(o.appName, o.envName, o.name) if err != nil { return fmt.Errorf("describe ECS service for %s in environment %s: %w", o.name, o.envName, err) } @@ -129,7 +129,7 @@ func (o *svcExecOpts) Execute() error { container := o.selectContainer() log.Infof("Execute %s in container %s in task %s.\n", color.HighlightCode(o.command), color.HighlightUserInput(container), color.HighlightResource(taskID)) - if err = o.newCommandExecutor(sess).ExecuteCommand(awsecs.ExecuteCommandInput{ + if err = o.newCommandExecutor(cfg).ExecuteCommand(awsecs.ExecuteCommandInput{ Cluster: svcDesc.ClusterName, Command: o.command, Container: container, @@ -181,12 +181,12 @@ func (o *svcExecOpts) validateAndAskSvcEnvName() error { return nil } -func (o *svcExecOpts) envSession() (*session.Session, error) { +func (o *svcExecOpts) envConfig() (aws.Config, error) { env, err := o.store.GetEnvironment(o.appName, o.envName) if err != nil { - return nil, fmt.Errorf("get environment %s: %w", o.envName, err) + return aws.Config{}, fmt.Errorf("get environment %s: %w", o.envName, err) } - return o.sessProvider.FromRole(env.ManagerRoleARN, env.Region) + return o.sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) } func (o *svcExecOpts) selectTask(tasks []*awsecs.Task) (string, error) { @@ -195,7 +195,7 @@ func (o *svcExecOpts) selectTask(tasks []*awsecs.Task) (string, error) { } if o.taskID != "" { for _, task := range tasks { - taskID, err := awsecs.TaskID(aws.StringValue(task.TaskArn)) + taskID, err := awsecs.TaskID(aws.ToString(task.TaskArn)) if err != nil { return "", err } @@ -205,7 +205,7 @@ func (o *svcExecOpts) selectTask(tasks []*awsecs.Task) (string, error) { } return "", fmt.Errorf("found no running task whose ID is prefixed with %s", o.taskID) } - taskID, err := awsecs.TaskID(aws.StringValue(tasks[o.randInt(len(tasks))].TaskArn)) + taskID, err := awsecs.TaskID(aws.ToString(tasks[o.randInt(len(tasks))].TaskArn)) if err != nil { return "", err } @@ -221,7 +221,7 @@ func (o *svcExecOpts) selectContainer() string { } func validateSSMBinary(prompt prompter, manager ssmPluginManager, skipConfirmation *bool) error { - if skipConfirmation != nil && !aws.BoolValue(skipConfirmation) { + if skipConfirmation != nil && !aws.ToBool(skipConfirmation) { return nil } err := manager.ValidateBinary() diff --git a/internal/pkg/cli/svc_exec_test.go b/internal/pkg/cli/svc_exec_test.go index f3b07d50a34..e64d5412229 100644 --- a/internal/pkg/cli/svc_exec_test.go +++ b/internal/pkg/cli/svc_exec_test.go @@ -14,8 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/exec" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -451,11 +450,7 @@ func TestSvcExec_Execute(t *testing.T) { m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), - m.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), m.ecsSvcDescriber.EXPECT().DescribeService("mockApp", "mockEnv", "mockSvc").Return(nil, mockError), ) }, @@ -468,11 +463,7 @@ func TestSvcExec_Execute(t *testing.T) { m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), - m.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), m.ecsSvcDescriber.EXPECT().DescribeService("mockApp", "mockEnv", "mockSvc").Return(&ecs.ServiceDesc{ Tasks: []*awsecs.Task{}, }, nil), @@ -488,11 +479,7 @@ func TestSvcExec_Execute(t *testing.T) { m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), - m.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), m.ecsSvcDescriber.EXPECT().DescribeService("mockApp", "mockEnv", "mockSvc").Return(&ecs.ServiceDesc{ Tasks: []*awsecs.Task{ { @@ -513,11 +500,7 @@ func TestSvcExec_Execute(t *testing.T) { m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), - m.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), m.ecsSvcDescriber.EXPECT().DescribeService("mockApp", "mockEnv", "mockSvc").Return(&ecs.ServiceDesc{ ClusterName: "mockCluster", Tasks: []*awsecs.Task{ @@ -544,11 +527,7 @@ func TestSvcExec_Execute(t *testing.T) { m.storeSvc.EXPECT().GetEnvironment("mockApp", "mockEnv").Return(&config.Environment{ Name: "my-env", }, nil), - m.sessProvider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil), + m.sessProvider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{Region: "mockRegion"}, nil), m.ecsSvcDescriber.EXPECT().DescribeService("mockApp", "mockEnv", "mockSvc").Return(&ecs.ServiceDesc{ ClusterName: "mockCluster", Tasks: []*awsecs.Task{ @@ -582,10 +561,10 @@ func TestSvcExec_Execute(t *testing.T) { mockSvcDescriber := mocks.NewMockserviceDescriber(ctrl) mockCommandExecutor := mocks.NewMockecsCommandExecutor(ctrl) mockSessionProvider := mocks.NewMocksessionProvider(ctrl) - mockNewSvcDescriber := func(_ *session.Session) serviceDescriber { + mockNewSvcDescriber := func(_ aws.Config) serviceDescriber { return mockSvcDescriber } - mockNewCommandExecutor := func(_ *session.Session) ecsCommandExecutor { + mockNewCommandExecutor := func(_ aws.Config) ecsCommandExecutor { return mockCommandExecutor } diff --git a/internal/pkg/cli/svc_init.go b/internal/pkg/cli/svc_init.go index 3b762fba645..b9fb0cf2a8d 100644 --- a/internal/pkg/cli/svc_init.go +++ b/internal/pkg/cli/svc_init.go @@ -18,7 +18,7 @@ import ( "github.com/dustin/go-humanize/english" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerfile" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" @@ -207,7 +207,7 @@ func newInitSvcOpts(vars initSvcVars) (*initSvcOpts, error) { Store: store, Ws: ws, Prog: termprogress.NewSpinner(log.DiagnosticWriter), - Deployer: cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)), + Deployer: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), } dfSel, err := selector.NewDockerfileSelector(prompter, fs) if err != nil { diff --git a/internal/pkg/cli/svc_init_test.go b/internal/pkg/cli/svc_init_test.go index 3908c3ae6e2..408c618c233 100644 --- a/internal/pkg/cli/svc_init_test.go +++ b/internal/pkg/cli/svc_init_test.go @@ -16,7 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/initialize" diff --git a/internal/pkg/cli/svc_logs.go b/internal/pkg/cli/svc_logs.go index 63ce8b94941..ee2eed39607 100644 --- a/internal/pkg/cli/svc_logs.go +++ b/internal/pkg/cli/svc_logs.go @@ -22,7 +22,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" ) @@ -115,21 +115,17 @@ func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { if err != nil { return fmt.Errorf("get environment: %w", err) } - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) - if err != nil { - return err - } cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } - opts.ecs = ecs.New(sess, cfg) + opts.ecs = ecs.New(cfg) newWorkloadLoggerOpts := &logging.NewWorkloadLoggerOpts{ App: opts.appName, Env: opts.envName, Name: opts.name, - Sess: sess, + Cfg: cfg, } if opts.targetSvcType != manifestinfo.RequestDrivenWebServiceType { opts.logsSvc = logging.NewECSServiceClient(newWorkloadLoggerOpts) @@ -249,9 +245,9 @@ func (o *svcLogsOpts) latestStoppedTaskID() (string, error) { } if len(svcDesc.StoppedTasks) > 0 { sort.Slice(svcDesc.StoppedTasks, func(i, j int) bool { - return svcDesc.StoppedTasks[i].StoppingAt.After(aws.TimeValue(svcDesc.StoppedTasks[j].StoppingAt)) + return svcDesc.StoppedTasks[i].StoppingAt.After(aws.ToTime(svcDesc.StoppedTasks[j].StoppingAt)) }) - taskID, err := awsecs.TaskID(aws.StringValue(svcDesc.StoppedTasks[0].TaskArn)) + taskID, err := awsecs.TaskID(aws.ToString(svcDesc.StoppedTasks[0].TaskArn)) if err != nil { return "", err } diff --git a/internal/pkg/cli/svc_logs_test.go b/internal/pkg/cli/svc_logs_test.go index 394841aedff..5e0119263d9 100644 --- a/internal/pkg/cli/svc_logs_test.go +++ b/internal/pkg/cli/svc_logs_test.go @@ -12,7 +12,7 @@ import ( awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/ecs" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" diff --git a/internal/pkg/cli/svc_package.go b/internal/pkg/cli/svc_package.go index d30ca4e395e..cd8682926d4 100644 --- a/internal/pkg/cli/svc_package.go +++ b/internal/pkg/cli/svc_package.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -17,7 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/exec" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -72,7 +73,7 @@ type packageSvcOpts struct { // cached variables targetApp *config.Application targetEnv *config.Environment - envSess *session.Session + envConfig aws.Config rawMft string appliedDynamicMft manifest.DynamicWorkload rootUserARN string @@ -295,21 +296,21 @@ func (o *packageSvcOpts) validateOrAskEnvName() error { func (o *packageSvcOpts) configureClients() error { o.gitShortCommit = imageTagFromGit(o.runner) // Best effort assign git tag. // client to retrieve an application's resources created with CloudFormation. - defaultSess, err := o.sessProvider.Default() + defaultConfig, err := o.sessProvider.DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("create default session: %w", err) + return fmt.Errorf("create default config: %w", err) } targetEnv, err := o.getTargetEnv() if err != nil { return err } - envSess, err := o.sessProvider.FromRole(targetEnv.ManagerRoleARN, targetEnv.Region) + envConfig, err := o.sessProvider.ConfigFromRole(context.Background(), targetEnv.ManagerRoleARN, targetEnv.Region) if err != nil { return err } - o.envSess = envSess + o.envConfig = envConfig // client to retrieve caller identity. - caller, err := identity.New(v2ConfigFromSessionRegion(defaultSess)).Get() + caller, err := identity.New(defaultConfig).Get() if err != nil { return fmt.Errorf("get identity: %w", err) } @@ -351,7 +352,7 @@ func (o *packageSvcOpts) getStackGenerator(env *config.Environment) (workloadSta ws: o.ws, interpolator: o.newInterpolator(o.appName, o.envName), unmarshal: o.unmarshal, - sess: o.envSess, + cfg: o.envConfig, }) if err != nil { return nil, err diff --git a/internal/pkg/cli/task_delete.go b/internal/pkg/cli/task_delete.go index 61433971319..9c312c7872f 100644 --- a/internal/pkg/cli/task_delete.go +++ b/internal/pkg/cli/task_delete.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -23,8 +24,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" ) @@ -60,14 +60,15 @@ type deleteTaskOpts struct { sel wsSelector // Generators for env-specific clients - newTaskSel func(session *session.Session) cfTaskSelector - newTaskStopper func(session *session.Session) taskStopper - newImageRemover func(session *session.Session) imageRemover - newBucketEmptier func(session *session.Session) bucketEmptier - newStackManager func(session *session.Session) taskStackManager + newTaskSel func(aws.Config) cfTaskSelector + newTaskStopper func(aws.Config) taskStopper + newImageRemover func(aws.Config) imageRemover + newBucketEmptier func(aws.Config) bucketEmptier + newStackManager func(aws.Config) taskStackManager // Cached variables - session *session.Session + cfg aws.Config + hasConfig bool stackInfo *deploy.TaskStackInfo } @@ -97,21 +98,21 @@ func newDeleteTaskOpts(vars deleteTaskVars) (*deleteTaskOpts, error) { prompt: prompter, provider: sessProvider, sel: selector.NewLocalWorkloadSelector(prompter, store, ws, selector.OnlyInitializedWorkloads), - newTaskSel: func(session *session.Session) cfTaskSelector { - cfn := cloudformation.New(session, cloudformation.WithProgressTracker(os.Stderr)) + newTaskSel: func(cfg aws.Config) cfTaskSelector { + cfn := cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) return selector.NewCFTaskSelect(prompter, store, cfn) }, - newTaskStopper: func(session *session.Session) taskStopper { - return ecs.New(session, v2ConfigFromSessionRegion(session)) + newTaskStopper: func(cfg aws.Config) taskStopper { + return ecs.New(cfg) }, - newStackManager: func(session *session.Session) taskStackManager { - return cloudformation.New(session, cloudformation.WithProgressTracker(os.Stderr)) + newStackManager: func(cfg aws.Config) taskStackManager { + return cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) }, - newImageRemover: func(session *session.Session) imageRemover { - return ecr.New(v2ConfigFromSessionRegion(session)) + newImageRemover: func(cfg aws.Config) imageRemover { + return ecr.New(cfg) }, - newBucketEmptier: func(session *session.Session) bucketEmptier { - return s3.New(v2ConfigFromSessionRegion(session)) + newBucketEmptier: func(cfg aws.Config) bucketEmptier { + return s3.New(cfg) }, }, nil } @@ -284,29 +285,31 @@ func (o *deleteTaskOpts) Ask() error { return nil } -func (o *deleteTaskOpts) getSession() (*session.Session, error) { - if o.session != nil { - return o.session, nil +func (o *deleteTaskOpts) getConfig() (aws.Config, error) { + if o.hasConfig { + return o.cfg, nil } if o.defaultCluster { - sess, err := o.provider.Default() + cfg, err := o.provider.DefaultConfig(context.Background()) if err != nil { - return nil, err + return aws.Config{}, err } - o.session = sess - return sess, nil + o.cfg = cfg + o.hasConfig = true + return cfg, nil } // Get environment manager role for deleting stack. env, err := o.store.GetEnvironment(o.app, o.env) if err != nil { - return nil, err + return aws.Config{}, err } - sess, err := o.provider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := o.provider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return nil, err + return aws.Config{}, err } - o.session = sess - return sess, nil + o.cfg = cfg + o.hasConfig = true + return cfg, nil } func (o *deleteTaskOpts) askTaskName() error { @@ -314,11 +317,11 @@ func (o *deleteTaskOpts) askTaskName() error { return nil } - sess, err := o.getSession() + cfg, err := o.getConfig() if err != nil { return fmt.Errorf("get task select session: %w", err) } - sel := o.newTaskSel(sess) + sel := o.newTaskSel(cfg) if o.defaultCluster { task, err := sel.Task(taskDeleteNamePrompt, "", selector.TaskWithDefaultCluster()) if err != nil { @@ -349,7 +352,7 @@ func (o *deleteTaskOpts) Execute() error { } func (o *deleteTaskOpts) stopTasks() error { - sess, err := o.getSession() + cfg, err := o.getConfig() if err != nil { return fmt.Errorf("get session: %w", err) } @@ -358,12 +361,12 @@ func (o *deleteTaskOpts) stopTasks() error { // Stop tasks. if o.defaultCluster { - if err = o.newTaskStopper(sess).StopDefaultClusterTasks(o.name); err != nil { + if err = o.newTaskStopper(cfg).StopDefaultClusterTasks(o.name); err != nil { o.spinner.Stop(log.Serrorln("Error stopping running tasks in default cluster.")) return fmt.Errorf("stop running tasks in family %s: %w", o.name, err) } } else { - if err = o.newTaskStopper(sess).StopOneOffTasks(o.app, o.env, o.name); err != nil { + if err = o.newTaskStopper(cfg).StopOneOffTasks(o.app, o.env, o.name); err != nil { o.spinner.Stop(log.Serrorln("Error stopping running tasks in environment.")) return fmt.Errorf("stop running tasks in family %s: %w", o.name, err) } @@ -375,27 +378,21 @@ func (o *deleteTaskOpts) stopTasks() error { func (o *deleteTaskOpts) clearECRRepository() error { // ECR Deletion happens from the default profile in app delete. We can do it here too by getting // a default session in whichever region we're deleting from. - var defaultSess *session.Session - var err error - defaultSess, err = o.getSession() + defaultConfig, err := o.getConfig() if err != nil { return err } if !o.defaultCluster { - regionalSession, err := o.getSession() - if err != nil { - return err - } - defaultSess, err = o.provider.DefaultWithRegion(aws.StringValue(regionalSession.Config.Region)) + defaultConfig, err = o.provider.DefaultConfigWithRegion(context.Background(), defaultConfig.Region) if err != nil { - return fmt.Errorf("get default session for ECR deletion: %s", err) + return fmt.Errorf("get default config for ECR deletion: %s", err) } } // Best effort to construct ECR repo name. ecrRepoName := fmt.Sprintf(deploy.FmtTaskECRRepoName, o.name) o.spinner.Start(fmt.Sprintf("Emptying ECR repository for task %s.", color.HighlightUserInput(o.name))) - err = o.newImageRemover(defaultSess).ClearRepository(ecrRepoName) + err = o.newImageRemover(defaultConfig).ClearRepository(ecrRepoName) if err != nil { o.spinner.Stop(log.Serrorln("Error emptying ECR repository.")) return fmt.Errorf("empty ECR repository for task %s: %w", o.name, err) @@ -407,7 +404,11 @@ func (o *deleteTaskOpts) clearECRRepository() error { func (o *deleteTaskOpts) emptyS3Bucket(info *deploy.TaskStackInfo) error { o.spinner.Start(fmt.Sprintf("Emptying S3 bucket for task %s.", color.HighlightUserInput(o.name))) - err := o.newBucketEmptier(o.session).EmptyBucket(info.BucketName) + cfg, err := o.getConfig() + if err != nil { + return err + } + err = o.newBucketEmptier(cfg).EmptyBucket(info.BucketName) if err != nil { o.spinner.Stop(log.Serrorln("Error emptying S3 bucket.")) return fmt.Errorf("empty S3 bucket for task %s: %w", o.name, err) @@ -423,11 +424,11 @@ func (o *deleteTaskOpts) getTaskInfo() (*deploy.TaskStackInfo, error) { if o.stackInfo != nil { return o.stackInfo, nil } - sess, err := o.getSession() + cfg, err := o.getConfig() if err != nil { return nil, err } - info, err := o.newStackManager(sess).GetTaskStack(o.name) + info, err := o.newStackManager(cfg).GetTaskStack(o.name) if err != nil { return nil, err @@ -437,7 +438,7 @@ func (o *deleteTaskOpts) getTaskInfo() (*deploy.TaskStackInfo, error) { } func (o *deleteTaskOpts) deleteStack() error { - sess, err := o.getSession() + cfg, err := o.getConfig() if err != nil { return err } @@ -460,7 +461,7 @@ func (o *deleteTaskOpts) deleteStack() error { } } o.spinner.Start(fmt.Sprintf("Deleting CloudFormation stack for task %s.", color.HighlightUserInput(o.name))) - err = o.newStackManager(sess).DeleteTask(*info) + err = o.newStackManager(cfg).DeleteTask(*info) if err != nil { o.spinner.Stop(log.Serrorln("Error deleting CloudFormation stack.")) return fmt.Errorf("delete stack for task %s: %w", o.name, err) diff --git a/internal/pkg/cli/task_delete_test.go b/internal/pkg/cli/task_delete_test.go index 43b88c714a1..74d01e4a893 100644 --- a/internal/pkg/cli/task_delete_test.go +++ b/internal/pkg/cli/task_delete_test.go @@ -8,9 +8,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "testing" - "github.com/aws/aws-sdk-go/aws" - - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" awscfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" @@ -65,7 +63,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.cfn.EXPECT().GetTaskStack("oneoff") }, want: nil, @@ -79,7 +77,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { m.store.EXPECT().GetApplication("phonetool").Return(&config.Application{Name: "phonetool"}, nil) m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) m.store.EXPECT().GetEnvironment("phonetool", "test").Return(&config.Environment{Name: "test", App: "phonetool"}, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.cfn.EXPECT().GetTaskStack("oneoff").Return(nil, errors.New("some error")) }, }, @@ -87,7 +85,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { inDefaultCluster: true, inName: "oneoff", setupMocks: func(m validateMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.cfn.EXPECT().GetTaskStack("oneoff") }, want: nil, @@ -133,7 +131,7 @@ func TestDeleteTaskOpts_Validate(t *testing.T) { defaultCluster: tc.inDefaultCluster, }, store: mockstore, - newStackManager: func(_ *session.Session) taskStackManager { + newStackManager: func(_ aws.Config) taskStackManager { return mocktaskStackManager }, provider: mocks.provider, @@ -194,7 +192,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) }, mockSess: func(m *mocks.MocksessionProvider) { - m.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil) + m.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) }, mockPrompter: func(m *mocks.Mockprompter) { m.EXPECT().Confirm("Are you sure you want to delete abc from application phonetool and environment test?", gomock.Any(), gomock.Any()).Return(true, nil) @@ -213,7 +211,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) }, mockSess: func(m *mocks.MocksessionProvider) { - m.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil) + m.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) }, mockPrompter: func(m *mocks.Mockprompter) { m.EXPECT().Confirm("Are you sure you want to delete abc from application phonetool and environment test?", gomock.Any(), gomock.Any()).Return(false, nil) @@ -230,7 +228,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) }, mockSess: func(m *mocks.MocksessionProvider) { - m.EXPECT().Default().Return(&session.Session{}, nil) + m.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, mockPrompter: func(m *mocks.Mockprompter) { m.EXPECT().Confirm("Are you sure you want to delete abc from the default cluster?", gomock.Any(), gomock.Any()).Return(true, nil) @@ -249,7 +247,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) }, mockSess: func(m *mocks.MocksessionProvider) { - m.EXPECT().FromRole(gomock.Any(), gomock.Any()).Return(&session.Session{}, nil) + m.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) }, mockPrompter: func(m *mocks.Mockprompter) { m.EXPECT().Confirm("Are you sure you want to delete abc from application phonetool and environment test?", gomock.Any(), gomock.Any()).Return(true, nil) @@ -264,7 +262,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { m.EXPECT().Task(taskDeleteNamePrompt, "", gomock.Any()).Return("abc", nil) }, mockSess: func(m *mocks.MocksessionProvider) { - m.EXPECT().Default().Return(&session.Session{}, nil) + m.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, mockPrompter: func(m *mocks.Mockprompter) { m.EXPECT().Confirm("Are you sure you want to delete abc from the default cluster?", gomock.Any(), gomock.Any()).Return(true, nil) @@ -304,7 +302,7 @@ func TestDeleteTaskOpts_Ask(t *testing.T) { provider: mockSess, prompt: mockPrompt, - newTaskSel: func(sess *session.Session) cfTaskSelector { return mockTaskSel }, + newTaskSel: func(aws.Config) cfTaskSelector { return mockTaskSel }, } // WHEN @@ -377,12 +375,8 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { inName: mockTaskName, setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) - m.sess.EXPECT().DefaultWithRegion("mockRegion").Return(&session.Session{}, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) + m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -407,7 +401,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { setupMocks: func(m deleteTaskMocks) { gomock.InOrder( - m.sess.EXPECT().Default().Return(&session.Session{}, nil), + m.sess.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopDefaultClusterTasks(mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -430,7 +424,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { setupMocks: func(m deleteTaskMocks) { gomock.InOrder( - m.sess.EXPECT().Default().Return(&session.Session{}, nil), + m.sess.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil), m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopDefaultClusterTasks(mockTaskName).Return(nil), m.spinner.EXPECT().Stop(gomock.Any()), @@ -465,12 +459,8 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { wantedErr: errors.New("delete stack for task hide-snacks: some error"), setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) - m.sess.EXPECT().DefaultWithRegion("mockRegion").Return(&session.Session{}, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) + m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -496,12 +486,8 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { setupMocks: func(m deleteTaskMocks) { mockErrStackNotFound := awscfn.ErrStackNotFound{} - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) - m.sess.EXPECT().DefaultWithRegion("mockRegion").Return(&session.Session{}, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) + m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -522,12 +508,8 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { wantedErr: errors.New("empty ECR repository for task hide-snacks: some error"), setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) - m.sess.EXPECT().DefaultWithRegion("mockRegion").Return(&session.Session{}, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) + m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -547,12 +529,8 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { wantedErr: errors.New("empty S3 bucket for task hide-snacks: some error"), setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) - m.sess.EXPECT().DefaultWithRegion("mockRegion").Return(&session.Session{}, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) + m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -576,11 +554,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { wantedErr: errors.New("stop running tasks in family hide-snacks: some error"), setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -597,12 +571,8 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { wantedErr: errors.New("some error"), setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().FromRole(mockEnv.ManagerRoleARN, mockEnv.Region).Return(&session.Session{ - Config: &aws.Config{ - Region: aws.String("mockRegion"), - }, - }, nil) - m.sess.EXPECT().DefaultWithRegion("mockRegion").Return(&session.Session{}, nil) + m.sess.EXPECT().ConfigFromRole(gomock.Any(), mockEnv.ManagerRoleARN, mockEnv.Region).Return(aws.Config{Region: "mockRegion"}, nil) + m.sess.EXPECT().DefaultConfigWithRegion(gomock.Any(), "mockRegion").Return(aws.Config{}, nil) gomock.InOrder( m.store.EXPECT().GetEnvironment(mockApp, mockEnvName).Return(mockEnv, nil), m.spinner.EXPECT().Start(gomock.Any()), @@ -622,7 +592,7 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { wantedErr: errors.New("stop running tasks in family hide-snacks: some error"), setupMocks: func(m deleteTaskMocks) { - m.sess.EXPECT().Default().Return(&session.Session{}, nil) + m.sess.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) gomock.InOrder( m.spinner.EXPECT().Start(gomock.Any()), m.ecs.EXPECT().StopDefaultClusterTasks(mockTaskName).Return(mockError), @@ -647,16 +617,16 @@ func TestDeleteTaskOpts_Execute(t *testing.T) { mockSession := mocks.NewMocksessionProvider(ctrl) mockSpinner := mocks.NewMockprogress(ctrl) - mockGetECR := func(_ *session.Session) imageRemover { + mockGetECR := func(_ aws.Config) imageRemover { return mockECR } - mockGetS3 := func(_ *session.Session) bucketEmptier { + mockGetS3 := func(_ aws.Config) bucketEmptier { return mockS3 } - mockGetECS := func(_ *session.Session) taskStopper { + mockGetECS := func(_ aws.Config) taskStopper { return mockECS } - mockGetCFN := func(_ *session.Session) taskStackManager { + mockGetCFN := func(_ aws.Config) taskStackManager { return mockCFN } diff --git a/internal/pkg/cli/task_exec.go b/internal/pkg/cli/task_exec.go index fb7b29b4a8d..cbaddebe545 100644 --- a/internal/pkg/cli/task_exec.go +++ b/internal/pkg/cli/task_exec.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "github.com/aproint/copilot-cli/cmd/copilot/template" @@ -15,8 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/cobra" ) @@ -45,9 +45,9 @@ type taskExecOpts struct { store store ssmPluginManager ssmPluginManager prompter prompter - newTaskSel func(*session.Session) runningTaskSelector + newTaskSel func(aws.Config) runningTaskSelector configSel appEnvSelector - newCommandExecutor func(*session.Session) ecsCommandExecutor + newCommandExecutor func(aws.Config) ecsCommandExecutor provider sessionProvider task *awsecs.Task @@ -70,12 +70,12 @@ func newTaskExecOpts(vars taskExecVars) (*taskExecOpts, error) { store: ssmStore, ssmPluginManager: exec.NewSSMPluginCommand(""), prompter: prompter, - newTaskSel: func(sess *session.Session) runningTaskSelector { - return selector.NewTaskSelector(prompter, ecs.New(sess, v2ConfigFromSessionRegion(sess))) + newTaskSel: func(cfg aws.Config) runningTaskSelector { + return selector.NewTaskSelector(prompter, ecs.New(cfg)) }, configSel: selector.NewConfigSelector(prompter, ssmStore), - newCommandExecutor: func(s *session.Session) ecsCommandExecutor { - return awsecs.New(v2ConfigFromSessionRegion(s)) + newCommandExecutor: func(cfg aws.Config) ecsCommandExecutor { + return awsecs.New(cfg) }, provider: sessProvider, }, nil @@ -131,18 +131,18 @@ func (o *taskExecOpts) Ask() error { // Execute executes a command in a running container. func (o *taskExecOpts) Execute() error { - sess, err := o.configSession() + cfg, err := o.config() if err != nil { return err } - cluster, container := aws.StringValue(o.task.ClusterArn), aws.StringValue(o.task.Containers[0].Name) - taskID, err := awsecs.TaskID(aws.StringValue(o.task.TaskArn)) + cluster, container := aws.ToString(o.task.ClusterArn), aws.ToString(o.task.Containers[0].Name) + taskID, err := awsecs.TaskID(aws.ToString(o.task.TaskArn)) if err != nil { - return fmt.Errorf("parse task ARN %s: %w", aws.StringValue(o.task.TaskArn), err) + return fmt.Errorf("parse task ARN %s: %w", aws.ToString(o.task.TaskArn), err) } log.Infof("Execute %s in container %s in task %s.\n", color.HighlightCode(o.command), color.HighlightUserInput(container), color.HighlightResource(taskID)) - if err = o.newCommandExecutor(sess).ExecuteCommand(awsecs.ExecuteCommandInput{ + if err = o.newCommandExecutor(cfg).ExecuteCommand(awsecs.ExecuteCommandInput{ Cluster: cluster, Command: o.command, Container: container, @@ -154,11 +154,11 @@ func (o *taskExecOpts) Execute() error { } func (o *taskExecOpts) selectTaskInDefaultCluster() error { - sess, err := o.provider.Default() + cfg, err := o.provider.DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("create default session: %w", err) + return fmt.Errorf("create default config: %w", err) } - task, err := o.newTaskSel(sess).RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, + task, err := o.newTaskSel(cfg).RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, selector.WithDefault(), selector.WithTaskGroup(o.name), selector.WithTaskID(o.taskID)) if err != nil { return fmt.Errorf("select running task in default cluster: %w", err) @@ -172,11 +172,11 @@ func (o *taskExecOpts) selectTaskInAppEnvCluster() error { if err != nil { return fmt.Errorf("get environment %s: %w", o.envName, err) } - sess, err := o.provider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := o.provider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return fmt.Errorf("get session from role %s and region %s: %w", env.ManagerRoleARN, env.Region, err) + return fmt.Errorf("get config from role %s and region %s: %w", env.ManagerRoleARN, env.Region, err) } - task, err := o.newTaskSel(sess).RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, + task, err := o.newTaskSel(cfg).RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, selector.WithAppEnv(o.appName, o.envName), selector.WithTaskGroup(o.name), selector.WithTaskID(o.taskID)) if err != nil { return fmt.Errorf("select running task in environment %s: %w", o.envName, err) @@ -185,15 +185,15 @@ func (o *taskExecOpts) selectTaskInAppEnvCluster() error { return nil } -func (o *taskExecOpts) configSession() (*session.Session, error) { +func (o *taskExecOpts) config() (aws.Config, error) { if o.useDefault { - return o.provider.Default() + return o.provider.DefaultConfig(context.Background()) } env, err := o.store.GetEnvironment(o.appName, o.envName) if err != nil { - return nil, fmt.Errorf("get environment %s: %w", o.envName, err) + return aws.Config{}, fmt.Errorf("get environment %s: %w", o.envName, err) } - return o.provider.FromRole(env.ManagerRoleARN, env.Region) + return o.provider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) } // buildTaskExecCmd builds the command for execute a running container in a one-off task. diff --git a/internal/pkg/cli/task_exec_test.go b/internal/pkg/cli/task_exec_test.go index 0b8767e87e1..243f43090e1 100644 --- a/internal/pkg/cli/task_exec_test.go +++ b/internal/pkg/cli/task_exec_test.go @@ -12,9 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/cli/mocks" "github.com/aproint/copilot-cli/internal/pkg/config" + "github.com/aws/aws-sdk-go-v2/aws" awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -156,7 +155,7 @@ func TestTaskExec_Ask(t *testing.T) { "should bubble error if fail to select task in default cluster": { useDefault: true, setupMocks: func(m execTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, mockErr) }, @@ -194,7 +193,7 @@ func TestTaskExec_Ask(t *testing.T) { inEnv: mockEnv, setupMocks: func(m execTaskMocks) { m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, mockErr) }, @@ -204,7 +203,7 @@ func TestTaskExec_Ask(t *testing.T) { "success with default flag set": { useDefault: true, setupMocks: func(m execTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(mockTask, nil) }, @@ -214,7 +213,7 @@ func TestTaskExec_Ask(t *testing.T) { }, "success with default option chose": { setupMocks: func(m execTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.configSel.EXPECT().Application(taskExecAppNamePrompt, taskExecAppNameHelpPrompt, useDefaultClusterOption). Return(useDefaultClusterOption, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, @@ -231,7 +230,7 @@ func TestTaskExec_Ask(t *testing.T) { m.configSel.EXPECT().Environment(taskExecEnvNamePrompt, taskExecEnvNameHelpPrompt, mockApp, prompt.Option{Value: useDefaultClusterOption}). Return(mockEnv, nil) m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.taskSel.EXPECT().RunningTask(taskExecTaskPrompt, taskExecTaskHelpPrompt, gomock.Any(), gomock.Any(), gomock.Any()).Return(mockTask, nil) }, @@ -249,7 +248,7 @@ func TestTaskExec_Ask(t *testing.T) { mockStoreReader := mocks.NewMockstore(ctrl) mockConfigSel := mocks.NewMockappEnvSelector(ctrl) mockTaskSel := mocks.NewMockrunningTaskSelector(ctrl) - mockNewTaskSel := func(_ *session.Session) runningTaskSelector { + mockNewTaskSel := func(_ aws.Config) runningTaskSelector { return mockTaskSel } mockProvider := mocks.NewMocksessionProvider(ctrl) @@ -340,7 +339,7 @@ func TestTaskExec_Execute(t *testing.T) { }, }, setupMocks: func(m execTaskMocks) { - m.provider.EXPECT().Default() + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, wantedError: fmt.Errorf("parse task ARN mockBadTaskARN: parse ECS task ARN: arn: invalid prefix"), @@ -349,7 +348,7 @@ func TestTaskExec_Execute(t *testing.T) { inTask: mockTask, inUseDefault: true, setupMocks: func(m execTaskMocks) { - m.provider.EXPECT().Default() + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.commandExec.EXPECT().ExecuteCommand(ecs.ExecuteCommandInput{ Cluster: mockClusterARN, Command: mockCommand, @@ -364,7 +363,7 @@ func TestTaskExec_Execute(t *testing.T) { inTask: mockTask, setupMocks: func(m execTaskMocks) { m.storeSvc.EXPECT().GetEnvironment(mockApp, mockEnv).Return(&config.Environment{}, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.commandExec.EXPECT().ExecuteCommand(ecs.ExecuteCommandInput{ Cluster: mockClusterARN, Command: mockCommand, @@ -382,7 +381,7 @@ func TestTaskExec_Execute(t *testing.T) { mockStoreReader := mocks.NewMockstore(ctrl) mockCommandExec := mocks.NewMockecsCommandExecutor(ctrl) - mockNewCommandExec := func(_ *session.Session) ecsCommandExecutor { + mockNewCommandExec := func(_ aws.Config) ecsCommandExecutor { return mockCommandExec } mocks := execTaskMocks{ diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index 8b0619425c8..539e24ed83a 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -18,7 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template/artifactpath" "golang.org/x/mod/semver" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/pflag" @@ -27,7 +27,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" awscloudformation "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/ecr" @@ -48,7 +48,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/log" termprogress "github.com/aproint/copilot-cli/internal/pkg/term/progress" "github.com/aproint/copilot-cli/internal/pkg/term/selector" - "github.com/aws/aws-sdk-go/aws/session" "github.com/dustin/go-humanize/english" "github.com/google/shlex" @@ -161,7 +160,7 @@ type runTaskOpts struct { publicIPGetter publicIPGetter provider sessionProvider - sess *session.Session + cfg aws.Config targetEnvironment *config.Environment // Configurer functions. @@ -170,10 +169,10 @@ type runTaskOpts struct { // NOTE: configureEventsWriter is only called when tailing logs (i.e. --follow is specified) configureEventsWriter func(tasks []*task.Task) - configureECSServiceDescriber func(session *session.Session) ecs.ECSServiceDescriber - configureServiceDescriber func(session *session.Session) ecs.ServiceDescriber - configureJobDescriber func(session *session.Session) ecs.JobDescriber - configureUploader func(session *session.Session) uploader + configureECSServiceDescriber func(aws.Config) ecs.ECSServiceDescriber + configureServiceDescriber func(aws.Config) ecs.ServiceDescriber + configureJobDescriber func(aws.Config) ecs.JobDescriber + configureUploader func(aws.Config) uploader // Functions to generate a task run command. runTaskRequestFromECSService func(client ecs.ECSServiceDescriber, cluster, service string) (*ecs.RunTaskRequest, error) @@ -217,33 +216,33 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { if err != nil { return fmt.Errorf("configure task runner: %w", err) } - opts.deployer = cloudformation.New(opts.sess, cloudformation.WithProgressTracker(os.Stderr)) - opts.defaultClusterGetter = awsecs.New(v2ConfigFromSessionRegion(opts.sess)) - opts.publicIPGetter = ec2.New(v2ConfigFromSessionRegion(opts.sess)) + opts.deployer = cloudformation.New(opts.cfg, cloudformation.WithProgressTracker(os.Stderr)) + opts.defaultClusterGetter = awsecs.New(opts.cfg) + opts.publicIPGetter = ec2.New(opts.cfg) return nil } opts.configureRepository = func() error { repoName := fmt.Sprintf(deploy.FmtTaskECRRepoName, opts.groupName) - opts.repository = repository.New(ecr.New(v2ConfigFromSessionRegion(opts.sess)), repoName) + opts.repository = repository.New(ecr.New(opts.cfg), repoName) return nil } opts.configureEventsWriter = func(tasks []*task.Task) { - opts.eventsWriter = logging.NewTaskClient(opts.sess, opts.groupName, tasks) + opts.eventsWriter = logging.NewTaskClient(opts.cfg, opts.groupName, tasks) } - opts.configureECSServiceDescriber = func(session *session.Session) ecs.ECSServiceDescriber { - return awsecs.New(v2ConfigFromSessionRegion(session)) + opts.configureECSServiceDescriber = func(cfg aws.Config) ecs.ECSServiceDescriber { + return awsecs.New(cfg) } - opts.configureServiceDescriber = func(session *session.Session) ecs.ServiceDescriber { - return ecs.New(session, v2ConfigFromSessionRegion(session)) + opts.configureServiceDescriber = func(cfg aws.Config) ecs.ServiceDescriber { + return ecs.New(cfg) } - opts.configureJobDescriber = func(session *session.Session) ecs.JobDescriber { - return ecs.New(session, v2ConfigFromSessionRegion(session)) + opts.configureJobDescriber = func(cfg aws.Config) ecs.JobDescriber { + return ecs.New(cfg) } - opts.configureUploader = func(session *session.Session) uploader { - return s3.New(v2ConfigFromSessionRegion(session)) + opts.configureUploader = func(cfg aws.Config) uploader { + return s3.New(cfg) } opts.envCompatibilityChecker = func(app, env string) (versionCompatibilityChecker, error) { envDescriber, err := describe.NewEnvDescriber(describe.NewEnvDescriberConfig{ @@ -264,8 +263,8 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { } func (o *runTaskOpts) configureRunner() (taskRunner, error) { - vpcGetter := ec2.New(v2ConfigFromSessionRegion(o.sess)) - ecsService := awsecs.New(v2ConfigFromSessionRegion(o.sess)) + vpcGetter := ec2.New(o.cfg) + ecsService := awsecs.New(o.cfg) if o.env != "" { deployStore, err := deploy.NewStore(o.provider, o.store) @@ -284,7 +283,7 @@ func (o *runTaskOpts) configureRunner() (taskRunner, error) { return nil, fmt.Errorf("create describer for environment %s in application %s: %w", o.env, o.appName, err) } - ecsClient := ecs.New(o.sess, v2ConfigFromSessionRegion(o.sess)) + ecsClient := ecs.New(o.cfg) return &task.EnvRunner{ Count: o.count, GroupName: o.groupName, @@ -315,13 +314,13 @@ func (o *runTaskOpts) configureRunner() (taskRunner, error) { VPCGetter: vpcGetter, ClusterGetter: ecsService, Starter: ecsService, - NonZeroExitCodeGetter: ecs.New(o.sess, v2ConfigFromSessionRegion(o.sess)), + NonZeroExitCodeGetter: ecs.New(o.cfg), }, nil } func (o *runTaskOpts) configureSessAndEnv() error { - var sess *session.Session + var cfg aws.Config var env *config.Environment if o.env != "" { @@ -331,20 +330,20 @@ func (o *runTaskOpts) configureSessAndEnv() error { return err } - sess, err = o.provider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err = o.provider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return fmt.Errorf("get session from role %s and region %s: %w", env.ManagerRoleARN, env.Region, err) + return fmt.Errorf("get config from role %s and region %s: %w", env.ManagerRoleARN, env.Region, err) } } else { var err error - sess, err = o.provider.Default() + cfg, err = o.provider.DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("get default session: %w", err) + return fmt.Errorf("get default config: %w", err) } } o.targetEnvironment = env - o.sess = sess + o.cfg = cfg return nil } @@ -795,21 +794,21 @@ func (o *runTaskOpts) runTaskCommand() (cliStringer, error) { if err != nil { return nil, err } - sess, err := o.provider.Default() + cfg, err := o.provider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("get default session: %s", err) + return nil, fmt.Errorf("get default config: %s", err) } - return o.runTaskCommandFromECSService(sess, clusterName, serviceName) + return o.runTaskCommandFromECSService(cfg, clusterName, serviceName) } parts := strings.Split(o.generateCommandTarget, "/") switch len(parts) { case 2: clusterName, serviceName := parts[0], parts[1] - sess, err := o.provider.Default() + cfg, err := o.provider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("get default session: %s", err) + return nil, fmt.Errorf("get default config: %s", err) } - cmd, err = o.runTaskCommandFromECSService(sess, clusterName, serviceName) + cmd, err = o.runTaskCommandFromECSService(cfg, clusterName, serviceName) if err != nil { return nil, err } @@ -819,11 +818,11 @@ func (o *runTaskOpts) runTaskCommand() (cliStringer, error) { if err != nil { return nil, err } - sess, err := o.provider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := o.provider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return nil, fmt.Errorf("get environment session: %s", err) + return nil, fmt.Errorf("get environment config: %s", err) } - cmd, err = o.runTaskCommandFromWorkload(sess, appName, envName, workloadName) + cmd, err = o.runTaskCommandFromWorkload(cfg, appName, envName, workloadName) if err != nil { return nil, err } @@ -842,8 +841,8 @@ func (o *runTaskOpts) parseARN() (string, string, error) { return svcARN.ClusterName(), svcARN.ServiceName(), nil } -func (o *runTaskOpts) runTaskCommandFromECSService(sess *session.Session, clusterName, serviceName string) (cliStringer, error) { - cmd, err := o.runTaskRequestFromECSService(o.configureECSServiceDescriber(sess), clusterName, serviceName) +func (o *runTaskOpts) runTaskCommandFromECSService(cfg aws.Config, clusterName, serviceName string) (cliStringer, error) { + cmd, err := o.runTaskRequestFromECSService(o.configureECSServiceDescriber(cfg), clusterName, serviceName) if err != nil { var errMultipleContainers *ecs.ErrMultipleContainersInTaskDef if errors.As(err, &errMultipleContainers) { @@ -854,7 +853,7 @@ func (o *runTaskOpts) runTaskCommandFromECSService(sess *session.Session, cluste return cmd, nil } -func (o *runTaskOpts) runTaskCommandFromWorkload(sess *session.Session, appName, envName, workloadName string) (cliStringer, error) { +func (o *runTaskOpts) runTaskCommandFromWorkload(cfg aws.Config, appName, envName, workloadName string) (cliStringer, error) { workloadType, err := o.workloadType(appName, workloadName) if err != nil { return nil, err @@ -866,12 +865,12 @@ func (o *runTaskOpts) runTaskCommandFromWorkload(sess *session.Session, appName, if err := o.validateEnvCompatibilityForGenerateJobCmd(appName, envName); err != nil { return nil, err } - cmd, err = o.runTaskRequestFromJob(o.configureJobDescriber(sess), appName, envName, workloadName) + cmd, err = o.runTaskRequestFromJob(o.configureJobDescriber(cfg), appName, envName, workloadName) if err != nil { return nil, fmt.Errorf("generate task run command from job %s of application %s deployed in environment %s: %w", workloadName, appName, envName, err) } case workloadTypeSvc: - cmd, err = o.runTaskRequestFromService(o.configureServiceDescriber(sess), appName, envName, workloadName) + cmd, err = o.runTaskRequestFromService(o.configureServiceDescriber(cfg), appName, envName, workloadName) if err != nil { return nil, fmt.Errorf("generate task run command from service %s of application %s deployed in environment %s: %w", workloadName, appName, envName, err) } @@ -1077,7 +1076,7 @@ func (o *runTaskOpts) pushEnvFileToS3(bucket string) (string, error) { } reader := bytes.NewReader(content) - uploader := o.configureUploader(o.sess) + uploader := o.configureUploader(o.cfg) url, err := uploader.Upload(bucket, artifactpath.EnvFiles(o.envFile, content), reader) if err != nil { return "", fmt.Errorf("put env file %s artifact to bucket %s: %w", o.envFile, bucket, err) @@ -1087,7 +1086,7 @@ func (o *runTaskOpts) pushEnvFileToS3(bucket string) (string, error) { return "", fmt.Errorf("parse s3 url: %w", err) } // The app and environment are always within the same partition. - partition, err := partitions.Region(aws.StringValue(o.sess.Config.Region)).Partition() + partition, err := partitions.Region(o.cfg.Region).Partition() if err != nil { return "", err } diff --git a/internal/pkg/cli/task_run_test.go b/internal/pkg/cli/task_run_test.go index fcab2688809..59e6eae6e80 100644 --- a/internal/pkg/cli/task_run_test.go +++ b/internal/pkg/cli/task_run_test.go @@ -12,8 +12,7 @@ import ( "path/filepath" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" @@ -811,7 +810,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }{ "check if default cluster exists if deploying to default cluster": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) m.deployer.EXPECT().DeployTask(gomock.Any()).Return(nil).AnyTimes() @@ -828,7 +827,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { Return(&config.Environment{ ExecutionRoleARN: "env execution role", }, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Any()).Return(nil).AnyTimes() mockRepositoryAnytime(m) m.runner.EXPECT().Run().AnyTimes() @@ -836,7 +835,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "error deploying resources": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, @@ -850,7 +849,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "error performing docker login": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, @@ -865,7 +864,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "error updating resources": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, @@ -887,7 +886,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "error running tasks": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(gomock.Any()).Return(nil).Times(2) mockRepositoryAnytime(m) @@ -903,7 +902,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { Return(&config.Environment{ ExecutionRoleARN: "env execution role", }, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Len(1)).AnyTimes() // NOTE: matching length because gomock is unable to match function arguments. mockRepositoryAnytime(m) m.runner.EXPECT().Run().AnyTimes() @@ -912,7 +911,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "deploy without execution role option if env is empty": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).Times(0) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Len(0)).AnyTimes() // NOTE: matching length because gomock is unable to match function arguments. mockRepositoryAnytime(m) @@ -923,7 +922,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "append 'latest' to image tag": { inTag: tag, setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.repository.EXPECT().Login().Return(mockRepoURI, nil) @@ -941,7 +940,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { "should use provided docker build context instead of dockerfile path": { inDockerCtx: "../../other", setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.repository.EXPECT().Login().Return(mockRepoURI, nil) @@ -960,7 +959,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { inCommand: `/bin/sh -c "curl $ECS_CONTAINER_METADATA_URI_V4"`, inEntryPoint: `exec "some command"`, setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetEnvironment(gomock.Any(), gomock.Any()).AnyTimes() m.deployer.EXPECT().DeployTask(&deploy.CreateTaskResourcesInput{ Name: inGroupName, @@ -982,7 +981,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "fail to get ENI information for some tasks": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.runner.EXPECT().Run().Return([]*task.Task{ { @@ -1003,7 +1002,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { }, "fail to get public ips": { setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.runner.EXPECT().Run().Return([]*task.Task{ { @@ -1021,7 +1020,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { inFollow: true, inImage: "image", setupMocks: func(m runTaskMocks) { - m.provider.EXPECT().Default().Return(&session.Session{}, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) m.deployer.EXPECT().DeployTask(gomock.Any()).AnyTimes() m.runner.EXPECT().Run().Return([]*task.Task{ { @@ -1044,7 +1043,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { Return(&config.Environment{ ExecutionRoleARN: "env execution role", }, nil) - m.provider.EXPECT().FromRole(gomock.Any(), gomock.Any()) + m.provider.EXPECT().ConfigFromRole(gomock.Any(), gomock.Any(), gomock.Any()).Return(aws.Config{}, nil) m.store.EXPECT().GetApplication("my-app").Return(nil, errors.New("some error")) m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Len(1)).AnyTimes() // NOTE: matching length because gomock is unable to match function arguments. mockRepositoryAnytime(m) @@ -1064,12 +1063,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { setupMocks: func(m runTaskMocks) { region := "us-east-35" - m.provider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - // uh oh, new leaked region - Region: aws.String(region), - }, - }, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) info := deploy.TaskStackInfo{BucketName: "arn:aws:s3:::bigbucket"} m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil).Times(2) @@ -1089,12 +1083,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { setupMocks: func(m runTaskMocks) { region := "us-east-35" - m.provider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - // uh oh, new leaked region - Region: aws.String(region), - }, - }, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) info := deploy.TaskStackInfo{BucketName: "arn:aws:s3:::bigbucket"} m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) @@ -1114,12 +1103,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { region := "us-east-35" m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Any()).Return(nil) - m.provider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - // uh oh, new leaked region - Region: aws.String(region), - }, - }, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) m.deployer.EXPECT().GetTaskStack(inGroupName).Return(nil, errors.New("hull breach in sector 3")) @@ -1137,12 +1121,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { region := "us-east-35" m.deployer.EXPECT().DeployTask(gomock.Any(), gomock.Any()).Return(nil) - m.provider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - // uh oh, new leaked region - Region: aws.String(region), - }, - }, nil) + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{Region: region}, nil) m.defaultClusterGetter.EXPECT().HasDefaultCluster().Return(true, nil) info := deploy.TaskStackInfo{BucketName: "arn:aws:s3:::bigbucket"} m.store.EXPECT().GetApplication("my-app").Return(&config.Application{Name: "my-app"}, nil) @@ -1216,7 +1195,7 @@ func TestTaskRunOpts_Execute(t *testing.T) { opts.configureEventsWriter = func(tasks []*task.Task) { opts.eventsWriter = mocks.eventsWriter } - opts.configureUploader = func(session *session.Session) uploader { + opts.configureUploader = func(aws.Config) uploader { return mocks.uploader } @@ -1257,7 +1236,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "should generate a command given an service ARN": { inGenerateCommandTarget: "arn:aws:ecs:us-east-1:123456789012:service/crowded-cluster/good-service", setUpMocks: func(m *taskRunMocks) { - m.provider.EXPECT().Default() + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, mockRunTaskRequester: mockRunTaskRequester{ mockRunTaskRequestFromECSService: func(client ecs.ECSServiceDescriber, cluster string, service string) (*ecs.RunTaskRequest, error) { @@ -1269,7 +1248,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "fail to generate a command given a service ARN": { inGenerateCommandTarget: "arn:aws:ecs:us-east-1:123456789012:service/crowded-cluster/good-service", setUpMocks: func(m *taskRunMocks) { - m.provider.EXPECT().Default() + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, mockRunTaskRequester: mockRunTaskRequester{ mockRunTaskRequestFromECSService: func(client ecs.ECSServiceDescriber, cluster string, service string) (*ecs.RunTaskRequest, error) { @@ -1281,7 +1260,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "should generate a command given a cluster/service target": { inGenerateCommandTarget: "crowded-cluster/good-service", setUpMocks: func(m *taskRunMocks) { - m.provider.EXPECT().Default() + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, mockRunTaskRequester: mockRunTaskRequester{ mockRunTaskRequestFromECSService: func(client ecs.ECSServiceDescriber, cluster string, service string) (*ecs.RunTaskRequest, error) { @@ -1293,7 +1272,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { "fail to generate a command given a cluster/service target": { inGenerateCommandTarget: "crowded-cluster/good-service", setUpMocks: func(m *taskRunMocks) { - m.provider.EXPECT().Default() + m.provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{}, nil) }, mockRunTaskRequester: mockRunTaskRequester{ mockRunTaskRequestFromECSService: func(client ecs.ECSServiceDescriber, cluster string, service string) (*ecs.RunTaskRequest, error) { @@ -1309,7 +1288,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "good-service").Return(nil, &config.ErrNoSuchJob{}) m.store.EXPECT().GetService("good-app", "good-service").Return(&config.Workload{}, nil) }, @@ -1327,7 +1306,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "good-service").Return(nil, &config.ErrNoSuchJob{}) m.store.EXPECT().GetService("good-app", "good-service").Return(&config.Workload{}, nil) }, @@ -1345,7 +1324,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("v1.12.2", nil) }, @@ -1363,7 +1342,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("v1.12.2", nil) }, @@ -1381,7 +1360,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("", errors.New("some error")) }, @@ -1395,7 +1374,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "good-job").Return(&config.Workload{}, nil) m.envCompatibilityChecker.EXPECT().Version().Return("v1.9.0", nil) }, @@ -1409,7 +1388,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "bad-workload").Return(nil, errors.New("some error")) }, wantedError: fmt.Errorf("determine whether workload bad-workload is a job: some error"), @@ -1421,7 +1400,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "bad-workload").Return(nil, &config.ErrNoSuchJob{}) m.store.EXPECT().GetService("good-app", "bad-workload").Return(nil, errors.New("some error")) }, @@ -1434,7 +1413,7 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { ManagerRoleARN: "mock-role", Region: "mock-region", }, nil) - m.provider.EXPECT().FromRole("mock-role", "mock-region") + m.provider.EXPECT().ConfigFromRole(gomock.Any(), "mock-role", "mock-region").Return(aws.Config{}, nil) m.store.EXPECT().GetJob("good-app", "bad-workload").Return(nil, &config.ErrNoSuchJob{}) m.store.EXPECT().GetService("good-app", "bad-workload").Return(nil, &config.ErrNoSuchService{}) }, @@ -1466,13 +1445,13 @@ func TestTaskRunOpts_runTaskCommand(t *testing.T) { store: m.store, provider: m.provider, - configureECSServiceDescriber: func(session *session.Session) ecs.ECSServiceDescriber { + configureECSServiceDescriber: func(aws.Config) ecs.ECSServiceDescriber { return ecsMocks.NewMockECSServiceDescriber(ctrl) }, - configureJobDescriber: func(session *session.Session) ecs.JobDescriber { + configureJobDescriber: func(aws.Config) ecs.JobDescriber { return ecsMocks.NewMockJobDescriber(ctrl) }, - configureServiceDescriber: func(session *session.Session) ecs.ServiceDescriber { + configureServiceDescriber: func(aws.Config) ecs.ServiceDescriber { return ecsMocks.NewMockServiceDescriber(ctrl) }, runTaskRequestFromECSService: tc.mockRunTaskRequester.mockRunTaskRequestFromECSService, diff --git a/internal/pkg/cli/validate.go b/internal/pkg/cli/validate.go index 0e12c6a853f..f37788e9603 100644 --- a/internal/pkg/cli/validate.go +++ b/internal/pkg/cli/validate.go @@ -23,7 +23,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) const basicNameRegex = `^[a-z][a-z0-9\-]+$` @@ -783,11 +783,11 @@ func validateSubscriptionKey(val interface{}) error { if err != nil { return errSubscribeBadFormat } - if err := validatePubSubName(aws.StringValue(sub.Name)); err != nil { - return fmt.Errorf("invalid topic subscription topic name `%s`: %w", aws.StringValue(sub.Name), err) + if err := validatePubSubName(aws.ToString(sub.Name)); err != nil { + return fmt.Errorf("invalid topic subscription topic name `%s`: %w", aws.ToString(sub.Name), err) } - if err = basicNameValidation(aws.StringValue(sub.Service)); err != nil { - return fmt.Errorf("invalid topic subscription service name `%s`: %w", aws.StringValue(sub.Service), err) + if err = basicNameValidation(aws.ToString(sub.Service)); err != nil { + return fmt.Errorf("invalid topic subscription service name `%s`: %w", aws.ToString(sub.Service), err) } return nil } diff --git a/internal/pkg/config/app.go b/internal/pkg/config/app.go index f061fce634a..96665f01ed2 100644 --- a/internal/pkg/config/app.go +++ b/internal/pkg/config/app.go @@ -5,11 +5,12 @@ package config import ( "encoding/json" + "errors" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" ) // Application is a named collection of environments and services. @@ -36,9 +37,9 @@ func (s *Store) CreateApplication(application *Application) error { _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ Name: aws.String(applicationPath), Description: aws.String("Copilot Application"), - Type: aws.String(ssm.ParameterTypeString), + Type: types.ParameterTypeString, Value: aws.String(data), - Tags: []*ssm.Tag{ + Tags: []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String(application.Name), @@ -47,11 +48,9 @@ func (s *Store) CreateApplication(application *Application) error { }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterAlreadyExists: - return nil - } + var existsErr *types.ParameterAlreadyExists + if errors.As(err, &existsErr) { + return nil } return fmt.Errorf("create application %s: %w", application.Name, err) } @@ -71,7 +70,7 @@ func (s *Store) UpdateApplication(application *Application) error { if _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ Name: aws.String(applicationPath), Description: aws.String("Copilot Application"), - Type: aws.String(ssm.ParameterTypeString), + Type: types.ParameterTypeString, Value: aws.String(data), Overwrite: aws.Bool(true), }); err != nil { @@ -88,22 +87,20 @@ func (s *Store) GetApplication(applicationName string) (*Application, error) { }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterNotFound: - account, region := s.getCallerAccountAndRegion() - return nil, &ErrNoSuchApplication{ - ApplicationName: applicationName, - AccountID: account, - Region: region, - } + var notFoundErr *types.ParameterNotFound + if errors.As(err, ¬FoundErr) { + account, region := s.getCallerAccountAndRegion() + return nil, &ErrNoSuchApplication{ + ApplicationName: applicationName, + AccountID: account, + Region: region, } } return nil, fmt.Errorf("get application %s: %w", applicationName, err) } var application Application - if err := json.Unmarshal([]byte(*applicationParam.Parameter.Value), &application); err != nil { + if err := json.Unmarshal([]byte(aws.ToString(applicationParam.Parameter.Value)), &application); err != nil { return nil, fmt.Errorf("read configuration for application %s: %w", applicationName, err) } return &application, nil @@ -136,16 +133,12 @@ func (s *Store) DeleteApplication(name string) error { }) if err != nil { - awserr, ok := err.(awserr.Error) - if !ok { - return err - } - - if awserr.Code() == ssm.ErrCodeParameterNotFound { + var notFoundErr *types.ParameterNotFound + if errors.As(err, ¬FoundErr) { return nil } - return fmt.Errorf("delete SSM param %s: %w", paramName, awserr) + return err } return nil diff --git a/internal/pkg/config/app_test.go b/internal/pkg/config/app_test.go index 464cc867303..4418c5e50a2 100644 --- a/internal/pkg/config/app_test.go +++ b/internal/pkg/config/app_test.go @@ -9,9 +9,9 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/stretchr/testify/require" ) @@ -36,7 +36,7 @@ func TestStore_ListApplications(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, rootApplicationPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String("/copilot/applications/chicken"), Value: aws.String(testApplicationString), @@ -56,7 +56,7 @@ func TestStore_ListApplications(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, rootApplicationPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String("/copilot/applications/chicken"), Value: aws.String("oops"), @@ -84,7 +84,7 @@ func TestStore_ListApplications(t *testing.T) { if !lastPageInPaginatedResp { lastPageInPaginatedResp = true return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String("/copilot/applications/chicken"), Value: aws.String(testApplicationString), @@ -94,7 +94,7 @@ func TestStore_ListApplications(t *testing.T) { }, nil } return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String("/copilot/applications/cow"), Value: aws.String(cowApplicationString), @@ -153,7 +153,7 @@ func TestStore_GetApplication(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -166,7 +166,7 @@ func TestStore_GetApplication(t *testing.T) { "with no existing application": { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "No Parameter", fmt.Errorf("No Parameter")) + return nil, &types.ParameterNotFound{} }, mockIdentityServiceGet: func() (identity.Caller, error) { return identity.Caller{ @@ -182,7 +182,7 @@ func TestStore_GetApplication(t *testing.T) { "with no existing application and failed STS call": { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "No Parameter", fmt.Errorf("No Parameter")) + return nil, &types.ParameterNotFound{} }, mockIdentityServiceGet: func() (identity.Caller, error) { return identity.Caller{}, fmt.Errorf("Error") @@ -197,7 +197,7 @@ func TestStore_GetApplication(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String("oops"), }, @@ -243,7 +243,7 @@ func TestStore_GetApplication(t *testing.T) { } func TestStore_CreateApplication(t *testing.T) { - tagForApplicationParam := []*ssm.Tag{ + tagForApplicationParam := []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String("phonetool"), @@ -262,7 +262,7 @@ func TestStore_CreateApplication(t *testing.T) { require.Equal(t, fmt.Sprintf(`{"name":"phonetool","account":"1234","domain":"phonetool.com","domainHostedZoneID":"mockHostedZoneID","version":"%s","tags":{"owner":"boss"}}`, schemaVersion), *param.Value) require.Equal(t, tagForApplicationParam, param.Tags) return &ssm.PutParameterOutput{ - Version: aws.Int64(1), + Version: 1, }, nil }, wantedErr: nil, @@ -271,7 +271,7 @@ func TestStore_CreateApplication(t *testing.T) { inApplication: &Application{Name: "phonetool", AccountID: "1234"}, mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, tagForApplicationParam, param.Tags) - return nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "Already exists", fmt.Errorf("Already Exists")) + return nil, &types.ParameterAlreadyExists{} }, wantedErr: nil, }, @@ -320,7 +320,7 @@ func TestStore_UpdateApplication(t *testing.T) { require.Equal(t, fmt.Sprintf(`{"name":"phonetool","account":"1234","domain":"phonetool.com","domainHostedZoneID":"mockHostedZoneID","version":"%s","tags":{"owner":"boss"}}`, schemaVersion), *param.Value) return &ssm.PutParameterOutput{ - Version: aws.Int64(1), + Version: 1, }, nil }, wantedErr: nil, @@ -377,7 +377,7 @@ func TestDeleteApplication(t *testing.T) { mockDeleteParameter: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { require.Equal(t, fmt.Sprintf(fmtApplicationPath, mockApplicationName), *in.Name) - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "whatevs", mockError) + return nil, &types.ParameterNotFound{} }, want: nil, }, diff --git a/internal/pkg/config/env.go b/internal/pkg/config/env.go index 1e45b529737..6ac062010a6 100644 --- a/internal/pkg/config/env.go +++ b/internal/pkg/config/env.go @@ -5,12 +5,13 @@ package config import ( "encoding/json" + "errors" "fmt" "sort" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" ) // Environment represents a deployment environment in an application. @@ -81,9 +82,9 @@ func (s *Store) CreateEnvironment(environment *Environment) error { _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ Name: aws.String(environmentPath), Description: aws.String(fmt.Sprintf("The %s deployment stage", environment.Name)), - Type: aws.String(ssm.ParameterTypeString), + Type: types.ParameterTypeString, Value: aws.String(data), - Tags: []*ssm.Tag{ + Tags: []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String(environment.App), @@ -95,11 +96,9 @@ func (s *Store) CreateEnvironment(environment *Environment) error { }, }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterAlreadyExists: - return nil - } + var existsErr *types.ParameterAlreadyExists + if errors.As(err, &existsErr) { + return nil } return fmt.Errorf("create environment %s in application %s: %w", environment.Name, environment.App, err) } @@ -115,20 +114,18 @@ func (s *Store) GetEnvironment(appName string, environmentName string) (*Environ }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterNotFound: - return nil, &ErrNoSuchEnvironment{ - ApplicationName: appName, - EnvironmentName: environmentName, - } + var notFoundErr *types.ParameterNotFound + if errors.As(err, ¬FoundErr) { + return nil, &ErrNoSuchEnvironment{ + ApplicationName: appName, + EnvironmentName: environmentName, } } return nil, fmt.Errorf("get environment %s in application %s: %w", environmentName, appName, err) } var env Environment - err = json.Unmarshal([]byte(*environmentParam.Parameter.Value), &env) + err = json.Unmarshal([]byte(aws.ToString(environmentParam.Parameter.Value)), &env) if err != nil { return nil, fmt.Errorf("read configuration for environment %s in application %s: %w", environmentName, appName, err) } @@ -165,11 +162,9 @@ func (s *Store) DeleteEnvironment(appName, environmentName string) error { }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterNotFound: - return nil - } + var notFoundErr *types.ParameterNotFound + if errors.As(err, ¬FoundErr) { + return nil } return fmt.Errorf("delete environment %s from application %s: %w", environmentName, appName, err) } diff --git a/internal/pkg/config/env_test.go b/internal/pkg/config/env_test.go index 7cdb52fcff0..63df36de9a6 100644 --- a/internal/pkg/config/env_test.go +++ b/internal/pkg/config/env_test.go @@ -8,9 +8,9 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/stretchr/testify/require" ) @@ -44,7 +44,7 @@ func TestStore_ListEnvironments(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, environmentPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(prodIADEnvPath), Value: aws.String(prodIADEnvString), @@ -64,7 +64,7 @@ func TestStore_ListEnvironments(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, environmentPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(testEnvironmentPath), Value: aws.String("oops"), @@ -88,7 +88,7 @@ func TestStore_ListEnvironments(t *testing.T) { if !lastPageInPaginatedResp { lastPageInPaginatedResp = true return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(prodPDXEnvPath), // Return "pdx" first on purpose to test if alphabetical ordering is maintained. Value: aws.String(prodPDXEnvString), @@ -99,7 +99,7 @@ func TestStore_ListEnvironments(t *testing.T) { } return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(prodIADEnvPath), Value: aws.String(prodIADEnvString), @@ -159,7 +159,7 @@ func TestStore_GetEnvironment(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testEnvironmentPath), Value: aws.String(testEnvironmentString), }, @@ -171,7 +171,7 @@ func TestStore_GetEnvironment(t *testing.T) { "with no existing environment": { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "bloop", nil) + return nil, &types.ParameterNotFound{} }, wantedErr: &ErrNoSuchEnvironment{ ApplicationName: testEnvironment.App, @@ -182,7 +182,7 @@ func TestStore_GetEnvironment(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testEnvironmentPath), Value: aws.String("oops"), }, @@ -244,7 +244,7 @@ func TestStore_CreateEnvironment(t *testing.T) { testEnvironmentPath := fmt.Sprintf(fmtEnvParamPath, testEnvironment.App, testEnvironment.Name) require.NoError(t, err, "Marshal environment should not fail") - tagsForEnvParam := []*ssm.Tag{ + tagsForEnvParam := []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String(testEnvironment.App), @@ -266,13 +266,13 @@ func TestStore_CreateEnvironment(t *testing.T) { require.Equal(t, testEnvironmentString, *param.Value) require.Equal(t, tagsForEnvParam, param.Tags) return &ssm.PutParameterOutput{ - Version: aws.Int64(1), + Version: 1, }, nil }, mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -285,12 +285,12 @@ func TestStore_CreateEnvironment(t *testing.T) { mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, testEnvironmentPath, *param.Name) require.Equal(t, tagsForEnvParam, param.Tags) - return nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "Already exists", fmt.Errorf("Already Exists")) + return nil, &types.ParameterAlreadyExists{} }, mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -306,7 +306,7 @@ func TestStore_CreateEnvironment(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -356,7 +356,7 @@ func TestStore_DeleteEnvironment(t *testing.T) { inApplicationName: "phonetool", inEnvName: "test", mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "Not found", nil) + return nil, &types.ParameterNotFound{} }, }, "unexpected error": { diff --git a/internal/pkg/config/store.go b/internal/pkg/config/store.go index e905e66ead2..9766937541f 100644 --- a/internal/pkg/config/store.go +++ b/internal/pkg/config/store.go @@ -10,12 +10,13 @@ application. package config import ( + "context" "encoding/json" "log" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" ) // Parameter name formats for resources in an application. Applications are laid out in SSM @@ -50,6 +51,31 @@ type SSM interface { DeleteParameter(in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) } +type ssmClient struct { + client *ssm.Client +} + +// NewSSMClient adapts the SDK v2 SSM client to Store's narrow SSM interface. +func NewSSMClient(cfg aws.Config) SSM { + return &ssmClient{client: ssm.NewFromConfig(cfg)} +} + +func (c *ssmClient) PutParameter(in *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { + return c.client.PutParameter(context.Background(), in) +} + +func (c *ssmClient) GetParametersByPath(in *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) { + return c.client.GetParametersByPath(context.Background(), in) +} + +func (c *ssmClient) GetParameter(in *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { + return c.client.GetParameter(context.Background(), in) +} + +func (c *ssmClient) DeleteParameter(in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { + return c.client.DeleteParameter(context.Background(), in) +} + // Store is in charge of fetching and creating applications, environment, services and other workloads, and pipeline configuration in SSM. type Store struct { sts IAMIdentityGetter diff --git a/internal/pkg/config/store_integration_test.go b/internal/pkg/config/store_integration_test.go index fca69f8b427..2e9422cdc66 100644 --- a/internal/pkg/config/store_integration_test.go +++ b/internal/pkg/config/store_integration_test.go @@ -12,8 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/stretchr/testify/require" diff --git a/internal/pkg/config/store_test.go b/internal/pkg/config/store_test.go index 0a968dbc758..e87fc24f41d 100644 --- a/internal/pkg/config/store_test.go +++ b/internal/pkg/config/store_test.go @@ -7,12 +7,10 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aws/aws-sdk-go/service/ssm" - "github.com/aws/aws-sdk-go/service/ssm/ssmiface" + "github.com/aws/aws-sdk-go-v2/service/ssm" ) type mockSSM struct { - ssmiface.SSMAPI t *testing.T mockPutParameter func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) mockGetParametersByPath func(t *testing.T, param *ssm.GetParametersByPathInput) (*ssm.GetParametersByPathOutput, error) diff --git a/internal/pkg/config/workload.go b/internal/pkg/config/workload.go index 1be39fefd9e..c13a4e4f6b7 100644 --- a/internal/pkg/config/workload.go +++ b/internal/pkg/config/workload.go @@ -9,9 +9,9 @@ import ( "fmt" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" ) // Workload represents a deployable long-running service or task. @@ -53,9 +53,9 @@ func (s *Store) createWorkload(wkld *Workload) error { _, err = s.ssm.PutParameter(&ssm.PutParameterInput{ Name: aws.String(wkldPath), Description: aws.String(fmt.Sprintf("Copilot %s %s", wkld.Type, wkld.Name)), - Type: aws.String(ssm.ParameterTypeString), + Type: types.ParameterTypeString, Value: aws.String(data), - Tags: []*ssm.Tag{ + Tags: []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String(wkld.App), @@ -67,11 +67,9 @@ func (s *Store) createWorkload(wkld *Workload) error { }, }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterAlreadyExists: - return nil - } + var existsErr *types.ParameterAlreadyExists + if errors.As(err, &existsErr) { + return nil } return err } @@ -156,18 +154,16 @@ func (s *Store) getWorkloadParam(appName, name string) ([]byte, error) { Name: aws.String(wlPath), }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterNotFound: - return nil, &errNoSuchWorkload{ - App: appName, - Name: name, - } + var notFoundErr *types.ParameterNotFound + if errors.As(err, ¬FoundErr) { + return nil, &errNoSuchWorkload{ + App: appName, + Name: name, } } return nil, err } - return []byte(*wlParam.Parameter.Value), nil + return []byte(aws.ToString(wlParam.Parameter.Value)), nil } // ListServices returns all services belonging to a particular application. @@ -258,11 +254,9 @@ func (s *Store) deleteWorkload(appName, wkldName string) error { }) if err != nil { - if aerr, ok := err.(awserr.Error); ok { - switch aerr.Code() { - case ssm.ErrCodeParameterNotFound: - return nil - } + var notFoundErr *types.ParameterNotFound + if errors.As(err, ¬FoundErr) { + return nil } return err } diff --git a/internal/pkg/config/workload_test.go b/internal/pkg/config/workload_test.go index ef248842b1f..ce2f8652862 100644 --- a/internal/pkg/config/workload_test.go +++ b/internal/pkg/config/workload_test.go @@ -8,9 +8,9 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ssm" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ssm" + "github.com/aws/aws-sdk-go-v2/service/ssm/types" "github.com/stretchr/testify/require" ) @@ -39,7 +39,7 @@ func TestStore_ListServices(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, servicePath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(frontendServicePath), Value: aws.String(frontendServiceString), @@ -59,7 +59,7 @@ func TestStore_ListServices(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, servicePath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(apiServicePath), Value: aws.String("oops"), @@ -83,7 +83,7 @@ func TestStore_ListServices(t *testing.T) { if !lastPageInPaginatedResp { lastPageInPaginatedResp = true return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(frontendServicePath), Value: aws.String(frontendServiceString), @@ -94,7 +94,7 @@ func TestStore_ListServices(t *testing.T) { } return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(apiServicePath), Value: aws.String(apiServiceString), @@ -158,7 +158,7 @@ func TestStore_ListWorkloads(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(mailerJobPath), Value: aws.String(mailerJobString), @@ -177,7 +177,7 @@ func TestStore_ListWorkloads(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(mailerJobPath), Value: aws.String(mailerJobString), @@ -243,7 +243,7 @@ func TestStore_ListJobs(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(mailerJobPath), Value: aws.String(mailerJobString), @@ -262,7 +262,7 @@ func TestStore_ListJobs(t *testing.T) { mockGetParametersByPath: func(t *testing.T, param *ssm.GetParametersByPathInput) (output *ssm.GetParametersByPathOutput, e error) { require.Equal(t, workloadPath, *param.Path) return &ssm.GetParametersByPathOutput{ - Parameters: []*ssm.Parameter{ + Parameters: []types.Parameter{ { Name: aws.String(mailerJobPath), Value: aws.String(mailerJobString), @@ -319,7 +319,7 @@ func TestStore_GetService(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testServicePath), Value: aws.String(testServiceString), }, @@ -331,7 +331,7 @@ func TestStore_GetService(t *testing.T) { "with no existing svc": { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "bloop", nil) + return nil, &types.ParameterNotFound{} }, wantedErr: errors.New("couldn't find service api in the application chicken"), }, @@ -339,7 +339,7 @@ func TestStore_GetService(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testServicePath), Value: aws.String("oops"), }, @@ -398,7 +398,7 @@ func TestStore_GetJob(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, mailerJobPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(mailerJobPath), Value: aws.String(mailerJobString), }, @@ -410,7 +410,7 @@ func TestStore_GetJob(t *testing.T) { "with no existing job": { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, mailerJobPath, *param.Name) - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "bloop", nil) + return nil, &types.ParameterNotFound{} }, wantedErr: errors.New("couldn't find job mailer in the application chicken"), }, @@ -418,7 +418,7 @@ func TestStore_GetJob(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, mailerJobPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testServicePath), Value: aws.String(testServiceString), }, @@ -463,7 +463,7 @@ func TestStore_CreateService(t *testing.T) { testServiceString, err := marshal(testService) testServicePath := fmt.Sprintf(fmtWkldParamPath, testService.App, testService.Name) require.NoError(t, err, "Marshal svc should not fail") - tagsForServiceParam := []*ssm.Tag{ + tagsForServiceParam := []types.Tag{ { Key: aws.String("copilot-application"), Value: aws.String(testApplication.Name), @@ -484,13 +484,13 @@ func TestStore_CreateService(t *testing.T) { require.Equal(t, testServiceString, *param.Value) require.Equal(t, tagsForServiceParam, param.Tags) return &ssm.PutParameterOutput{ - Version: aws.Int64(1), + Version: 1, }, nil }, mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -501,12 +501,12 @@ func TestStore_CreateService(t *testing.T) { mockPutParameter: func(t *testing.T, param *ssm.PutParameterInput) (*ssm.PutParameterOutput, error) { require.Equal(t, testServicePath, *param.Name) require.Equal(t, tagsForServiceParam, param.Tags) - return nil, awserr.New(ssm.ErrCodeParameterAlreadyExists, "Already exists", fmt.Errorf("Already Exists")) + return nil, &types.ParameterAlreadyExists{} }, mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -522,7 +522,7 @@ func TestStore_CreateService(t *testing.T) { mockGetParameter: func(t *testing.T, param *ssm.GetParameterInput) (*ssm.GetParameterOutput, error) { require.Equal(t, testApplicationPath, *param.Name) return &ssm.GetParameterOutput{ - Parameter: &ssm.Parameter{ + Parameter: &types.Parameter{ Name: aws.String(testApplicationPath), Value: aws.String(testApplicationString), }, @@ -569,7 +569,7 @@ func TestDeleteService(t *testing.T) { }{ "parameter is already deleted": { mockDeleteParam: func(t *testing.T, in *ssm.DeleteParameterInput) (*ssm.DeleteParameterOutput, error) { - return nil, awserr.New(ssm.ErrCodeParameterNotFound, "Not found", nil) + return nil, &types.ParameterNotFound{} }, }, "unexpected error": { diff --git a/internal/pkg/deploy/app.go b/internal/pkg/deploy/app.go index 0ec649571c9..4cc4d9a5607 100644 --- a/internal/pkg/deploy/app.go +++ b/internal/pkg/deploy/app.go @@ -8,7 +8,7 @@ package deploy import ( "fmt" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" ) const appDNSDelegationRoleName = "DNSDelegationRole" diff --git a/internal/pkg/deploy/cloudformation/app.go b/internal/pkg/deploy/cloudformation/app.go index e2fc67a3402..e0ae529ec4e 100644 --- a/internal/pkg/deploy/cloudformation/app.go +++ b/internal/pkg/deploy/cloudformation/app.go @@ -22,8 +22,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" - sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" - sdkcloudformationiface "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" ) type errNoRegionalResources struct { @@ -68,7 +66,7 @@ func (cf CloudFormation) DeployApp(in *deploy.CreateAppInput) error { stackset.WithDescription(appConfig.StackSetDescription()), stackset.WithExecutionRoleName(appConfig.StackSetExecutionRoleName()), stackset.WithAdministrationRoleARN(stackSetAdminRoleARN), - stackset.WithTags(toMap(appConfig.Tags()))) + stackset.WithTags(toMapPtr(appConfig.Tags()))) } // UpgradeApplication upgrades the application stack to the latest version. @@ -566,12 +564,8 @@ func (cf CloudFormation) AddEnvToApp(opts *AddEnvToAppOpts) error { return nil } -var getRegionFromClient = func(client sdkcloudformationiface.CloudFormationAPI) (string, error) { - concrete, ok := client.(*sdkcloudformation.CloudFormation) - if !ok { - return "", errors.New("failed to retrieve the region") - } - return *concrete.Client.Config.Region, nil +var getRegionFromClient = func(client any) (string, error) { + return "", errors.New("failed to retrieve the region") } // AddPipelineResourcesToApp conditionally adds resources needed to support @@ -630,7 +624,7 @@ func (cf CloudFormation) deployAppConfig(appConfig *stack.AppStackConfig, resour stackset.WithDescription(appConfig.StackSetDescription()), stackset.WithExecutionRoleName(appConfig.StackSetExecutionRoleName()), stackset.WithAdministrationRoleARN(stackSetAdminRoleARN), - stackset.WithTags(toMap(appConfig.Tags()))) + stackset.WithTags(toMapPtr(appConfig.Tags()))) }, now: time.Now, } diff --git a/internal/pkg/deploy/cloudformation/app_test.go b/internal/pkg/deploy/cloudformation/app_test.go index 41bca048638..9dee1723fd6 100644 --- a/internal/pkg/deploy/cloudformation/app_test.go +++ b/internal/pkg/deploy/cloudformation/app_test.go @@ -17,9 +17,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" - "github.com/aws/aws-sdk-go/aws" - awscfn "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/cloudformation/cloudformationiface" + "github.com/aws/aws-sdk-go-v2/aws" + awscfn "github.com/aws/aws-sdk-go-v2/service/cloudformation" + awscfntypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -218,11 +218,11 @@ func TestCloudFormation_UpgradeApplication(t *testing.T) { DescribeStackEventsFn: func(input *awscfn.DescribeStackEventsInput) (*awscfn.DescribeStackEventsOutput, error) { // just finish the renderer on the first Describe call return &awscfn.DescribeStackEventsOutput{ - StackEvents: []*awscfn.StackEvent{ + StackEvents: []awscfntypes.StackEvent{ { Timestamp: aws.Time(time.Now().Add(1 * time.Hour)), LogicalResourceId: aws.String("phonetool-infrastructure-roles"), - ResourceStatus: aws.String(awscfn.StackStatusUpdateComplete), + ResourceStatus: awscfntypes.ResourceStatusUpdateComplete, }, }, }, nil @@ -258,11 +258,11 @@ func TestCloudFormation_UpgradeApplication(t *testing.T) { }, DescribeStackEventsFn: func(input *awscfn.DescribeStackEventsInput) (*awscfn.DescribeStackEventsOutput, error) { return &awscfn.DescribeStackEventsOutput{ - StackEvents: []*awscfn.StackEvent{ + StackEvents: []awscfntypes.StackEvent{ { Timestamp: aws.Time(time.Now().Add(1 * time.Hour)), LogicalResourceId: aws.String("phonetool-infrastructure-roles"), - ResourceStatus: aws.String(awscfn.StackStatusUpdateComplete), + ResourceStatus: awscfntypes.ResourceStatusUpdateComplete, }, }, }, nil @@ -306,11 +306,11 @@ func TestCloudFormation_UpgradeApplication(t *testing.T) { }, DescribeStackEventsFn: func(input *awscfn.DescribeStackEventsInput) (*awscfn.DescribeStackEventsOutput, error) { return &awscfn.DescribeStackEventsOutput{ - StackEvents: []*awscfn.StackEvent{ + StackEvents: []awscfntypes.StackEvent{ { Timestamp: aws.Time(time.Now().Add(1 * time.Hour)), LogicalResourceId: aws.String("phonetool-infrastructure-roles"), - ResourceStatus: aws.String(awscfn.StackStatusUpdateComplete), + ResourceStatus: awscfntypes.ResourceStatusUpdateComplete, }, }, }, nil @@ -482,7 +482,7 @@ func TestCloudFormation_AddPipelineResourcesToApp(t *testing.T) { testCases := map[string]struct { app *config.Application mockStackSet func(t *testing.T, ctrl *gomock.Controller) stackSetClient - getRegionFromClient func(client cloudformationiface.CloudFormationAPI) (string, error) + getRegionFromClient func(client any) (string, error) expectedErr error }{ "with no existing account nor environment, add pipeline supporting resources": { @@ -498,7 +498,7 @@ func TestCloudFormation_AddPipelineResourcesToApp(t *testing.T) { m.EXPECT().CreateInstances(gomock.Any(), []string{"1234"}, []string{"us-west-2"}).Return("1", nil) return m }, - getRegionFromClient: func(client cloudformationiface.CloudFormationAPI) (string, error) { + getRegionFromClient: func(client any) (string, error) { return "us-west-2", nil }, }, @@ -520,7 +520,7 @@ func TestCloudFormation_AddPipelineResourcesToApp(t *testing.T) { m.EXPECT().CreateInstances(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) return m }, - getRegionFromClient: func(client cloudformationiface.CloudFormationAPI) (string, error) { + getRegionFromClient: func(client any) (string, error) { return "us-west-2", nil }, }, @@ -1025,9 +1025,9 @@ func mockValidAppResourceStack() *cloudformation.StackDescription { } func mockAppResourceStack(stackArn string, outputs map[string]string) *cloudformation.StackDescription { - outputList := []*awscfn.Output{} + outputList := []awscfntypes.Output{} for key, val := range outputs { - outputList = append(outputList, &awscfn.Output{ + outputList = append(outputList, awscfntypes.Output{ OutputKey: aws.String(key), OutputValue: aws.String(val), }) @@ -1040,9 +1040,9 @@ func mockAppResourceStack(stackArn string, outputs map[string]string) *cloudform } func mockAppRolesStack(stackArn string, parameters map[string]string) *cloudformation.StackDescription { - parametersList := []*awscfn.Parameter{} + parametersList := []awscfntypes.Parameter{} for key, val := range parameters { - parametersList = append(parametersList, &awscfn.Parameter{ + parametersList = append(parametersList, awscfntypes.Parameter{ ParameterKey: aws.String(key), ParameterValue: aws.String(val), }) @@ -1050,7 +1050,7 @@ func mockAppRolesStack(stackArn string, parameters map[string]string) *cloudform return &cloudformation.StackDescription{ StackId: aws.String(stackArn), - StackStatus: aws.String("UPDATE_COMPLETE"), + StackStatus: awscfntypes.StackStatusUpdateComplete, Parameters: parametersList, } } @@ -1285,7 +1285,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1347,7 +1347,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { appStackSet.EXPECT().DeleteInstance("phonetool-infrastructure", "1234", "us-west-2").Return("123", nil) appStackSet.EXPECT().WaitForOperation("phonetool-infrastructure", "123").Return(nil) cfn.EXPECT().Describe(stack.NameForAppStack("phonetool")).Return(&cloudformation.StackDescription{ - Parameters: []*awscfn.Parameter{ + Parameters: []awscfntypes.Parameter{ { ParameterKey: aws.String("AppDNSDelegatedAccounts"), ParameterValue: aws.String("1234,5678"), @@ -1375,7 +1375,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1445,7 +1445,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1499,7 +1499,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { appStackSet.EXPECT().DeleteInstance(gomock.Any(), gomock.Any(), gomock.Any()).Times(0) appStackSet.EXPECT().WaitForOperation(gomock.Any(), gomock.Any()).Times(0) cfn.EXPECT().Describe(stack.NameForAppStack("phonetool")).Return(&cloudformation.StackDescription{ - Parameters: []*awscfn.Parameter{ + Parameters: []awscfntypes.Parameter{ { ParameterKey: aws.String("AppDNSDelegatedAccounts"), ParameterValue: aws.String("1234,5678"), @@ -1527,7 +1527,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1596,7 +1596,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1656,7 +1656,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { appStackSet.EXPECT().DeleteInstance("phonetool-infrastructure", "1234", "us-west-2").Return("123", nil) appStackSet.EXPECT().WaitForOperation("phonetool-infrastructure", "123").Return(nil) cfn.EXPECT().Describe(stack.NameForAppStack("phonetool")).Return(&cloudformation.StackDescription{ - Parameters: []*awscfn.Parameter{ + Parameters: []awscfntypes.Parameter{ { ParameterKey: aws.String("AppDNSDelegatedAccounts"), ParameterValue: aws.String("1234,5678"), @@ -1684,7 +1684,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1756,7 +1756,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1819,7 +1819,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { @@ -1880,7 +1880,7 @@ func TestCloudFormation_RemoveEnvFromApp(t *testing.T) { region: "us-east-1", appStackSet: appStackSet, - dnsDelegatedAccountsForStack: func(in *awscfn.Stack) []string { + dnsDelegatedAccountsForStack: func(in *awscfntypes.Stack) []string { return []string{"1234", "5678"} }, renderStackSet: func(in renderStackSetInput) error { diff --git a/internal/pkg/deploy/cloudformation/cloudformation.go b/internal/pkg/deploy/cloudformation/cloudformation.go index ab51340be4f..aa57f0337aa 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation.go +++ b/internal/pkg/deploy/cloudformation/cloudformation.go @@ -25,16 +25,15 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/codestar" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/aws/s3" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/stream" "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/cursor" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/term/progress" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + sdkcloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "golang.org/x/sync/errgroup" ) @@ -56,8 +55,8 @@ var ( type StackConfiguration interface { StackName() string Template() (string, error) - Parameters() ([]*sdkcloudformation.Parameter, error) - Tags() []*sdkcloudformation.Tag + Parameters() ([]*types.Parameter, error) + Tags() []*types.Tag SerializedParameters() (string, error) } @@ -203,35 +202,36 @@ type CloudFormation struct { // Overridden in tests. renderStackSet func(input renderStackSetInput) error - dnsDelegatedAccountsForStack func(stack *sdkcloudformation.Stack) []string + dnsDelegatedAccountsForStack func(stack *types.Stack) []string notifySignals func() chan os.Signal } // New returns a configured CloudFormation client. -func New(sess *session.Session, opts ...OptFn) CloudFormation { - v2Config, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) +func New(v2Config aws.Config, opts ...OptFn) CloudFormation { client := CloudFormation{ - cfnClient: cloudformation.New(sess), + cfnClient: cloudformation.New(v2Config), codeStarClient: codestar.New(v2Config), cpClient: codepipeline.New(v2Config, v2Config), ecsClient: ecs.New(v2Config), cwClient: cloudwatch.New(v2Config, v2Config), regionalClient: func(region string) cfnClient { - return cloudformation.New(sess.Copy(&aws.Config{ - Region: aws.String(region), - })) + regionalV2Config := v2Config + regionalV2Config.Region = region + return cloudformation.New(regionalV2Config) }, regionalECRClient: func(region string) imageRemover { - regionalV2Config, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), region) + regionalV2Config := v2Config + regionalV2Config.Region = region return ecr.New(regionalV2Config) }, - appStackSet: stackset.New(sess), + appStackSet: stackset.New(v2Config), s3Client: s3.New(v2Config), regionalS3Client: func(region string) s3Client { - regionalV2Config, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), region) + regionalV2Config := v2Config + regionalV2Config.Region = region return s3.New(regionalV2Config) }, - region: aws.StringValue(sess.Config.Region), + region: v2Config.Region, console: new(discardFile), } for _, opt := range opts { @@ -267,7 +267,7 @@ func (cf CloudFormation) errorEvents(stackName string) ([]string, error) { var reasons []string for _, event := range events { // CFN error messages end with a '. (Service' and only the first sentence is useful, the rest is error codes. - reasons = append(reasons, strings.Split(aws.StringValue(event.ResourceStatusReason), ". (Service")[0]) + reasons = append(reasons, strings.Split(aws.ToString(event.ResourceStatusReason), ". (Service")[0]) } return reasons, nil } @@ -451,8 +451,8 @@ func (cf CloudFormation) waitForSignalAndHandleInterrupt(in signalHandlerInput) if err != nil { return fmt.Errorf("describe stack %s: %w", in.stackName, err) } - switch aws.StringValue(stackDescr.StackStatus) { - case sdkcloudformation.StackStatusCreateInProgress: + switch stackDescr.StackStatus { + case types.StackStatusCreateInProgress: log.Infoln() log.Infof(`Received Interrupt for Ctrl-C. Pressing Ctrl-C again will exit immediately but the deletion of stack %s will continue @@ -469,7 +469,7 @@ Pressing Ctrl-C again will exit immediately but the deletion of stack %s will co return err } return &ErrStackDeletedOnInterrupt{stackName: in.stackName} - case sdkcloudformation.StackStatusUpdateInProgress: + case types.StackStatusUpdateInProgress: log.Infoln() log.Infof(`Received Interrupt for Ctrl-C. Pressing Ctrl-C again will exit immediately but stack %s rollback will continue @@ -514,7 +514,7 @@ func (cf CloudFormation) cancelUpdateAndRender(in *cancelUpdateAndRenderInput) e ctx, cancel := context.WithTimeout(context.Background(), waitForStackTimeout) defer cancel() g, ctx := errgroup.WithContext(ctx) - renderer, err := cf.createChangeSetRenderer(g, ctx, aws.StringValue(stackDescr.ChangeSetId), in.stackName, in.description, progress.RenderOptions{}) + renderer, err := cf.createChangeSetRenderer(g, ctx, aws.ToString(stackDescr.ChangeSetId), in.stackName, in.description, progress.RenderOptions{}) if err != nil { return err } @@ -536,8 +536,8 @@ func (cf CloudFormation) errOnFailedCancelUpdate(stackName string) error { if err != nil { return fmt.Errorf("describe stack %s: %w", stackName, err) } - status := aws.StringValue(stack.StackStatus) - if status != sdkcloudformation.StackStatusUpdateRollbackComplete { + status := string(stack.StackStatus) + if status != string(types.StackStatusUpdateRollbackComplete) { return fmt.Errorf("stack %s did not rollback successfully and exited with status %s", stackName, status) } return nil @@ -608,34 +608,35 @@ func (cf CloudFormation) createChangeSetRenderer(group *errgroup.Group, ctx cont } type changeRenderersInput struct { - g *errgroup.Group // Group that all goroutines belong. - ctx context.Context // Context associated with the group. - stackName string // Name of the stack. - stackStreamer progress.StackSubscriber // Streamer for the stack where changes belong. - changes []*sdkcloudformation.Change // List of changes that will be applied to the stack. - changeSetTimestamp time.Time // ChangeSet creation time. - descriptions map[string]string // Descriptions for the logical IDs of the changes. - opts progress.RenderOptions // Display options that should be applied to the changes. + g *errgroup.Group // Group that all goroutines belong. + ctx context.Context // Context associated with the group. + stackName string // Name of the stack. + stackStreamer progress.StackSubscriber // Streamer for the stack where changes belong. + changes []types.Change // List of changes that will be applied to the stack. + changeSetTimestamp time.Time // ChangeSet creation time. + descriptions map[string]string // Descriptions for the logical IDs of the changes. + opts progress.RenderOptions // Display options that should be applied to the changes. } // changeRenderers filters changes by resources that have a description and returns the appropriate progress.Renderer for each resource type. func (cf CloudFormation) changeRenderers(in changeRenderersInput) ([]progress.Renderer, error) { var resources []progress.Renderer for _, change := range in.changes { - logicalID := aws.StringValue(change.ResourceChange.LogicalResourceId) + change := change + logicalID := aws.ToString(change.ResourceChange.LogicalResourceId) description, ok := in.descriptions[logicalID] if !ok { continue } var renderer progress.Renderer switch { - case aws.StringValue(change.ResourceChange.ResourceType) == envControllerResourceType: + case aws.ToString(change.ResourceChange.ResourceType) == envControllerResourceType: r, err := cf.createEnvControllerRenderer(&envControllerRendererInput{ g: in.g, ctx: in.ctx, workloadStackName: in.stackName, workloadTimestamp: in.changeSetTimestamp, - change: change, + change: &change, description: description, serviceStack: in.stackStreamer, renderOpts: in.opts, @@ -644,7 +645,7 @@ func (cf CloudFormation) changeRenderers(in changeRenderersInput) ([]progress.Re return nil, err } renderer = r - case aws.StringValue(change.ResourceChange.ResourceType) == ecsServiceResourceType: + case aws.ToString(change.ResourceChange.ResourceType) == ecsServiceResourceType: renderer = progress.ListeningECSServiceResourceRenderer(progress.ECSServiceRendererCfg{ Streamer: in.stackStreamer, ECSClient: cf.ecsClient, @@ -659,8 +660,8 @@ func (cf CloudFormation) changeRenderers(in changeRenderersInput) ([]progress.Re }) case change.ResourceChange.ChangeSetId != nil: // The resource change is a nested stack. - changeSetID := aws.StringValue(change.ResourceChange.ChangeSetId) - stackName := parseStackNameFromARN(aws.StringValue(change.ResourceChange.PhysicalResourceId)) + changeSetID := aws.ToString(change.ResourceChange.ChangeSetId) + stackName := parseStackNameFromARN(aws.ToString(change.ResourceChange.PhysicalResourceId)) r, err := cf.createChangeSetRenderer(in.g, in.ctx, changeSetID, stackName, description, in.opts) if err != nil { @@ -682,7 +683,7 @@ type envControllerRendererInput struct { ctx context.Context workloadStackName string workloadTimestamp time.Time - change *sdkcloudformation.Change + change *types.Change description string serviceStack progress.StackSubscriber renderOpts progress.RenderOptions @@ -719,7 +720,7 @@ func (cf CloudFormation) createEnvControllerRenderer(in *envControllerRendererIn Description: in.description, RenderOpts: in.renderOpts, ActionStreamer: in.serviceStack, - ActionLogicalID: aws.StringValue(in.change.ResourceChange.LogicalResourceId), + ActionLogicalID: aws.ToString(in.change.ResourceChange.LogicalResourceId), EnvStreamer: envStreamer, CancelEnvStream: cancel, EnvStackName: envStackName, @@ -782,7 +783,7 @@ func (cf CloudFormation) deleteAndRenderStack(in deleteAndRenderInput) error { g.Go(in.deleteFn) renderer := cf.stackRenderer(ctx, renderStackInput{ group: g, - stackID: aws.StringValue(stack.StackId), + stackID: aws.ToString(stack.StackId), stackName: in.stackName, description: in.description, descriptionFor: descriptionFor, @@ -833,12 +834,12 @@ func (cf CloudFormation) errOnFailedStack(stackName string) error { if err != nil { return err } - status := aws.StringValue(stack.StackStatus) + status := string(stack.StackStatus) if cloudformation.StackStatus(status).IsFailure() { events, _ := cf.cfnClient.ErrorEvents(stackName) var failedResourceType string if len(events) > 0 { - failedResourceType = aws.StringValue(events[0].ResourceType) + failedResourceType = aws.ToString(events[0].ResourceType) } return &errFailedService{ stackName: stackName, @@ -855,52 +856,87 @@ func toStack(config StackConfiguration) (*cloudformation.Stack, error) { return nil, err } stack := cloudformation.NewStack(config.StackName(), template) - stack.Parameters, err = config.Parameters() + params, err := config.Parameters() if err != nil { return nil, err } - stack.Tags = config.Tags() + stack.Parameters = flattenParameters(params) + stack.Tags = flattenTags(config.Tags()) return stack, nil } func toStackFromS3(config StackConfiguration, s3url string) (*cloudformation.Stack, error) { stack := cloudformation.NewStackWithURL(config.StackName(), s3url) var err error - stack.Parameters, err = config.Parameters() + params, err := config.Parameters() if err != nil { return nil, err } - stack.Tags = config.Tags() + stack.Parameters = flattenParameters(params) + stack.Tags = flattenTags(config.Tags()) return stack, nil } -func toMap(tags []*sdkcloudformation.Tag) map[string]string { +func toMap(tags []types.Tag) map[string]string { m := make(map[string]string) for _, t := range tags { - m[aws.StringValue(t.Key)] = aws.StringValue(t.Value) + m[aws.ToString(t.Key)] = aws.ToString(t.Value) } return m } +func toMapPtr(tags []*types.Tag) map[string]string { + m := make(map[string]string) + for _, t := range tags { + if t == nil { + continue + } + m[aws.ToString(t.Key)] = aws.ToString(t.Value) + } + return m +} + +func flattenParameters(params []*types.Parameter) []types.Parameter { + flat := make([]types.Parameter, 0, len(params)) + for _, param := range params { + if param == nil { + continue + } + flat = append(flat, *param) + } + return flat +} + +func flattenTags(tags []*types.Tag) []types.Tag { + flat := make([]types.Tag, 0, len(tags)) + for _, tag := range tags { + if tag == nil { + continue + } + flat = append(flat, *tag) + } + return flat +} + // parseStackNameFromARN retrieves "my-nested-stack" from an input like: // arn:aws:cloudformation:us-west-2:123456789012:stack/my-nested-stack/d0a825a0-e4cd-xmpl-b9fb-061c69e99205 func parseStackNameFromARN(stackARN string) string { return strings.Split(stackARN, "/")[1] } -func parseAppNameFromTags(tags []*sdkcloudformation.Tag) string { +func parseAppNameFromTags(tags []types.Tag) string { for _, t := range tags { - if aws.StringValue(t.Key) == deploy.AppTagKey { - return aws.StringValue(t.Value) + if aws.ToString(t.Key) == deploy.AppTagKey { + return aws.ToString(t.Value) } } return "" } -func parseEnvNameFromTags(tags []*sdkcloudformation.Tag) string { +func parseEnvNameFromTags(tags []types.Tag) string { for _, t := range tags { - if aws.StringValue(t.Key) == deploy.EnvTagKey { - return aws.StringValue(t.Value) + if aws.ToString(t.Key) == deploy.EnvTagKey { + return aws.ToString(t.Value) } } return "" diff --git a/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go b/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go index 664baf75fbf..196c02f67d3 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go +++ b/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go @@ -28,7 +28,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" + awsv1 "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/session" awsCF "github.com/aws/aws-sdk-go/service/cloudformation" @@ -50,11 +52,11 @@ func init() { func Test_App_Infrastructure(t *testing.T) { sess, err := testSession(nil) require.NoError(t, err) - identity := identity.New(sess) + identity := identity.New(v2ConfigFromSessionRegion(sess)) callerInfo, err := identity.Get() require.NoError(t, err) require.NoError(t, err) - deployer := cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) + deployer := cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)) cfClient := awsCF.New(sess) require.NoError(t, err) version.Version = "v1.28.0" @@ -394,14 +396,14 @@ func Test_Environment_Deployment_Integration(t *testing.T) { version.Version = "v1.28.0" sess, err := testSession(nil) require.NoError(t, err) - deployer := cloudformation.New(sess, cloudformation.WithProgressTracker(os.Stderr)) + deployer := cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)) cfClient := awsCF.New(sess) - identity := identity.New(sess) + identity := identity.New(v2ConfigFromSessionRegion(sess)) s3ManagerClient := s3manager.NewUploader(sess) - s3Config, err := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) + s3Config, err := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(sess.Config.Region)) require.NoError(t, err) s3Client := awss3.New(s3Config) - iamClient := iam.New(sess) + iamClient := iam.New(v2ConfigFromSessionRegion(sess)) id, err := identity.Get() require.NoError(t, err) @@ -523,7 +525,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { require.NoError(t, err) lastForceUpdateID, err := deployer.ForceUpdateOutputID(environmentToDeploy.App.Name, environmentToDeploy.Name) require.NoError(t, err) - conf, err := stack.NewEnvConfigFromExistingStack(&environmentToDeploy, lastForceUpdateID, oldParams) + conf, err := stack.NewEnvConfigFromExistingStack(&environmentToDeploy, lastForceUpdateID, parameterPtrs(oldParams)) require.NoError(t, err) // Deploy the environment and wait for it to be complete. require.NoError(t, deployer.UpdateAndRenderEnvironment(conf, environmentToDeploy.ArtifactBucketARN, false)) @@ -538,7 +540,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { deployedStack := output.Stacks[0] expectedResultsForKey := map[string]func(*awsCF.Output){ "EnabledFeatures": func(output *awsCF.Output) { - require.Equal(t, ",,,,,", aws.StringValue(output.OutputValue), "no env features enabled by default") + require.Equal(t, ",,,,,", aws.ToString(output.OutputValue), "no env features enabled by default") }, "EnvironmentManagerRoleARN": func(output *awsCF.Output) { require.Equal(t, @@ -641,7 +643,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { "EnvironmentSecurityGroup value should not be nil") }, "LastForceDeployID": func(output *awsCF.Output) { - require.Equal(t, lastForceUpdateID, aws.StringValue(output.OutputValue), "last force update id does not change by default") + require.Equal(t, lastForceUpdateID, aws.ToString(output.OutputValue), "last force update id does not change by default") }, } require.True(t, len(deployedStack.Outputs) == len(expectedResultsForKey), @@ -670,14 +672,27 @@ func testSession(region *string) (*session.Session, error) { // override with the provided region return session.NewSessionWithOptions(session.Options{ - Config: aws.Config{ - CredentialsChainVerboseErrors: aws.Bool(true), + Config: awsv1.Config{ + CredentialsChainVerboseErrors: awsv1.Bool(true), Region: region, }, SharedConfigState: session.SharedConfigEnable, }) } +func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { + cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(sess.Config.Region)) + return cfg +} + +func parameterPtrs(params []types.Parameter) []*types.Parameter { + ptrs := make([]*types.Parameter, 0, len(params)) + for i := range params { + ptrs = append(ptrs, ¶ms[i]) + } + return ptrs +} + func randStringBytes(n int) string { b := make([]byte, n) for i := range b { diff --git a/internal/pkg/deploy/cloudformation/cloudformation_test.go b/internal/pkg/deploy/cloudformation/cloudformation_test.go index faff75362d1..d7fa886fb27 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation_test.go +++ b/internal/pkg/deploy/cloudformation/cloudformation_test.go @@ -18,9 +18,10 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" + "github.com/aws/aws-sdk-go-v2/aws" + sdkcloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" + sdkcloudformationtypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" - sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -254,18 +255,18 @@ func testDeployWorkload_StreamUntilStackCreationFails(t *testing.T, stackName st m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.ChangeSetDescription{}, nil) m.EXPECT().TemplateBodyFromChangeSet(gomock.Any(), gomock.Any()).Return("", nil) m.EXPECT().DescribeStackEvents(gomock.Any()).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("2"), LogicalResourceId: aws.String(stackName), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_FAILED"), // Send failure event for stack. + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_FAILED"), // Send failure event for stack. Timestamp: aws.Time(time.Now()), }, }, }, nil).AnyTimes() m.EXPECT().Describe(stackName).Return(&cloudformation.StackDescription{ - StackStatus: aws.String("CREATE_FAILED"), + StackStatus: sdkcloudformationtypes.StackStatus("CREATE_FAILED"), }, nil) m.EXPECT().ErrorEvents(stackName).Return( []cloudformation.StackEvent{ @@ -273,7 +274,7 @@ func testDeployWorkload_StreamUntilStackCreationFails(t *testing.T, stackName st EventId: aws.String("2"), LogicalResourceId: aws.String(stackName), PhysicalResourceId: aws.String("AWS::AppRunner::Service"), - ResourceStatus: aws.String("CREATE_FAILED"), // Send failure event for stack. + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_FAILED"), // Send failure event for stack. Timestamp: aws.Time(time.Now()), }, }, nil) @@ -304,9 +305,9 @@ func testDeployWorkload_RenderNewlyCreatedStackWithECSService(t *testing.T, stac mockCFN.EXPECT().Create(gomock.Any()).Return("1234", nil) mockCFN.EXPECT().DescribeChangeSet("1234", stackName).Return(&cloudformation.ChangeSetDescription{ - Changes: []*sdkcloudformation.Change{ + Changes: []sdkcloudformationtypes.Change{ { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ LogicalResourceId: aws.String("Service"), ResourceType: aws.String("AWS::ECS::Service"), }, @@ -323,13 +324,13 @@ Resources: mockCFN.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String(stackName), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("1"), LogicalResourceId: aws.String("Service"), PhysicalResourceId: aws.String("arn:aws:ecs:us-west-2:1111:service/cluster/service"), ResourceType: aws.String("AWS::ECS::Service"), - ResourceStatus: aws.String("CREATE_IN_PROGRESS"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_IN_PROGRESS"), Timestamp: aws.Time(deploymentTime), }, { @@ -337,14 +338,14 @@ Resources: LogicalResourceId: aws.String("Service"), PhysicalResourceId: aws.String("arn:aws:ecs:us-west-2:1111:service/cluster/service"), ResourceType: aws.String("AWS::ECS::Service"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(deploymentTime), }, { EventId: aws.String("3"), LogicalResourceId: aws.String(stackName), ResourceType: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(deploymentTime), }, }, @@ -361,7 +362,7 @@ Resources: }, nil) mockECS.EXPECT().StoppedServiceTasks("cluster", "service").Return(nil, nil) mockCFN.EXPECT().Describe(stackName).Return(&cloudformation.StackDescription{ - StackStatus: aws.String("CREATE_COMPLETE"), + StackStatus: sdkcloudformationtypes.StackStatus("CREATE_COMPLETE"), }, nil) buf := new(strings.Builder) client := CloudFormation{cfnClient: mockCFN, ecsClient: mockECS, s3Client: mS3Client, console: mockFileWriter{Writer: buf}, @@ -392,12 +393,12 @@ func testDeployWorkload_WithEnvControllerRenderer_NoStackUpdates(t *testing.T, s mockCFN.EXPECT().Create(gomock.Any()).Return("1234", nil) mockCFN.EXPECT().DescribeChangeSet("1234", svcStackName).Return(&cloudformation.ChangeSetDescription{ - Changes: []*sdkcloudformation.Change{ + Changes: []sdkcloudformationtypes.Change{ { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ LogicalResourceId: aws.String("EnvControllerAction"), ResourceType: aws.String("Custom::EnvControllerFunction"), - Action: aws.String(sdkcloudformation.ChangeActionAdd), + Action: sdkcloudformationtypes.ChangeActionAdd, }, }, }, @@ -409,7 +410,7 @@ Resources: 'aws:copilot:description': "Updating environment" `, nil) mockCFN.EXPECT().Describe(svcStackName).Return(&cloudformation.StackDescription{ - Tags: []*sdkcloudformation.Tag{ + Tags: []sdkcloudformationtypes.Tag{ { Key: aws.String("copilot-application"), Value: aws.String("my-app"), @@ -429,12 +430,12 @@ Resources: mockCFN.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String(svcStackName), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("1"), LogicalResourceId: aws.String(svcStackName), ResourceType: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(deploymentTime), }, }, @@ -442,11 +443,11 @@ Resources: mockCFN.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String("my-app-my-env"), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{}, // No updates for the env stack. + StackEvents: []sdkcloudformationtypes.StackEvent{}, // No updates for the env stack. }, nil).AnyTimes() mockCFN.EXPECT().Describe(svcStackName).Return(&cloudformation.StackDescription{ - StackStatus: aws.String("CREATE_COMPLETE"), + StackStatus: sdkcloudformationtypes.StackStatus("CREATE_COMPLETE"), }, nil) buf := new(strings.Builder) client := CloudFormation{cfnClient: mockCFN, s3Client: mS3Client, console: mockFileWriter{Writer: buf}, @@ -474,15 +475,15 @@ func testDeployWorkload_RenderNewlyCreatedStackWithAddons(t *testing.T, stackNam // Mocks for the parent stack. m.EXPECT().Create(gomock.Any()).Return("1234", nil) m.EXPECT().DescribeChangeSet("1234", stackName).Return(&cloudformation.ChangeSetDescription{ - Changes: []*sdkcloudformation.Change{ + Changes: []sdkcloudformationtypes.Change{ { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ LogicalResourceId: aws.String("Cluster"), PhysicalResourceId: aws.String("AWS::ECS::Cluster"), }, }, { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ ChangeSetId: aws.String("5678"), LogicalResourceId: aws.String("AddonsStack"), PhysicalResourceId: aws.String("arn:aws:cloudformation:us-west-2:12345:stack/my-nested-stack/d0a825a0-e4cd-xmpl-b9fb-061c69e99205"), @@ -506,40 +507,40 @@ Resources: m.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String(stackName), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("1"), LogicalResourceId: aws.String("Cluster"), PhysicalResourceId: aws.String("AWS::ECS::Cluster"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, { EventId: aws.String("2"), LogicalResourceId: aws.String("AddonsStack"), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, { EventId: aws.String("3"), LogicalResourceId: aws.String(stackName), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, }, }, nil).AnyTimes() m.EXPECT().Describe(stackName).Return(&cloudformation.StackDescription{ - StackStatus: aws.String("CREATE_COMPLETE"), + StackStatus: sdkcloudformationtypes.StackStatus("CREATE_COMPLETE"), }, nil) // Mocks for the addons stack. m.EXPECT().DescribeChangeSet("5678", "my-nested-stack").Return(&cloudformation.ChangeSetDescription{ - Changes: []*sdkcloudformation.Change{ + Changes: []sdkcloudformationtypes.Change{ { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ LogicalResourceId: aws.String("MyTable"), PhysicalResourceId: aws.String("AWS::DynamoDB::Table"), }, @@ -557,19 +558,19 @@ Resources: m.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String("my-nested-stack"), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("1"), LogicalResourceId: aws.String("MyTable"), PhysicalResourceId: aws.String("AWS::DynamoDB::Table"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, { EventId: aws.String("2"), LogicalResourceId: aws.String("my-nested-stack"), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, }, @@ -712,18 +713,18 @@ func testDeployTask_StreamUntilStackCreationFails(t *testing.T, stackName string m.EXPECT().DescribeChangeSet(gomock.Any(), gomock.Any()).Return(&cloudformation.ChangeSetDescription{}, nil) m.EXPECT().TemplateBodyFromChangeSet(gomock.Any(), gomock.Any()).Return("", nil) m.EXPECT().DescribeStackEvents(gomock.Any()).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("2"), LogicalResourceId: aws.String(stackName), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_FAILED"), // Send failure event for stack. + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_FAILED"), // Send failure event for stack. Timestamp: aws.Time(time.Now()), }, }, }, nil).AnyTimes() m.EXPECT().Describe(stackName).Return(&cloudformation.StackDescription{ - StackStatus: aws.String("CREATE_FAILED"), + StackStatus: sdkcloudformationtypes.StackStatus("CREATE_FAILED"), }, nil) m.EXPECT().ErrorEvents(stackName).Return( []cloudformation.StackEvent{ @@ -731,7 +732,7 @@ func testDeployTask_StreamUntilStackCreationFails(t *testing.T, stackName string EventId: aws.String("2"), LogicalResourceId: aws.String(stackName), PhysicalResourceId: aws.String("AWS::AppRunner::Service"), - ResourceStatus: aws.String("CREATE_FAILED"), // Send failure event for stack. + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_FAILED"), // Send failure event for stack. Timestamp: aws.Time(time.Now()), }, }, nil) @@ -753,15 +754,15 @@ func testDeployTask_RenderNewlyCreatedStackWithAddons(t *testing.T, stackName st // Mocks for the parent stack. m.EXPECT().Create(gomock.Any()).Return("1234", nil) m.EXPECT().DescribeChangeSet("1234", stackName).Return(&cloudformation.ChangeSetDescription{ - Changes: []*sdkcloudformation.Change{ + Changes: []sdkcloudformationtypes.Change{ { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ LogicalResourceId: aws.String("Cluster"), PhysicalResourceId: aws.String("AWS::ECS::Cluster"), }, }, { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ ChangeSetId: aws.String("5678"), LogicalResourceId: aws.String("AddonsStack"), PhysicalResourceId: aws.String("arn:aws:cloudformation:us-west-2:12345:stack/my-nested-stack/d0a825a0-e4cd-xmpl-b9fb-061c69e99205"), @@ -785,40 +786,40 @@ Resources: m.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String(stackName), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("1"), LogicalResourceId: aws.String("Cluster"), PhysicalResourceId: aws.String("AWS::ECS::Cluster"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, { EventId: aws.String("2"), LogicalResourceId: aws.String("AddonsStack"), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, { EventId: aws.String("3"), LogicalResourceId: aws.String(stackName), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, }, }, nil).AnyTimes() m.EXPECT().Describe(stackName).Return(&cloudformation.StackDescription{ - StackStatus: aws.String("CREATE_COMPLETE"), + StackStatus: sdkcloudformationtypes.StackStatus("CREATE_COMPLETE"), }, nil) // Mocks for the addons stack. m.EXPECT().DescribeChangeSet("5678", "my-nested-stack").Return(&cloudformation.ChangeSetDescription{ - Changes: []*sdkcloudformation.Change{ + Changes: []sdkcloudformationtypes.Change{ { - ResourceChange: &sdkcloudformation.ResourceChange{ + ResourceChange: &sdkcloudformationtypes.ResourceChange{ LogicalResourceId: aws.String("MyTable"), PhysicalResourceId: aws.String("AWS::DynamoDB::Table"), }, @@ -836,19 +837,19 @@ Resources: m.EXPECT().DescribeStackEvents(&sdkcloudformation.DescribeStackEventsInput{ StackName: aws.String("my-nested-stack"), }).Return(&sdkcloudformation.DescribeStackEventsOutput{ - StackEvents: []*sdkcloudformation.StackEvent{ + StackEvents: []sdkcloudformationtypes.StackEvent{ { EventId: aws.String("1"), LogicalResourceId: aws.String("MyTable"), PhysicalResourceId: aws.String("AWS::DynamoDB::Table"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, { EventId: aws.String("2"), LogicalResourceId: aws.String("my-nested-stack"), PhysicalResourceId: aws.String("AWS::CloudFormation::Stack"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: sdkcloudformationtypes.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Now()), }, }, diff --git a/internal/pkg/deploy/cloudformation/env.go b/internal/pkg/deploy/cloudformation/env.go index 08e5a2bfb6b..87aa05d1f3c 100644 --- a/internal/pkg/deploy/cloudformation/env.go +++ b/internal/pkg/deploy/cloudformation/env.go @@ -10,7 +10,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" "gopkg.in/yaml.v3" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" @@ -18,8 +18,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/term/progress" - "github.com/aws/aws-sdk-go/aws" - awscfn "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/types" ) // CreateAndRenderEnvironment creates the CloudFormation stack for an environment, and render the stack creation to out. @@ -111,15 +111,15 @@ func (cf CloudFormation) ForceUpdateOutputID(app, env string) (string, error) { return "", err } for _, output := range stackDescr.Outputs { - if aws.StringValue(output.OutputKey) == template.LastForceDeployIDOutputName { - return aws.StringValue(output.OutputValue), nil + if aws.ToString(output.OutputKey) == template.LastForceDeployIDOutputName { + return aws.ToString(output.OutputValue), nil } } return "", nil } // DeployedEnvironmentParameters returns the environment stack's parameters. -func (cf CloudFormation) DeployedEnvironmentParameters(appName, envName string) ([]*awscfn.Parameter, error) { +func (cf CloudFormation) DeployedEnvironmentParameters(appName, envName string) ([]types.Parameter, error) { isInitial, err := cf.isInitialDeployment(appName, envName) if err != nil { return nil, err @@ -175,7 +175,7 @@ func (cf CloudFormation) waitAndDescribeStack(stackName string) (*cloudformation return nil, fmt.Errorf("describe stack %s: %w", stackName, err) } - if cloudformation.StackStatus(aws.StringValue(stackDescription.StackStatus)).InProgress() { + if cloudformation.StackStatus(stackDescription.StackStatus).InProgress() { // There is already an update happening to the environment stack. // Best-effort try to wait for the existing update to be over before retrying. _ = cf.cfnClient.WaitForUpdate(context.Background(), stackName) diff --git a/internal/pkg/deploy/cloudformation/env_test.go b/internal/pkg/deploy/cloudformation/env_test.go index bef92b8d935..3452d8c4517 100644 --- a/internal/pkg/deploy/cloudformation/env_test.go +++ b/internal/pkg/deploy/cloudformation/env_test.go @@ -10,8 +10,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - awscfn "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + awscfn "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -22,7 +22,7 @@ func TestCloudFormation_DeployedEnvironmentParameters(t *testing.T) { inEnvName string inClient func(ctrl *gomock.Controller) *mocks.MockcfnClient - wantedParams []*awscfn.Parameter + wantedParams []awscfn.Parameter wantedErr error }{ "error retrieving metadata": { @@ -51,7 +51,7 @@ func TestCloudFormation_DeployedEnvironmentParameters(t *testing.T) { m := mocks.NewMockcfnClient(ctrl) m.EXPECT().Metadata(gomock.Any()).Return(`Version: `, nil) m.EXPECT().Describe("phonetool-test").Return(&cloudformation.StackDescription{ - Parameters: []*awscfn.Parameter{ + Parameters: []awscfn.Parameter{ { ParameterKey: aws.String("name"), ParameterValue: aws.String("test"), @@ -61,7 +61,7 @@ func TestCloudFormation_DeployedEnvironmentParameters(t *testing.T) { return m }, - wantedParams: []*awscfn.Parameter{ + wantedParams: []awscfn.Parameter{ { ParameterKey: aws.String("name"), ParameterValue: aws.String("test"), @@ -113,7 +113,7 @@ func TestCloudFormation_ForceUpdateID(t *testing.T) { inClient: func(ctrl *gomock.Controller) *mocks.MockcfnClient { m := mocks.NewMockcfnClient(ctrl) m.EXPECT().Describe("phonetool-test").Return(&cloudformation.StackDescription{ - Outputs: []*awscfn.Output{ + Outputs: []awscfn.Output{ { OutputKey: aws.String(template.LastForceDeployIDOutputName), OutputValue: aws.String("mockForceUpdateID"), @@ -183,13 +183,13 @@ func TestCloudFormation_UpdateEnvironmentTemplate(t *testing.T) { inExecRoleARN: "arn", inClient: func(t *testing.T, ctrl *gomock.Controller) *mocks.MockcfnClient { m := mocks.NewMockcfnClient(ctrl) - params := []*awscfn.Parameter{ + params := []awscfn.Parameter{ { ParameterKey: aws.String("ALBWorkloads"), ParameterValue: aws.String("frontend"), }, } - tags := []*awscfn.Tag{ + tags := []awscfn.Tag{ { Key: aws.String("copilot-application"), Value: aws.String("phonetool"), diff --git a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go index 7aee7d59b7d..31796bf2272 100644 --- a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go +++ b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./internal/pkg/deploy/cloudformation/cloudformation.go +// Source: internal/pkg/deploy/cloudformation/cloudformation.go // Package mocks is a generated GoMock package. package mocks @@ -13,7 +13,8 @@ import ( stackset "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation/stackset" cloudwatch "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" ecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" - cloudformation0 "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation0 "github.com/aws/aws-sdk-go-v2/service/cloudformation" + types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" gomock "github.com/golang/mock/gomock" ) @@ -41,10 +42,10 @@ func (m *MockStackConfiguration) EXPECT() *MockStackConfigurationMockRecorder { } // Parameters mocks base method. -func (m *MockStackConfiguration) Parameters() ([]*cloudformation0.Parameter, error) { +func (m *MockStackConfiguration) Parameters() ([]*types.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Parameters") - ret0, _ := ret[0].([]*cloudformation0.Parameter) + ret0, _ := ret[0].([]*types.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -85,10 +86,10 @@ func (mr *MockStackConfigurationMockRecorder) StackName() *gomock.Call { } // Tags mocks base method. -func (m *MockStackConfiguration) Tags() []*cloudformation0.Tag { +func (m *MockStackConfiguration) Tags() []*types.Tag { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Tags") - ret0, _ := ret[0].([]*cloudformation0.Tag) + ret0, _ := ret[0].([]*types.Tag) return ret0 } diff --git a/internal/pkg/deploy/cloudformation/pipeline.go b/internal/pkg/deploy/cloudformation/pipeline.go index b1987b7f577..df84a626912 100644 --- a/internal/pkg/deploy/cloudformation/pipeline.go +++ b/internal/pkg/deploy/cloudformation/pipeline.go @@ -12,7 +12,7 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy" @@ -85,8 +85,8 @@ func (cf CloudFormation) pipelinePhysicalResourceID(stackName string) (string, e return "", err } for _, resource := range stackResources { - if aws.StringValue(resource.LogicalResourceId) == cfnLogicalResourceIDPipeline && aws.StringValue(resource.ResourceType) == cfnResourceTypePipeline { - return aws.StringValue(resource.PhysicalResourceId), nil + if aws.ToString(resource.LogicalResourceId) == cfnLogicalResourceIDPipeline && aws.ToString(resource.ResourceType) == cfnResourceTypePipeline { + return aws.ToString(resource.PhysicalResourceId), nil } } return "", fmt.Errorf(`cannot find a resource in stack %s with logical ID "%s" of type "%s"`, stackName, cfnLogicalResourceIDPipeline, cfnResourceTypePipeline) diff --git a/internal/pkg/deploy/cloudformation/pipeline_test.go b/internal/pkg/deploy/cloudformation/pipeline_test.go index 97863977c42..f2cba4a62b0 100644 --- a/internal/pkg/deploy/cloudformation/pipeline_test.go +++ b/internal/pkg/deploy/cloudformation/pipeline_test.go @@ -13,8 +13,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" - "github.com/aws/aws-sdk-go/aws" - sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + sdkcloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) func TestCloudFormation_PipelineExists(t *testing.T) { diff --git a/internal/pkg/deploy/cloudformation/stack/app.go b/internal/pkg/deploy/cloudformation/stack/app.go index f6ebfdd5677..6d4665ba423 100644 --- a/internal/pkg/deploy/cloudformation/stack/app.go +++ b/internal/pkg/deploy/cloudformation/stack/app.go @@ -8,8 +8,8 @@ import ( "sort" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "gopkg.in/yaml.v3" "github.com/aproint/copilot-cli/internal/pkg/aws/ecr" diff --git a/internal/pkg/deploy/cloudformation/stack/app_test.go b/internal/pkg/deploy/cloudformation/stack/app_test.go index 5f6ebc03792..5871bd43d37 100644 --- a/internal/pkg/deploy/cloudformation/stack/app_test.go +++ b/internal/pkg/deploy/cloudformation/stack/app_test.go @@ -12,8 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -352,9 +352,9 @@ func TestDNSDelegatedAccountsForStack(t *testing.T) { } func mockAppResourceStack(stackArn string, outputs map[string]string) *cloudformation.Stack { - outputList := []*cloudformation.Output{} + outputList := []cloudformation.Output{} for key, val := range outputs { - outputList = append(outputList, &cloudformation.Output{ + outputList = append(outputList, cloudformation.Output{ OutputKey: aws.String(key), OutputValue: aws.String(val), }) @@ -367,9 +367,9 @@ func mockAppResourceStack(stackArn string, outputs map[string]string) *cloudform } func mockAppRolesStack(stackArn string, parameters map[string]string) *cloudformation.Stack { - parameterList := []*cloudformation.Parameter{} + parameterList := []cloudformation.Parameter{} for key, val := range parameters { - parameterList = append(parameterList, &cloudformation.Parameter{ + parameterList = append(parameterList, cloudformation.Parameter{ ParameterKey: aws.String(key), ParameterValue: aws.String(val), }) diff --git a/internal/pkg/deploy/cloudformation/stack/backend_svc.go b/internal/pkg/deploy/cloudformation/stack/backend_svc.go index a98381128dc..05c8c48f5d4 100644 --- a/internal/pkg/deploy/cloudformation/stack/backend_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/backend_svc.go @@ -15,8 +15,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) // BackendService represents the configuration needed to create a CloudFormation stack from a backend service manifest. @@ -63,8 +63,8 @@ func NewBackendService(conf BackendServiceConfig, opts ...BackendServiceOption) b := &BackendService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(conf.Manifest.Name), - env: aws.StringValue(conf.EnvManifest.Name), + name: aws.ToString(conf.Manifest.Name), + env: aws.ToString(conf.EnvManifest.Name), app: conf.App.Name, permBound: conf.App.PermissionsBoundary, artifactBucketName: conf.ArtifactBucketName, @@ -181,7 +181,7 @@ func (s *BackendService) Template() (string, error) { AddonsExtraParams: addonsParams, Autoscaling: autoscaling, CapacityProviders: capacityProviders, - CredentialsParameter: aws.StringValue(s.manifest.ImageConfig.Image.Credentials), + CredentialsParameter: aws.ToString(s.manifest.ImageConfig.Image.Credentials), DeploymentConfiguration: convertDeploymentConfig(s.manifest.DeployConfig), DesiredCountOnSpot: desiredCountOnSpot, DependsOn: convertDependsOn(s.manifest.ImageConfig.Image.DependsOn), @@ -213,7 +213,7 @@ func (s *BackendService) Template() (string, error) { // Additional options for request driven web service templates. Observability: template.ObservabilityOpts{ - Tracing: strings.ToUpper(aws.StringValue(s.manifest.Observability.Tracing)), + Tracing: strings.ToUpper(aws.ToString(s.manifest.Observability.Tracing)), }, }) if err != nil { diff --git a/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go b/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go index 77d8207321d..8341280e07f 100644 --- a/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go +++ b/internal/pkg/deploy/cloudformation/stack/backend_svc_test.go @@ -19,8 +19,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack/mocks" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -617,7 +617,7 @@ func TestBackendService_Parameters(t *testing.T) { conf := &BackendService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(testBackendSvcManifest.Name), + name: aws.ToString(testBackendSvcManifest.Name), env: testEnvName, app: testAppName, image: manifest.Image{ diff --git a/internal/pkg/deploy/cloudformation/stack/env.go b/internal/pkg/deploy/cloudformation/stack/env.go index da75a7e2e4a..25d5cfbb2cb 100644 --- a/internal/pkg/deploy/cloudformation/stack/env.go +++ b/internal/pkg/deploy/cloudformation/stack/env.go @@ -14,9 +14,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/google/uuid" ) @@ -333,11 +333,11 @@ func (e *Env) transformParameters(currParams, oldParams []*cloudformation.Parame // Make a map out of `currParams` and out of `oldParams`. curr := make(map[string]*cloudformation.Parameter) for _, p := range currParams { - curr[aws.StringValue(p.ParameterKey)] = p + curr[aws.ToString(p.ParameterKey)] = p } old := make(map[string]*cloudformation.Parameter) for _, p := range oldParams { - old[aws.StringValue(p.ParameterKey)] = p + old[aws.ToString(p.ParameterKey)] = p } // Remove or transform each of the current parameters. @@ -365,7 +365,7 @@ func transformEnvControllerParameters(new, old *cloudformation.Parameter) *cloud for _, f := range template.AvailableEnvFeatures() { isEnvControllerManaged[f] = struct{}{} } - if _, ok := isEnvControllerManaged[aws.StringValue(new.ParameterKey)]; !ok { + if _, ok := isEnvControllerManaged[aws.ToString(new.ParameterKey)]; !ok { return new } if old == nil { // The EnvController-managed parameter doesn't exist in the old stack. Use the new value. @@ -384,7 +384,7 @@ func (e *Env) transformServiceDiscoveryEndpoint(new, old *cloudformation.Paramet if new == nil { return nil } - if aws.StringValue(new.ParameterKey) != EnvParamServiceDiscoveryEndpoint { + if aws.ToString(new.ParameterKey) != EnvParamServiceDiscoveryEndpoint { return new } if old == nil { @@ -488,7 +488,7 @@ func (e *Env) cdnConfig() *template.CDNConfig { mftConfig := e.in.Mft.CDNConfig.Config config := &template.CDNConfig{ ImportedCertificate: mftConfig.Certificate, - TerminateTLS: aws.BoolValue(mftConfig.TerminateTLS), + TerminateTLS: aws.ToBool(mftConfig.TerminateTLS), } if !mftConfig.Static.IsEmpty() { config.Static = &template.CDNStaticAssetConfig{ @@ -587,7 +587,7 @@ func (e *Env) telemetryConfig() *template.Telemetry { // If a manifest is present, it is the only place we look at. if e.in.Mft != nil { return &template.Telemetry{ - EnableContainerInsights: aws.BoolValue(e.in.Mft.Observability.ContainerInsights), + EnableContainerInsights: aws.ToBool(e.in.Mft.Observability.ContainerInsights), } } diff --git a/internal/pkg/deploy/cloudformation/stack/env_test.go b/internal/pkg/deploy/cloudformation/stack/env_test.go index 58cc2f417bd..c24bbd272c0 100644 --- a/internal/pkg/deploy/cloudformation/stack/env_test.go +++ b/internal/pkg/deploy/cloudformation/stack/env_test.go @@ -16,8 +16,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack/mocks" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -1246,7 +1246,7 @@ func TestBootstrapEnv_ToEnv(t *testing.T) { func mockEnvironmentStack(stackArn, managerRoleARN, executionRoleARN string) *cloudformation.Stack { return &cloudformation.Stack{ StackId: aws.String(stackArn), - Outputs: []*cloudformation.Output{ + Outputs: []cloudformation.Output{ { OutputKey: aws.String(envOutputManagerRoleKey), OutputValue: aws.String(managerRoleARN), diff --git a/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go index cdad16922b1..ce9f08eea8b 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_grpc_web_service_integration_test.go @@ -20,8 +20,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) @@ -54,7 +53,7 @@ func TestGrpcLoadBalancedWebService_Template(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -70,7 +69,7 @@ func TestGrpcLoadBalancedWebService_Template(t *testing.T) { require.NoError(t, err) ws, err := workspace.Use(fs) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go index 0b026293c2c..376721d2061 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_network_web_service_integration_test.go @@ -19,8 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" @@ -73,7 +72,7 @@ func TestNetworkLoadBalancedWebService_Template(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -91,7 +90,7 @@ func TestNetworkLoadBalancedWebService_Template(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go index 59675620050..2a1bc78d673 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_web_service_integration_test.go @@ -17,8 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "gopkg.in/yaml.v3" @@ -94,7 +93,7 @@ func TestLoadBalancedWebService_TemplateInteg(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -112,7 +111,7 @@ func TestLoadBalancedWebService_TemplateInteg(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go b/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go index 4a1c04f3191..84d76b12e49 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_web_svc.go @@ -17,8 +17,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) // Parameter logical IDs for a load balanced web service. @@ -94,8 +94,8 @@ func NewLoadBalancedWebService(conf LoadBalancedWebServiceConfig, s := &LoadBalancedWebService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(conf.Manifest.Name), - env: aws.StringValue(conf.EnvManifest.Name), + name: aws.ToString(conf.Manifest.Name), + env: aws.ToString(conf.EnvManifest.Name), app: conf.App.Name, permBound: conf.App.PermissionsBoundary, artifactBucketName: conf.ArtifactBucketName, @@ -217,7 +217,7 @@ func (s *LoadBalancedWebService) Template() (string, error) { AddonsExtraParams: addonsParams, Autoscaling: autoscaling, CapacityProviders: capacityProviders, - CredentialsParameter: aws.StringValue(s.manifest.ImageConfig.Image.Credentials), + CredentialsParameter: aws.ToString(s.manifest.ImageConfig.Image.Credentials), DesiredCountOnSpot: desiredCountOnSpot, DeploymentConfiguration: convertDeploymentConfig(s.manifest.DeployConfig), DependsOn: convertDependsOn(s.manifest.ImageConfig.Image.DependsOn), @@ -248,7 +248,7 @@ func (s *LoadBalancedWebService) Template() (string, error) { // Additional options for request driven web service templates. Observability: template.ObservabilityOpts{ - Tracing: strings.ToUpper(aws.StringValue(s.manifest.Observability.Tracing)), + Tracing: strings.ToUpper(aws.ToString(s.manifest.Observability.Tracing)), }, // Sidecar configs. diff --git a/internal/pkg/deploy/cloudformation/stack/lb_web_svc_test.go b/internal/pkg/deploy/cloudformation/stack/lb_web_svc_test.go index c13f4eb9902..ecb396e7593 100644 --- a/internal/pkg/deploy/cloudformation/stack/lb_web_svc_test.go +++ b/internal/pkg/deploy/cloudformation/stack/lb_web_svc_test.go @@ -20,8 +20,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -893,12 +893,12 @@ func TestLoadBalancedWebService_Parameters(t *testing.T) { conf := &LoadBalancedWebService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(testManifest.Name), + name: aws.ToString(testManifest.Name), env: testEnvName, app: testAppName, rc: RuntimeConfig{ PushedImages: map[string]ECRImage{ - aws.StringValue(testManifest.Name): { + aws.ToString(testManifest.Name): { RepoURL: testImageRepoURL, ImageTag: testImageTag, }, @@ -1002,7 +1002,7 @@ func TestLoadBalancedWebService_Tags(t *testing.T) { conf := &LoadBalancedWebService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(testLBWebServiceManifest.Name), + name: aws.ToString(testLBWebServiceManifest.Name), env: testEnvName, app: testAppName, rc: RuntimeConfig{ diff --git a/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go b/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go index 0f2160ae2d0..4c23ae8abb5 100644 --- a/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go +++ b/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: ./internal/pkg/deploy/cloudformation/stack/workload.go +// Source: internal/pkg/deploy/cloudformation/stack/workload.go // Package mocks is a generated GoMock package. package mocks @@ -7,7 +7,7 @@ package mocks import ( reflect "reflect" - cloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" gomock "github.com/golang/mock/gomock" ) @@ -176,10 +176,10 @@ func (m *MocktemplateConfigurer) EXPECT() *MocktemplateConfigurerMockRecorder { } // Parameters mocks base method. -func (m *MocktemplateConfigurer) Parameters() ([]*cloudformation.Parameter, error) { +func (m *MocktemplateConfigurer) Parameters() ([]*types.Parameter, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Parameters") - ret0, _ := ret[0].([]*cloudformation.Parameter) + ret0, _ := ret[0].([]*types.Parameter) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -191,10 +191,10 @@ func (mr *MocktemplateConfigurerMockRecorder) Parameters() *gomock.Call { } // Tags mocks base method. -func (m *MocktemplateConfigurer) Tags() []*cloudformation.Tag { +func (m *MocktemplateConfigurer) Tags() []*types.Tag { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Tags") - ret0, _ := ret[0].([]*cloudformation.Tag) + ret0, _ := ret[0].([]*types.Tag) return ret0 } diff --git a/internal/pkg/deploy/cloudformation/stack/pipeline.go b/internal/pkg/deploy/cloudformation/stack/pipeline.go index 0c673481742..f3cd8be462d 100644 --- a/internal/pkg/deploy/cloudformation/stack/pipeline.go +++ b/internal/pkg/deploy/cloudformation/stack/pipeline.go @@ -5,7 +5,7 @@ package stack import ( "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/service/cloudformation" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/aproint/copilot-cli/internal/pkg/deploy" ) diff --git a/internal/pkg/deploy/cloudformation/stack/pipeline_test.go b/internal/pkg/deploy/cloudformation/stack/pipeline_test.go index 6746fdf6c1a..b9e9c288e2a 100644 --- a/internal/pkg/deploy/cloudformation/stack/pipeline_test.go +++ b/internal/pkg/deploy/cloudformation/stack/pipeline_test.go @@ -11,8 +11,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack/mocks" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" diff --git a/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go b/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go index 57a8b747fdd..01f6afce062 100644 --- a/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/rd_web_svc.go @@ -12,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) var awsSDKLayerForRegion = map[string]*string{ @@ -71,7 +71,7 @@ func NewRequestDrivenWebService(cfg RequestDrivenWebServiceConfig) (*RequestDriv return &RequestDrivenWebService{ appRunnerWkld: &appRunnerWkld{ wkld: &wkld{ - name: aws.StringValue(cfg.Manifest.Name), + name: aws.ToString(cfg.Manifest.Name), env: cfg.Env, app: cfg.App.Name, permBound: cfg.App.PermissionsBoundary, @@ -143,10 +143,10 @@ func (s *RequestDrivenWebService) Template() (string, error) { ServiceDiscoveryEndpoint: s.rc.ServiceDiscoveryEndpoint, Observability: template.ObservabilityOpts{ - Tracing: strings.ToUpper(aws.StringValue(s.manifest.Observability.Tracing)), + Tracing: strings.ToUpper(aws.ToString(s.manifest.Observability.Tracing)), }, PermissionsBoundary: s.permBound, - Private: aws.BoolValue(s.manifest.Private.Basic) || s.manifest.Private.Advanced.Endpoint != nil, + Private: aws.ToBool(s.manifest.Private.Basic) || s.manifest.Private.Advanced.Endpoint != nil, AppRunnerVPCEndpoint: s.manifest.Private.Advanced.Endpoint, Count: s.manifest.Count, Secrets: convertSecrets(s.manifest.RequestDrivenWebServiceConfig.Secrets), diff --git a/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go b/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go index b1965237221..a029e7b79f5 100644 --- a/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/rd_web_svc_integration_test.go @@ -16,8 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -49,7 +48,7 @@ func TestRDWS_Template(t *testing.T) { require.NoError(t, err, "apply test env to manifest") err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -67,7 +66,7 @@ func TestRDWS_Template(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/rd_web_svc_test.go b/internal/pkg/deploy/cloudformation/stack/rd_web_svc_test.go index e2ebd3c551d..6f20d128889 100644 --- a/internal/pkg/deploy/cloudformation/stack/rd_web_svc_test.go +++ b/internal/pkg/deploy/cloudformation/stack/rd_web_svc_test.go @@ -19,8 +19,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack/mocks" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -100,7 +100,7 @@ func TestRequestDrivenWebService_NewRequestDrivenWebService(t *testing.T) { wantedStack: &RequestDrivenWebService{ appRunnerWkld: &appRunnerWkld{ wkld: &wkld{ - name: aws.StringValue(testRDWebServiceManifest.Name), + name: aws.ToString(testRDWebServiceManifest.Name), env: testEnvName, app: testAppName, rc: RuntimeConfig{ @@ -516,7 +516,7 @@ func TestRequestDrivenWebService_Parameters(t *testing.T) { c := &RequestDrivenWebService{ appRunnerWkld: &appRunnerWkld{ wkld: &wkld{ - name: aws.StringValue(testRDWebServiceManifest.Name), + name: aws.ToString(testRDWebServiceManifest.Name), env: testEnvName, app: testAppName, image: tc.imageConfig.Image, @@ -541,13 +541,13 @@ func TestRequestDrivenWebService_SerializedParameters(t *testing.T) { c := &RequestDrivenWebService{ appRunnerWkld: &appRunnerWkld{ wkld: &wkld{ - name: aws.StringValue(testRDWebServiceManifest.Name), + name: aws.ToString(testRDWebServiceManifest.Name), env: testEnvName, app: testAppName, artifactKey: "arn:aws:kms:us-west-2:123456789012:key/1234abcd-12ab-34cd-56ef-1234567890ab", rc: RuntimeConfig{ PushedImages: map[string]ECRImage{ - aws.StringValue(testRDWebServiceManifest.Name): { + aws.ToString(testRDWebServiceManifest.Name): { RepoURL: testImageRepoURL, ImageTag: testImageTag, }, diff --git a/internal/pkg/deploy/cloudformation/stack/scheduled_job.go b/internal/pkg/deploy/cloudformation/stack/scheduled_job.go index 81ae0757e4e..076b0dbb884 100644 --- a/internal/pkg/deploy/cloudformation/stack/scheduled_job.go +++ b/internal/pkg/deploy/cloudformation/stack/scheduled_job.go @@ -17,8 +17,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/robfig/cron/v3" ) @@ -109,7 +109,7 @@ func NewScheduledJob(cfg ScheduledJobConfig) (*ScheduledJob, error) { return &ScheduledJob{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(cfg.Manifest.Name), + name: aws.ToString(cfg.Manifest.Name), env: cfg.Env, app: cfg.App.Name, permBound: cfg.App.PermissionsBoundary, @@ -193,7 +193,7 @@ func (j *ScheduledJob) Template() (string, error) { EntryPoint: entrypoint, Command: command, DependsOn: convertDependsOn(j.manifest.ImageConfig.Image.DependsOn), - CredentialsParameter: aws.StringValue(j.manifest.ImageConfig.Image.Credentials), + CredentialsParameter: aws.ToString(j.manifest.ImageConfig.Image.Credentials), ServiceDiscoveryEndpoint: j.rc.ServiceDiscoveryEndpoint, Publish: publishers, Platform: convertPlatform(j.manifest.Platform), @@ -246,13 +246,13 @@ func (j *ScheduledJob) SerializedParameters() (string, error) { // Exception is made for strings of the form "rate( )" or "cron( )". These are accepted as-is and // validated server-side by CloudFormation. func (j *ScheduledJob) awsSchedule() (string, error) { - schedule := aws.StringValue(j.manifest.On.Schedule) + schedule := aws.ToString(j.manifest.On.Schedule) if schedule == "" { return "", fmt.Errorf(`missing required field "schedule" in manifest for job %s`, j.name) } // If the schedule uses default CloudWatch Events syntax, pass it through for server-side validation. if match := awsScheduleRegexp.FindStringSubmatch(schedule); match != nil { - return aws.StringValue(j.manifest.On.Schedule), nil + return aws.ToString(j.manifest.On.Schedule), nil } // Try parsing the string as a cron expression to validate it. if _, err := cron.ParseStandard(schedule); err != nil { @@ -406,7 +406,7 @@ func toAWSCron(schedule string) (string, error) { // It also performs basic validations to provide a fast feedback loop to the customer. func (j *ScheduledJob) stateMachineOpts() (*template.StateMachineOpts, error) { var timeoutSeconds *int - if inTimeout := aws.StringValue(j.manifest.Timeout); inTimeout != "" { + if inTimeout := aws.ToString(j.manifest.Timeout); inTimeout != "" { parsedTimeout, err := time.ParseDuration(inTimeout) if err != nil { return nil, errDurationInvalid{reason: err} @@ -421,7 +421,7 @@ func (j *ScheduledJob) stateMachineOpts() (*template.StateMachineOpts, error) { } var retries *int - if inRetries := aws.IntValue(j.manifest.Retries); inRetries != 0 { + if inRetries := aws.ToInt(j.manifest.Retries); inRetries != 0 { if inRetries < 0 { return nil, errors.New("number of retries cannot be negative") } diff --git a/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go b/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go index 864b8ea621e..d2a958092b1 100644 --- a/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/scheduled_job_integration_test.go @@ -16,8 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -40,7 +39,7 @@ func TestScheduledJob_Template(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -58,7 +57,7 @@ func TestScheduledJob_Template(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/scheduled_job_test.go b/internal/pkg/deploy/cloudformation/stack/scheduled_job_test.go index 7ba6de2cbd1..ec13d1e81d0 100644 --- a/internal/pkg/deploy/cloudformation/stack/scheduled_job_test.go +++ b/internal/pkg/deploy/cloudformation/stack/scheduled_job_test.go @@ -14,8 +14,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -156,7 +156,7 @@ DiscoveryServiceArn: !GetAtt DiscoveryService.Arn`, addons := mockAddons{tplErr: errors.New("some error")} j.wkld.addons = addons }, - wantedError: fmt.Errorf("generate addons template for %s: %w", aws.StringValue(testScheduledJobManifest.Name), errors.New("some error")), + wantedError: fmt.Errorf("generate addons template for %s: %w", aws.ToString(testScheduledJobManifest.Name), errors.New("some error")), }, "template parsing error": { mockDependencies: func(t *testing.T, ctrl *gomock.Controller, j *ScheduledJob) { @@ -177,7 +177,7 @@ DiscoveryServiceArn: !GetAtt DiscoveryService.Arn`, conf := &ScheduledJob{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(testScheduledJobManifest.Name), + name: aws.ToString(testScheduledJobManifest.Name), env: testJobEnvName, app: testJobAppName, rc: RuntimeConfig{ @@ -436,8 +436,8 @@ func TestScheduledJob_stateMachine(t *testing.T) { require.True(t, errors.As(err, tc.wantedErrorType)) } else { require.NoError(t, err) - require.Equal(t, aws.IntValue(tc.wantedConfig.Retries), aws.IntValue(parsedStateMachine.Retries)) - require.Equal(t, aws.IntValue(tc.wantedConfig.Timeout), aws.IntValue(parsedStateMachine.Timeout)) + require.Equal(t, aws.ToInt(tc.wantedConfig.Retries), aws.ToInt(parsedStateMachine.Retries)) + require.Equal(t, aws.ToInt(tc.wantedConfig.Timeout), aws.ToInt(parsedStateMachine.Timeout)) } }) } @@ -525,7 +525,7 @@ func TestScheduledJob_Parameters(t *testing.T) { conf := &ScheduledJob{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(tc.manifest.Name), + name: aws.ToString(tc.manifest.Name), env: testEnvName, app: testAppName, rc: RuntimeConfig{ @@ -569,12 +569,12 @@ func TestScheduledJob_SerializedParameters(t *testing.T) { c := &ScheduledJob{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(testScheduledJobManifest.Name), + name: aws.ToString(testScheduledJobManifest.Name), env: testEnvName, app: testAppName, rc: RuntimeConfig{ PushedImages: map[string]ECRImage{ - aws.StringValue(testScheduledJobManifest.Name): { + aws.ToString(testScheduledJobManifest.Name): { RepoURL: testImageRepoURL, ImageTag: testImageTag, }, diff --git a/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go b/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go index 85e7a5671e5..4a8c10f8adf 100644 --- a/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/stack_local_integration_test.go @@ -16,7 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) @@ -59,7 +59,7 @@ func Test_Stack_Local_Integration(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) @@ -76,7 +76,7 @@ func Test_Stack_Local_Integration(t *testing.T) { ArtifactBucketName: "bucket", RuntimeConfig: stack.RuntimeConfig{ PushedImages: map[string]stack.ECRImage{ - aws.StringValue(v.Name): { + aws.ToString(v.Name): { RepoURL: imageURL, ImageTag: imageTag, }, diff --git a/internal/pkg/deploy/cloudformation/stack/static_site.go b/internal/pkg/deploy/cloudformation/stack/static_site.go index 5bc64f5ecc1..2a4c8e9217d 100644 --- a/internal/pkg/deploy/cloudformation/stack/static_site.go +++ b/internal/pkg/deploy/cloudformation/stack/static_site.go @@ -13,8 +13,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) // StaticSite represents the configuration needed to create a CloudFormation stack from a static site service manifest. @@ -62,8 +62,8 @@ func NewStaticSite(cfg *StaticSiteConfig) (*StaticSite, error) { } return &StaticSite{ wkld: &wkld{ - name: aws.StringValue(cfg.Manifest.Name), - env: aws.StringValue(cfg.EnvManifest.Name), + name: aws.ToString(cfg.Manifest.Name), + env: aws.ToString(cfg.EnvManifest.Name), app: cfg.App.Name, permBound: cfg.App.PermissionsBoundary, artifactBucketName: cfg.ArtifactBucketName, diff --git a/internal/pkg/deploy/cloudformation/stack/static_site_integration_test.go b/internal/pkg/deploy/cloudformation/stack/static_site_integration_test.go index d8348a13a4f..ac3cb2f87ca 100644 --- a/internal/pkg/deploy/cloudformation/stack/static_site_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/static_site_integration_test.go @@ -16,8 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -62,7 +61,7 @@ func TestStaticSiteService_TemplateAndParamsGeneration(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -80,7 +79,7 @@ func TestStaticSiteService_TemplateAndParamsGeneration(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/static_site_test.go b/internal/pkg/deploy/cloudformation/stack/static_site_test.go index b8ccd2d49c6..ebe869310d8 100644 --- a/internal/pkg/deploy/cloudformation/stack/static_site_test.go +++ b/internal/pkg/deploy/cloudformation/stack/static_site_test.go @@ -15,8 +15,8 @@ import ( "github.com/golang/mock/gomock" "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/stretchr/testify/require" ) @@ -64,7 +64,7 @@ func TestStaticSite_NewStaticSite(t *testing.T) { wantedStack: &StaticSite{ wkld: &wkld{ - name: aws.StringValue(testStaticSiteManifest.Name), + name: aws.ToString(testStaticSiteManifest.Name), env: testEnvName, app: testAppName, rc: RuntimeConfig{ diff --git a/internal/pkg/deploy/cloudformation/stack/tags.go b/internal/pkg/deploy/cloudformation/stack/tags.go index 953498bc974..08e8b954502 100644 --- a/internal/pkg/deploy/cloudformation/stack/tags.go +++ b/internal/pkg/deploy/cloudformation/stack/tags.go @@ -7,8 +7,8 @@ import ( "sort" "github.com/aproint/copilot-cli/internal/pkg/aws/tags" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) func mergeAndFlattenTags(additionalTags map[string]string, cliTags map[string]string) []*cloudformation.Tag { @@ -19,6 +19,6 @@ func mergeAndFlattenTags(additionalTags map[string]string, cliTags map[string]st Value: aws.String(v), }) } - sort.SliceStable(flatTags, func(i, j int) bool { return aws.StringValue(flatTags[i].Key) < aws.StringValue(flatTags[j].Key) }) + sort.SliceStable(flatTags, func(i, j int) bool { return aws.ToString(flatTags[i].Key) < aws.ToString(flatTags[j].Key) }) return flatTags } diff --git a/internal/pkg/deploy/cloudformation/stack/task.go b/internal/pkg/deploy/cloudformation/stack/task.go index d95361ad4a3..916f2bde624 100644 --- a/internal/pkg/deploy/cloudformation/stack/task.go +++ b/internal/pkg/deploy/cloudformation/stack/task.go @@ -11,8 +11,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) const ( diff --git a/internal/pkg/deploy/cloudformation/stack/task_test.go b/internal/pkg/deploy/cloudformation/stack/task_test.go index ce43448d54c..358224e1039 100644 --- a/internal/pkg/deploy/cloudformation/stack/task_test.go +++ b/internal/pkg/deploy/cloudformation/stack/task_test.go @@ -12,8 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/deploy/cloudformation/stack/transformers.go b/internal/pkg/deploy/cloudformation/stack/transformers.go index a259b684636..5cdd00c57cc 100644 --- a/internal/pkg/deploy/cloudformation/stack/transformers.go +++ b/internal/pkg/deploy/cloudformation/stack/transformers.go @@ -20,7 +20,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/s3" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" @@ -141,7 +141,7 @@ func convertContainerHealthCheck(hc manifest.ContainerHealthCheck) *template.Con return &template.ContainerHealthCheck{ Command: hc.Command, Interval: aws.Int64(int64(hc.Interval.Seconds())), - Retries: aws.Int64(int64(aws.IntValue(hc.Retries))), + Retries: aws.Int64(int64(aws.ToInt(hc.Retries))), StartPeriod: aws.Int64(int64(hc.StartPeriod.Seconds())), Timeout: aws.Int64(int64(hc.Timeout.Seconds())), } @@ -152,14 +152,14 @@ func convertHostedZone(alias manifest.Alias, defaultHostedZone *string) (templat if len(alias.AdvancedAliases) != 0 { for _, alias := range alias.AdvancedAliases { if alias.HostedZone != nil { - if isDuplicateAliasEntry(aliasesFor[*alias.HostedZone], aws.StringValue(alias.Alias)) { + if isDuplicateAliasEntry(aliasesFor[*alias.HostedZone], aws.ToString(alias.Alias)) { continue } aliasesFor[*alias.HostedZone] = append(aliasesFor[*alias.HostedZone], *alias.Alias) continue } if defaultHostedZone != nil { - if isDuplicateAliasEntry(aliasesFor[*defaultHostedZone], aws.StringValue(alias.Alias)) { + if isDuplicateAliasEntry(aliasesFor[*defaultHostedZone], aws.ToString(alias.Alias)) { continue } aliasesFor[*defaultHostedZone] = append(aliasesFor[*defaultHostedZone], *alias.Alias) @@ -239,8 +239,8 @@ func convertCapacityProviders(a manifest.AdvancedCount) []*template.CapacityProv return cps } // Scaling with spot - spotFrom := aws.IntValue(rc.SpotFrom) - min := aws.IntValue(rc.Min) + spotFrom := aws.ToInt(rc.SpotFrom) + min := aws.ToInt(rc.Min) // If spotFrom value is greater than or equal to the autoscaling min, // then the base value on the Fargate capacity provider must be set // to one less than spotFrom @@ -367,7 +367,7 @@ func convertHTTPHealthCheck(hc *manifest.HealthCheckArgsOrString) template.HTTPH GracePeriod: manifest.DefaultHealthCheckGracePeriod, HealthyThreshold: hc.Advanced.HealthyThreshold, UnhealthyThreshold: hc.Advanced.UnhealthyThreshold, - SuccessCodes: aws.StringValue(hc.Advanced.SuccessCodes), + SuccessCodes: aws.ToString(hc.Advanced.SuccessCodes), } if hc.IsZero() { @@ -382,7 +382,7 @@ func convertHTTPHealthCheck(hc *manifest.HealthCheckArgsOrString) template.HTTPH opts.HealthCheckPath = convertPath(*hc.Advanced.Path) } if hc.Advanced.Port != nil { - opts.Port = strconv.Itoa(aws.IntValue(hc.Advanced.Port)) + opts.Port = strconv.Itoa(aws.ToInt(hc.Advanced.Port)) } if hc.Advanced.Interval != nil { opts.Interval = aws.Int64(int64(hc.Advanced.Interval.Seconds())) @@ -404,7 +404,7 @@ func convertNLBHealthCheck(nlbHC *manifest.NLBHealthCheckArgs) template.NLBHealt GracePeriod: aws.Int64(int64(manifest.DefaultHealthCheckGracePeriod)), } if nlbHC.Port != nil { - hc.Port = strconv.Itoa(aws.IntValue(nlbHC.Port)) + hc.Port = strconv.Itoa(aws.ToInt(nlbHC.Port)) } if nlbHC.Timeout != nil { hc.Timeout = aws.Int64(int64(nlbHC.Timeout.Seconds())) @@ -437,8 +437,8 @@ func convertELBAccessLogsConfig(mft *manifest.Environment) *template.ELBAccessLo } return &template.ELBAccessLogs{ - BucketName: aws.StringValue(elbAccessLogsArgs.BucketName), - Prefix: aws.StringValue(elbAccessLogsArgs.Prefix), + BucketName: aws.ToString(elbAccessLogsArgs.BucketName), + Prefix: aws.ToString(elbAccessLogsArgs.Prefix), } } @@ -501,7 +501,7 @@ func (s *LoadBalancedWebService) convertALBListener() (*template.ALBListener, er for _, routingRule := range rrConfig.RoutingRules() { httpRedirect := true if routingRule.RedirectToHTTPS != nil { - httpRedirect = aws.BoolValue(routingRule.RedirectToHTTPS) + httpRedirect = aws.ToBool(routingRule.RedirectToHTTPS) } rule, err := routingRuleConfigConverter{ rule: routingRule, @@ -642,14 +642,14 @@ func (conv routingRuleConfigConverter) convert() (*template.ALBListenerRule, err } config := &template.ALBListenerRule{ - Path: convertPath(aws.StringValue(conv.rule.Path)), + Path: convertPath(aws.ToString(conv.rule.Path)), TargetContainer: targetContainer, TargetPort: targetPort, Aliases: aliases, HTTPHealthCheck: convertHTTPHealthCheck(&conv.rule.HealthCheck), AllowedSourceIps: convertAllowedSourceIPs(conv.rule.AllowedSourceIps), - Stickiness: strconv.FormatBool(aws.BoolValue(conv.rule.Stickiness)), - HTTPVersion: aws.StringValue(convertHTTPVersion(conv.rule.ProtocolVersion)), + Stickiness: strconv.FormatBool(aws.ToBool(conv.rule.Stickiness)), + HTTPVersion: aws.ToString(convertHTTPVersion(conv.rule.ProtocolVersion)), RedirectToHTTPS: conv.redirectToHTTPS, DeregistrationDelay: convertDeregistrationDelay(conv.rule.DeregistrationDelay), } @@ -703,8 +703,8 @@ func (s *LoadBalancedWebService) convertNetworkLoadBalancer() (networkLoadBalanc } listeners[idx] = template.NetworkLoadBalancerListener{ - Port: aws.StringValue(port), - Protocol: strings.ToUpper(aws.StringValue(protocol)), + Port: aws.ToString(port), + Protocol: strings.ToUpper(aws.ToString(protocol)), TargetContainer: targetContainer, TargetPort: targetPort, SSLPolicy: listener.SSLPolicy, @@ -775,7 +775,7 @@ func (s *LoadBalancedWebService) convertImportedALB() (*template.ImportedALB, er } func convertExecuteCommand(e *manifest.ExecuteCommand) *template.ExecuteCommandOpts { - if e.Config.IsEmpty() && !aws.BoolValue(e.Enable) { + if e.Config.IsEmpty() && !aws.ToBool(e.Enable) { return nil } return &template.ExecuteCommandOpts{} @@ -797,7 +797,7 @@ func convertServiceConnectServer(s manifest.ServiceConnectBoolOrArgs, target *ma return &template.ServiceConnectServer{ Name: target.Container, Port: target.Port, - Alias: aws.StringValue(s.Alias), + Alias: aws.ToString(s.Alias), } } @@ -847,7 +847,7 @@ func convertStorageOpts(wlName *string, in manifest.Storage) *template.StorageOp func convertEphemeral(in *int) *int { // Min value for extensible ephemeral storage is 21; if customer specifies 20, which is the default size, // we shouldn't let CF error out. Instead, we'll just omit it from the config. - if aws.IntValue(in) == 20 { + if aws.ToInt(in) == 20 { return nil } return in @@ -925,7 +925,7 @@ func convertEFSPermissions(input map[string]*manifest.Volume) []*template.EFSPer // Write defaults to false. write := defaultWritePermission if volume.ReadOnly != nil { - write = !aws.BoolValue(volume.ReadOnly) + write = !aws.ToBool(volume.ReadOnly) } accessPointID := volume.EFS.Advanced.AuthConfig.AccessPointID output = append(output, &template.EFSPermission{ @@ -972,7 +972,7 @@ func convertManagedFSInfo(wlName *string, input map[string]*manifest.Volume) *te // See https://stackoverflow.com/a/14210379/5890422 for discussion of the possibility of collisions in CRC32 with // small numbers of hashes. func getRandomUIDGID(name *string) uint32 { - return crc32.ChecksumIEEE([]byte(aws.StringValue(name))) + return crc32.ChecksumIEEE([]byte(aws.ToString(name))) } func convertVolumes(input map[string]*manifest.Volume) []*template.Volume { @@ -1022,7 +1022,7 @@ func convertVolumes(input map[string]*manifest.Volume) []*template.Volume { func convertEFSConfiguration(in manifest.EFSVolumeConfiguration) *template.EFSVolumeConfiguration { // Set default values correctly. rootDir := in.RootDirectory - if aws.StringValue(rootDir) == "" { + if aws.ToString(rootDir) == "" { rootDir = aws.String(defaultRootDirectory) } // Set default values for IAM and AccessPointID @@ -1035,7 +1035,7 @@ func convertEFSConfiguration(in manifest.EFSVolumeConfiguration) *template.EFSVo } } // AuthConfig exists; check the properties. - if aws.BoolValue(in.AuthConfig.IAM) { + if aws.ToBool(in.AuthConfig.IAM) { iam = aws.String(enabled) } @@ -1049,9 +1049,9 @@ func convertEFSConfiguration(in manifest.EFSVolumeConfiguration) *template.EFSVo func convertFileSystemID(in manifest.EFSVolumeConfiguration) template.FileSystemID { if in.FileSystemID.Plain != nil { - return template.PlainFileSystemID(aws.StringValue(in.FileSystemID.Plain)) + return template.PlainFileSystemID(aws.ToString(in.FileSystemID.Plain)) } - return template.ImportedFileSystemID(aws.StringValue(in.FileSystemID.FromCFN.Name)) + return template.ImportedFileSystemID(aws.ToString(in.FileSystemID.FromCFN.Name)) } func convertNetworkConfig(network manifest.NetworkConfig) template.NetworkOpts { @@ -1069,9 +1069,9 @@ func convertNetworkConfig(network manifest.NetworkConfig) template.NetworkOpts { outSGs := make([]template.SecurityGroup, len(inSGs)) for i, sg := range inSGs { if sg.Plain != nil { - outSGs[i] = template.PlainSecurityGroup(aws.StringValue(sg.Plain)) + outSGs[i] = template.PlainSecurityGroup(aws.ToString(sg.Plain)) } else { - outSGs[i] = template.ImportedSecurityGroup(aws.StringValue(sg.FromCFN.Name)) + outSGs[i] = template.ImportedSecurityGroup(aws.ToString(sg.FromCFN.Name)) } } opts.SecurityGroups = outSGs @@ -1132,7 +1132,7 @@ func convertDeploymentControllerConfig(in manifest.DeploymentControllerConfig) t MinHealthyPercent: minHealthyPercentDefault, MaxPercent: maxPercentDefault, } - if strings.EqualFold(aws.StringValue(in.Rolling), manifest.ECSRecreateRollingUpdateStrategy) { + if strings.EqualFold(aws.ToString(in.Rolling), manifest.ECSRecreateRollingUpdateStrategy) { out.MinHealthyPercent = minHealthyPercentRecreate out.MaxPercent = maxPercentRecreate } @@ -1225,7 +1225,7 @@ func convertTopicSubscription(t manifest.TopicSubscription) ( if err != nil { return nil, err } - if aws.BoolValue(t.Queue.Enabled) { + if aws.ToBool(t.Queue.Enabled) { return &template.TopicSubscription{ Name: t.Name, Service: t.Service, @@ -1268,7 +1268,7 @@ func convertQueue(in manifest.SQSQueue) *template.SQSQueue { return queue } - if aws.BoolValue(in.FIFO.Enable) { + if aws.ToBool(in.FIFO.Enable) { queue.FIFOQueueConfig = &template.FIFOQueueConfig{} return queue } @@ -1279,7 +1279,7 @@ func convertQueue(in manifest.SQSQueue) *template.SQSQueue { DeduplicationScope: in.FIFO.Advanced.DeduplicationScope, FIFOThroughputLimit: in.FIFO.Advanced.FIFOThroughputLimit, } - if aws.BoolValue(in.FIFO.Advanced.HighThroughputFifo) { + if aws.ToBool(in.FIFO.Advanced.HighThroughputFifo) { queue.FIFOQueueConfig.FIFOThroughputLimit = aws.String(sqsFIFOThroughputLimitPerMessageGroupId) queue.FIFOQueueConfig.DeduplicationScope = aws.String(sqsDedupeScopeMessageGroup) } diff --git a/internal/pkg/deploy/cloudformation/stack/transformers_test.go b/internal/pkg/deploy/cloudformation/stack/transformers_test.go index 1b16c3f4ec0..95b4e1eda3d 100644 --- a/internal/pkg/deploy/cloudformation/stack/transformers_test.go +++ b/internal/pkg/deploy/cloudformation/stack/transformers_test.go @@ -16,7 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go b/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go index 30445f375ac..c35b636cd6d 100644 --- a/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/validate_template_integration_test.go @@ -6,6 +6,7 @@ package stack_test import ( + "context" "fmt" "os" "path/filepath" @@ -17,8 +18,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" "github.com/spf13/afero" "github.com/stretchr/testify/require" ) @@ -43,7 +44,7 @@ func TestAutoscalingIntegration_Validate(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) @@ -57,7 +58,7 @@ func TestAutoscalingIntegration_Validate(t *testing.T) { Manifest: v, RuntimeConfig: stack.RuntimeConfig{ PushedImages: map[string]stack.ECRImage{ - aws.StringValue(v.Name): { + aws.ToString(v.Name): { RepoURL: imageURL, ImageTag: imageTag, }, @@ -75,12 +76,12 @@ func TestAutoscalingIntegration_Validate(t *testing.T) { require.NoError(t, err) tpl, err := serializer.Template() require.NoError(t, err) - sess, err := sessions.ImmutableProvider().Default() + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - cfn := cloudformation.New(sess) + cfn := cloudformation.NewFromConfig(cfg) t.Run("CloudFormation template must be valid", func(t *testing.T) { - _, err := cfn.ValidateTemplate(&cloudformation.ValidateTemplateInput{ + _, err := cfn.ValidateTemplate(context.Background(), &cloudformation.ValidateTemplateInput{ TemplateBody: aws.String(tpl), }) require.NoError(t, err) @@ -107,7 +108,7 @@ func TestScheduledJob_Validate(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) @@ -132,12 +133,12 @@ func TestScheduledJob_Validate(t *testing.T) { tpl, err := serializer.Template() require.NoError(t, err, "template should render") - sess, err := sessions.ImmutableProvider().Default() + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - cfn := cloudformation.New(sess) + cfn := cloudformation.NewFromConfig(cfg) t.Run("CF template should be valid", func(t *testing.T) { - _, err := cfn.ValidateTemplate(&cloudformation.ValidateTemplateInput{ + _, err := cfn.ValidateTemplate(context.Background(), &cloudformation.ValidateTemplateInput{ TemplateBody: aws.String(tpl), }) require.NoError(t, err) diff --git a/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go index 444400ded2a..ec9dfe50a84 100644 --- a/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/windows_lb_web_service_integration_test.go @@ -17,8 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -40,7 +39,7 @@ func TestWindowsLoadBalancedWebService_Template(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -58,7 +57,7 @@ func TestWindowsLoadBalancedWebService_Template(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go b/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go index 4889dbd20d1..f4adf13bfc4 100644 --- a/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go +++ b/internal/pkg/deploy/cloudformation/stack/worker_service_integration_test.go @@ -17,8 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/spf13/afero" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" @@ -40,7 +39,7 @@ func TestWorkerService_Template(t *testing.T) { require.NoError(t, err) err = envMft.Validate() require.NoError(t, err) - err = envMft.Load(session.New()) + err = envMft.Load(aws.Config{}) require.NoError(t, err) content := envMft.Manifest() @@ -58,7 +57,7 @@ func TestWorkerService_Template(t *testing.T) { ws, err := workspace.Use(fs) require.NoError(t, err) - _, err = addon.ParseFromWorkload(aws.StringValue(v.Name), ws) + _, err = addon.ParseFromWorkload(aws.ToString(v.Name), ws) var notFound *addon.ErrAddonsNotFound require.ErrorAs(t, err, ¬Found) diff --git a/internal/pkg/deploy/cloudformation/stack/worker_svc.go b/internal/pkg/deploy/cloudformation/stack/worker_svc.go index 5e4bf1927f7..549e025fde0 100644 --- a/internal/pkg/deploy/cloudformation/stack/worker_svc.go +++ b/internal/pkg/deploy/cloudformation/stack/worker_svc.go @@ -14,8 +14,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) // WorkerService represents the configuration needed to create a CloudFormation stack from a worker service manifest. @@ -49,7 +49,7 @@ func NewWorkerService(cfg WorkerServiceConfig) (*WorkerService, error) { return &WorkerService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(cfg.Manifest.Name), + name: aws.ToString(cfg.Manifest.Name), env: cfg.Env, app: cfg.App.Name, permBound: cfg.App.PermissionsBoundary, @@ -156,13 +156,13 @@ func (s *WorkerService) Template() (string, error) { ServiceConnectOpts: scOpts, Command: command, DependsOn: convertDependsOn(s.manifest.ImageConfig.Image.DependsOn), - CredentialsParameter: aws.StringValue(s.manifest.ImageConfig.Image.Credentials), + CredentialsParameter: aws.ToString(s.manifest.ImageConfig.Image.Credentials), ServiceDiscoveryEndpoint: s.rc.ServiceDiscoveryEndpoint, Subscribe: subscribe, Publish: publishers, Platform: convertPlatform(s.manifest.Platform), Observability: template.ObservabilityOpts{ - Tracing: strings.ToUpper(aws.StringValue(s.manifest.Observability.Tracing)), + Tracing: strings.ToUpper(aws.ToString(s.manifest.Observability.Tracing)), }, PermissionsBoundary: s.permBound, }) diff --git a/internal/pkg/deploy/cloudformation/stack/worker_svc_test.go b/internal/pkg/deploy/cloudformation/stack/worker_svc_test.go index 7421b0139ab..3901280ded5 100644 --- a/internal/pkg/deploy/cloudformation/stack/worker_svc_test.go +++ b/internal/pkg/deploy/cloudformation/stack/worker_svc_test.go @@ -15,8 +15,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack/mocks" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -266,7 +266,7 @@ func TestWorkerService_Parameters(t *testing.T) { conf := &WorkerService{ ecsWkld: &ecsWkld{ wkld: &wkld{ - name: aws.StringValue(testWorkerSvcManifest.Name), + name: aws.ToString(testWorkerSvcManifest.Name), env: testEnvName, app: testAppName, image: manifest.Image{ diff --git a/internal/pkg/deploy/cloudformation/stack/workload.go b/internal/pkg/deploy/cloudformation/stack/workload.go index efdbac2a15f..60f1ff838ce 100644 --- a/internal/pkg/deploy/cloudformation/stack/workload.go +++ b/internal/pkg/deploy/cloudformation/stack/workload.go @@ -16,8 +16,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/override" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + cloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" ) // Parameter logical IDs common across workloads. @@ -235,10 +235,10 @@ func serializeTemplateConfig(parser template.Parser, stack templateConfigurer) ( } for _, param := range params { - config.Parameters[aws.StringValue(param.ParameterKey)] = param.ParameterValue + config.Parameters[aws.ToString(param.ParameterKey)] = param.ParameterValue } for _, tag := range tags { - config.Tags[aws.StringValue(tag.Key)] = tag.Value + config.Tags[aws.ToString(tag.Key)] = tag.Value } str, err := json.MarshalIndent(config, "", " ") @@ -350,16 +350,16 @@ func (w *ecsWkld) Parameters() ([]*cloudformation.Parameter, error) { } logRetention := ecsWkldLogRetentionDefault if w.logging.Retention != nil { - logRetention = aws.IntValue(w.logging.Retention) + logRetention = aws.ToInt(w.logging.Retention) } return append(envFileParameters, []*cloudformation.Parameter{ { ParameterKey: aws.String(WorkloadTaskCPUParamKey), - ParameterValue: aws.String(strconv.Itoa(aws.IntValue(w.tc.CPU))), + ParameterValue: aws.String(strconv.Itoa(aws.ToInt(w.tc.CPU))), }, { ParameterKey: aws.String(WorkloadTaskMemoryParamKey), - ParameterValue: aws.String(strconv.Itoa(aws.IntValue(w.tc.Memory))), + ParameterValue: aws.String(strconv.Itoa(aws.ToInt(w.tc.Memory))), }, { ParameterKey: aws.String(WorkloadTaskCountParamKey), @@ -450,15 +450,15 @@ func (w *appRunnerWkld) Parameters() ([]*cloudformation.Parameter, error) { }, { ParameterKey: aws.String(WorkloadContainerPortParamKey), - ParameterValue: aws.String(strconv.Itoa(int(aws.Uint16Value(w.imageConfig.Port)))), + ParameterValue: aws.String(strconv.Itoa(int(aws.ToUint16(w.imageConfig.Port)))), }, { ParameterKey: aws.String(RDWkldInstanceCPUParamKey), - ParameterValue: aws.String(strconv.Itoa(aws.IntValue(w.instanceConfig.CPU))), + ParameterValue: aws.String(strconv.Itoa(aws.ToInt(w.instanceConfig.CPU))), }, { ParameterKey: aws.String(RDWkldInstanceMemoryParamKey), - ParameterValue: aws.String(strconv.Itoa(aws.IntValue(w.instanceConfig.Memory))), + ParameterValue: aws.String(strconv.Itoa(aws.ToInt(w.instanceConfig.Memory))), }, } diff --git a/internal/pkg/deploy/cloudformation/task.go b/internal/pkg/deploy/cloudformation/task.go index 9c57e982d41..815b8b39f62 100644 --- a/internal/pkg/deploy/cloudformation/task.go +++ b/internal/pkg/deploy/cloudformation/task.go @@ -10,7 +10,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) // DeployTask deploys a task stack, renders the deployment to out until it is done. @@ -52,11 +52,11 @@ func (cf CloudFormation) ListTaskStacks(appName, envName string) ([]deploy.TaskS for _, task := range tasks { outputTaskStacks = append(outputTaskStacks, deploy.TaskStackInfo{ - StackName: aws.StringValue(task.StackName), + StackName: aws.ToString(task.StackName), App: appName, Env: envName, - RoleARN: aws.StringValue(task.RoleARN), + RoleARN: aws.ToString(task.RoleARN), }) } return outputTaskStacks, nil @@ -72,23 +72,23 @@ func (cf CloudFormation) GetTaskStack(taskName string) (*deploy.TaskStackInfo, e } info := deploy.TaskStackInfo{ StackName: stackName, - RoleARN: aws.StringValue(desc.RoleARN), + RoleARN: aws.ToString(desc.RoleARN), } var isTask bool for _, tag := range desc.Tags { - switch aws.StringValue(tag.Key) { + switch aws.ToString(tag.Key) { case deploy.AppTagKey: - info.App = aws.StringValue(tag.Value) + info.App = aws.ToString(tag.Value) case deploy.EnvTagKey: - info.Env = aws.StringValue(tag.Value) + info.Env = aws.ToString(tag.Value) case deploy.TaskTagKey: isTask = true } } for _, out := range desc.Outputs { - switch aws.StringValue(out.OutputKey) { + switch aws.ToString(out.OutputKey) { case stack.TaskOutputS3Bucket: - info.BucketName = aws.StringValue(out.OutputValue) + info.BucketName = aws.ToString(out.OutputValue) } } if !isTask { @@ -108,10 +108,10 @@ func (cf CloudFormation) ListDefaultTaskStacks() ([]deploy.TaskStackInfo, error) // Eliminate tasks which are tagged for a particular copilot app or env. var hasAppTag, hasEnvTag bool for _, tag := range task.Tags { - if aws.StringValue(tag.Key) == deploy.AppTagKey { + if aws.ToString(tag.Key) == deploy.AppTagKey { hasAppTag = true } - if aws.StringValue(tag.Key) == deploy.EnvTagKey { + if aws.ToString(tag.Key) == deploy.EnvTagKey { hasEnvTag = true } } @@ -119,7 +119,7 @@ func (cf CloudFormation) ListDefaultTaskStacks() ([]deploy.TaskStackInfo, error) continue } outputTaskStacks = append(outputTaskStacks, deploy.TaskStackInfo{ - StackName: aws.StringValue(task.StackName), + StackName: aws.ToString(task.StackName), }) } return outputTaskStacks, nil diff --git a/internal/pkg/deploy/cloudformation/task_test.go b/internal/pkg/deploy/cloudformation/task_test.go index 4e25e148eda..11d8cf885d9 100644 --- a/internal/pkg/deploy/cloudformation/task_test.go +++ b/internal/pkg/deploy/cloudformation/task_test.go @@ -8,8 +8,8 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/deploy" - "github.com/aws/aws-sdk-go/aws" - awscfn "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + awscfn "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/stretchr/testify/require" @@ -53,7 +53,7 @@ func TestCloudFormation_DeployTask(t *testing.T) { } var mockDescription1 = &cloudformation.StackDescription{ - Tags: []*awscfn.Tag{ + Tags: []awscfn.Tag{ { Key: aws.String("copilot-task"), }, @@ -70,7 +70,7 @@ var mockDescription1 = &cloudformation.StackDescription{ RoleARN: aws.String("arn:aws:iam::123456789012:role/appname-test-CFNExecutionRole"), } var mockDescription2 = &cloudformation.StackDescription{ - Tags: []*awscfn.Tag{ + Tags: []awscfn.Tag{ { Key: aws.String("copilot-task"), }, @@ -88,7 +88,7 @@ var mockDescription2 = &cloudformation.StackDescription{ } var mockDescription3 = &cloudformation.StackDescription{ - Tags: []*awscfn.Tag{ + Tags: []awscfn.Tag{ { Key: aws.String("copilot-task"), }, @@ -120,7 +120,7 @@ func TestCloudFormation_ListTaskStacks(t *testing.T) { StackName: "task-database", App: "appname", Env: "test", - RoleARN: aws.StringValue(mockDescription1.RoleARN), + RoleARN: aws.ToString(mockDescription1.RoleARN), }, }, }, diff --git a/internal/pkg/deploy/cloudformation/workload_test.go b/internal/pkg/deploy/cloudformation/workload_test.go index 659d5fa8dea..1b2da1ba0dc 100644 --- a/internal/pkg/deploy/cloudformation/workload_test.go +++ b/internal/pkg/deploy/cloudformation/workload_test.go @@ -11,8 +11,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/mocks" - "github.com/aws/aws-sdk-go/aws" - sdkcloudformation "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + sdkcloudformation "github.com/aws/aws-sdk-go-v2/service/cloudformation" + sdkcloudformationtypes "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -32,10 +33,10 @@ func (m *mockStackConfig) Template() (string, error) { return m.template, nil } -func (m *mockStackConfig) Parameters() ([]*sdkcloudformation.Parameter, error) { - var params []*sdkcloudformation.Parameter +func (m *mockStackConfig) Parameters() ([]*sdkcloudformationtypes.Parameter, error) { + var params []*sdkcloudformationtypes.Parameter for k, v := range m.parameters { - params = append(params, &sdkcloudformation.Parameter{ + params = append(params, &sdkcloudformationtypes.Parameter{ ParameterKey: aws.String(k), ParameterValue: aws.String(v), }) @@ -47,10 +48,10 @@ func (m *mockStackConfig) SerializedParameters() (string, error) { return "", nil } -func (m *mockStackConfig) Tags() []*sdkcloudformation.Tag { - var tags []*sdkcloudformation.Tag +func (m *mockStackConfig) Tags() []*sdkcloudformationtypes.Tag { + var tags []*sdkcloudformationtypes.Tag for k, v := range m.tags { - tags = append(tags, &sdkcloudformation.Tag{ + tags = append(tags, &sdkcloudformationtypes.Tag{ Key: aws.String(k), Value: aws.String(v), }) diff --git a/internal/pkg/deploy/deploy.go b/internal/pkg/deploy/deploy.go index a688fffce46..ae258fb9c33 100644 --- a/internal/pkg/deploy/deploy.go +++ b/internal/pkg/deploy/deploy.go @@ -11,7 +11,7 @@ import ( "sort" awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" diff --git a/internal/pkg/deploy/deploy_test.go b/internal/pkg/deploy/deploy_test.go index e2afeaac1d2..2120e6b97bb 100644 --- a/internal/pkg/deploy/deploy_test.go +++ b/internal/pkg/deploy/deploy_test.go @@ -9,7 +9,7 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" rg "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/config" diff --git a/internal/pkg/deploy/pipeline.go b/internal/pkg/deploy/pipeline.go index dd1c3ae67b8..9c000380cec 100644 --- a/internal/pkg/deploy/pipeline.go +++ b/internal/pkg/deploy/pipeline.go @@ -19,7 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/graph" "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" ) const ( diff --git a/internal/pkg/deploy/pipeline_test.go b/internal/pkg/deploy/pipeline_test.go index 6b9c00ccab4..aeea6e23bad 100644 --- a/internal/pkg/deploy/pipeline_test.go +++ b/internal/pkg/deploy/pipeline_test.go @@ -13,7 +13,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/deploy/sns.go b/internal/pkg/deploy/sns.go index 375c3f9fa93..82dbdf5cb34 100644 --- a/internal/pkg/deploy/sns.go +++ b/internal/pkg/deploy/sns.go @@ -10,7 +10,7 @@ import ( "fmt" "strings" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" ) var ( diff --git a/internal/pkg/describe/app.go b/internal/pkg/describe/app.go index 315c8640744..1f9f3841713 100644 --- a/internal/pkg/describe/app.go +++ b/internal/pkg/describe/app.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "strings" @@ -108,14 +109,14 @@ type AppDescriber struct { // NewAppDescriber instantiates an application describer. func NewAppDescriber(appName string) (*AppDescriber, error) { - sess, err := sessions.ImmutableProvider().Default() + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) if err != nil { return nil, fmt.Errorf("assume default role for app %s: %w", appName, err) } return &AppDescriber{ app: appName, - stackDescriber: stack.NewStackDescriber(cfnstack.NameForAppStack(appName), sess), - stackSetDescriber: stack.NewStackDescriber(cfnstack.NameForAppStackSet(appName), sess), + stackDescriber: stack.NewStackDescriber(cfnstack.NameForAppStack(appName), cfg), + stackSetDescriber: stack.NewStackDescriber(cfnstack.NameForAppStackSet(appName), cfg), }, nil } diff --git a/internal/pkg/describe/aws_config.go b/internal/pkg/describe/aws_config.go deleted file mode 100644 index e3f550f775b..00000000000 --- a/internal/pkg/describe/aws_config.go +++ /dev/null @@ -1,15 +0,0 @@ -package describe - -import ( - "context" - - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go-v2/aws" - awsv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" -) - -func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), awsv1.StringValue(sess.Config.Region)) - return cfg -} diff --git a/internal/pkg/describe/backend_service.go b/internal/pkg/describe/backend_service.go index d12f1b31874..65fad477f94 100644 --- a/internal/pkg/describe/backend_service.go +++ b/internal/pkg/describe/backend_service.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "strings" @@ -60,11 +61,11 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, err } - return elbv2.New(v2ConfigFromSessionRegion(sess)), nil + return elbv2.New(cfg), nil } describer.initECSServiceDescribers = func(env string) (ecsDescriber, error) { if describer, ok := describer.ecsServiceDescribers[env]; ok { @@ -90,11 +91,10 @@ func NewBackendServiceDescriber(opt NewServiceConfig) (*BackendServiceDescriber, if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, err } - cfg := v2ConfigFromSessionRegion(sess) return cloudwatch.New(cfg, cfg), nil } describer.initEnvDescribers = func(env string) (envDescriber, error) { diff --git a/internal/pkg/describe/env.go b/internal/pkg/describe/env.go index d68edf86453..31c0071978f 100644 --- a/internal/pkg/describe/env.go +++ b/internal/pkg/describe/env.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "sort" @@ -73,7 +74,7 @@ func NewEnvDescriber(opt NewEnvDescriberConfig) (*EnvDescriber, error) { if err != nil { return nil, fmt.Errorf("get environment: %w", err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, fmt.Errorf("assume role for environment %s: %w", env.ManagerRoleARN, err) } @@ -84,7 +85,7 @@ func NewEnvDescriber(opt NewEnvDescriberConfig) (*EnvDescriber, error) { configStore: opt.ConfigStore, deployStore: opt.DeployStore, - cfn: stack.NewStackDescriber(cfnstack.NameForEnv(opt.App, opt.Env), sess), + cfn: stack.NewStackDescriber(cfnstack.NameForEnv(opt.App, opt.Env), cfg), }, nil } diff --git a/internal/pkg/describe/lb_web_service.go b/internal/pkg/describe/lb_web_service.go index 37217c95dba..64047d95ed3 100644 --- a/internal/pkg/describe/lb_web_service.go +++ b/internal/pkg/describe/lb_web_service.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -12,6 +13,8 @@ import ( "strings" "text/tabwriter" + "github.com/aws/smithy-go" + "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" @@ -22,7 +25,6 @@ import ( cfnstack "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" "github.com/aproint/copilot-cli/internal/pkg/term/color" - "github.com/aws/aws-sdk-go/aws/awserr" ) const ( @@ -83,11 +85,11 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, err } - return elbv2.New(v2ConfigFromSessionRegion(sess)), nil + return elbv2.New(cfg), nil } describer.initECSServiceDescribers = func(env string) (ecsDescriber, error) { if describer, ok := describer.ecsServiceDescribers[env]; ok { @@ -128,11 +130,10 @@ func NewLBWebServiceDescriber(opt NewServiceConfig) (*LBWebServiceDescriber, err if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, err } - cfg := v2ConfigFromSessionRegion(sess) return cloudwatch.New(cfg, cfg), nil } return describer, nil @@ -350,14 +351,15 @@ func IsStackNotExistsErr(err error) bool { if err == nil { return false } - aerr, ok := err.(awserr.Error) + var aerr smithy.APIError + ok := errors.As(err, &aerr) if !ok { return IsStackNotExistsErr(errors.Unwrap(err)) } - if aerr.Code() != "ValidationError" { + if aerr.ErrorCode() != "ValidationError" { return IsStackNotExistsErr(errors.Unwrap(err)) } - if !strings.Contains(aerr.Message(), "does not exist") { + if !strings.Contains(aerr.ErrorMessage(), "does not exist") { return IsStackNotExistsErr(errors.Unwrap(err)) } return true diff --git a/internal/pkg/describe/pipeline.go b/internal/pkg/describe/pipeline.go index e7543431b11..38710a65234 100644 --- a/internal/pkg/describe/pipeline.go +++ b/internal/pkg/describe/pipeline.go @@ -4,6 +4,8 @@ package describe import ( + "context" + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" describestack "github.com/aproint/copilot-cli/internal/pkg/describe/stack" @@ -17,12 +19,12 @@ type PipelineStackDescriber struct { // NewPipelineStackDescriber instantiates a new pipeline stack describer func NewPipelineStackDescriber(appName, name string, isLegacy bool) (*PipelineStackDescriber, error) { - sess, err := sessions.ImmutableProvider().Default() + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) if err != nil { return nil, err } return &PipelineStackDescriber{ - cfn: describestack.NewStackDescriber(stack.NameForPipeline(appName, name, isLegacy), sess), + cfn: describestack.NewStackDescriber(stack.NameForPipeline(appName, name, isLegacy), cfg), }, nil } diff --git a/internal/pkg/describe/pipeline_show.go b/internal/pkg/describe/pipeline_show.go index 325cf4f1da7..8d0c2747848 100644 --- a/internal/pkg/describe/pipeline_show.go +++ b/internal/pkg/describe/pipeline_show.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "strings" @@ -44,12 +45,11 @@ type PipelineDescriber struct { // NewPipelineDescriber instantiates a new pipeline describer func NewPipelineDescriber(pipeline deploy.Pipeline, showResources bool) (*PipelineDescriber, error) { - sess, err := sessions.ImmutableProvider().Default() + v2Config, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) if err != nil { return nil, err } - v2Config := v2ConfigFromSessionRegion(sess) pipelineSvc := codepipeline.New(v2Config, v2Config) return &PipelineDescriber{ @@ -57,7 +57,7 @@ func NewPipelineDescriber(pipeline deploy.Pipeline, showResources bool) (*Pipeli pipelineSvc: pipelineSvc, showResources: showResources, - cfn: describestack.NewStackDescriber(stack.NameForPipeline(pipeline.AppName, pipeline.Name, pipeline.IsLegacy), sess), + cfn: describestack.NewStackDescriber(stack.NameForPipeline(pipeline.AppName, pipeline.Name, pipeline.IsLegacy), v2Config), }, nil } diff --git a/internal/pkg/describe/pipeline_status.go b/internal/pkg/describe/pipeline_status.go index 4eb4972638f..b23f1600fe3 100644 --- a/internal/pkg/describe/pipeline_status.go +++ b/internal/pkg/describe/pipeline_status.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "strings" @@ -34,12 +35,11 @@ type PipelineStatus struct { // NewPipelineStatusDescriber instantiates a new PipelineStatus struct. func NewPipelineStatusDescriber(pipeline deploy.Pipeline) (*PipelineStatusDescriber, error) { - sess, err := sessions.ImmutableProvider().Default() + v2Config, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) if err != nil { return nil, err } - v2Config := v2ConfigFromSessionRegion(sess) pipelineSvc := codepipeline.New(v2Config, v2Config) return &PipelineStatusDescriber{ pipeline: pipeline, diff --git a/internal/pkg/describe/service.go b/internal/pkg/describe/service.go index 2733d4b8e8f..f255b4a9116 100644 --- a/internal/pkg/describe/service.go +++ b/internal/pkg/describe/service.go @@ -18,7 +18,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" "github.com/aproint/copilot-cli/internal/pkg/ecs" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" ) const ( @@ -151,7 +151,7 @@ func newECSServiceDescriber(opt NewServiceConfig) (*ecsServiceDescriber, error) } return &ecsServiceDescriber{ WorkloadStackDescriber: stackDescriber, - ecsClient: ecs.New(stackDescriber.sess, v2ConfigFromSessionRegion(stackDescriber.sess)), + ecsClient: ecs.New(stackDescriber.cfg), }, nil } @@ -168,7 +168,7 @@ func newAppRunnerServiceDescriber(opt NewServiceConfig) (*appRunnerServiceDescri return &appRunnerServiceDescriber{ WorkloadStackDescriber: stackDescriber, - apprunnerClient: apprunner.New(v2ConfigFromSessionRegion(stackDescriber.sess)), + apprunnerClient: apprunner.New(stackDescriber.cfg), }, nil } diff --git a/internal/pkg/describe/service_test.go b/internal/pkg/describe/service_test.go index bc112e88f95..fe91fd463a1 100644 --- a/internal/pkg/describe/service_test.go +++ b/internal/pkg/describe/service_test.go @@ -15,7 +15,7 @@ import ( awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/describe/mocks" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/describe/stack/stack.go b/internal/pkg/describe/stack/stack.go index b20591fa0d4..55ec77f5c11 100644 --- a/internal/pkg/describe/stack/stack.go +++ b/internal/pkg/describe/stack/stack.go @@ -7,8 +7,7 @@ import ( "fmt" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) type cfn interface { @@ -43,10 +42,10 @@ type StackDescriber struct { } // NewStackDescriber instantiates a new StackDescriber. -func NewStackDescriber(stackName string, sess *session.Session) *StackDescriber { +func NewStackDescriber(stackName string, cfg aws.Config) *StackDescriber { return &StackDescriber{ name: stackName, - cfn: cloudformation.New(sess), + cfn: cloudformation.New(cfg), } } @@ -58,15 +57,15 @@ func (d *StackDescriber) Describe() (StackDescription, error) { } params := make(map[string]string) for _, param := range descr.Parameters { - params[aws.StringValue(param.ParameterKey)] = aws.StringValue(param.ParameterValue) + params[aws.ToString(param.ParameterKey)] = aws.ToString(param.ParameterValue) } outputs := make(map[string]string) for _, out := range descr.Outputs { - outputs[aws.StringValue(out.OutputKey)] = aws.StringValue(out.OutputValue) + outputs[aws.ToString(out.OutputKey)] = aws.ToString(out.OutputValue) } tags := make(map[string]string) for _, tag := range descr.Tags { - tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value) + tags[aws.ToString(tag.Key)] = aws.ToString(tag.Value) } return StackDescription{ Parameters: params, @@ -106,9 +105,9 @@ func flattenResources(stackResources []*cloudformation.StackResource) []*Resourc var resources []*Resource for _, stackResource := range stackResources { resources = append(resources, &Resource{ - Type: aws.StringValue(stackResource.ResourceType), - PhysicalID: aws.StringValue(stackResource.PhysicalResourceId), - LogicalID: aws.StringValue(stackResource.LogicalResourceId), + Type: aws.ToString(stackResource.ResourceType), + PhysicalID: aws.ToString(stackResource.PhysicalResourceId), + LogicalID: aws.ToString(stackResource.LogicalResourceId), }) } return resources diff --git a/internal/pkg/describe/stack/stack_test.go b/internal/pkg/describe/stack/stack_test.go index f5e04e62672..d01d917bcbc 100644 --- a/internal/pkg/describe/stack/stack_test.go +++ b/internal/pkg/describe/stack/stack_test.go @@ -10,8 +10,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/describe/stack/mocks" - "github.com/aws/aws-sdk-go/aws" - sdkcfn "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + sdkcfn "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -41,19 +41,19 @@ func TestStackDescriber_Describe(t *testing.T) { setupMocks: func(m stackDescriberMocks) { gomock.InOrder( m.cfn.EXPECT().Describe(mockStackName).Return(&cloudformation.StackDescription{ - Parameters: []*sdkcfn.Parameter{ + Parameters: []sdkcfn.Parameter{ { ParameterKey: aws.String("mockParamKey"), ParameterValue: aws.String("mockParamVal"), }, }, - Outputs: []*sdkcfn.Output{ + Outputs: []sdkcfn.Output{ { OutputKey: aws.String("mockOutputKey"), OutputValue: aws.String("mockOutputVal"), }, }, - Tags: []*sdkcfn.Tag{ + Tags: []sdkcfn.Tag{ { Key: aws.String("mockTagKey"), Value: aws.String("mockTagVal"), diff --git a/internal/pkg/describe/static_site.go b/internal/pkg/describe/static_site.go index 76602a62def..da34118fd70 100644 --- a/internal/pkg/describe/static_site.go +++ b/internal/pkg/describe/static_site.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "strings" @@ -67,12 +68,11 @@ func NewStaticSiteDescriber(opt NewServiceConfig) (*StaticSiteDescriber, error) if err != nil { return nil, nil, fmt.Errorf("get environment %s: %w", env, err) } - sess, err := sessions.ImmutableProvider().FromRole(environment.ManagerRoleARN, environment.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), environment.ManagerRoleARN, environment.Region) if err != nil { return nil, nil, err } - cfg := v2ConfigFromSessionRegion(sess) - return awsS3.New(cfg), s3.New(sess, cfg), nil + return awsS3.New(cfg), s3.New(cfg), nil } return describer, nil } diff --git a/internal/pkg/describe/status_describe.go b/internal/pkg/describe/status_describe.go index d4b50e60052..a152b4faa43 100644 --- a/internal/pkg/describe/status_describe.go +++ b/internal/pkg/describe/status_describe.go @@ -4,6 +4,7 @@ package describe import ( + "context" "fmt" "sort" @@ -18,7 +19,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/ecs" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -96,7 +97,7 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er if err != nil { return nil, fmt.Errorf("get environment %s: %w", opt.Env, err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, fmt.Errorf("session for role %s and region %s: %w", env.ManagerRoleARN, env.Region, err) } @@ -104,11 +105,11 @@ func NewECSStatusDescriber(opt *NewServiceStatusConfig) (*ecsStatusDescriber, er app: opt.App, env: opt.Env, svc: opt.Svc, - svcDescriber: ecs.New(sess, v2ConfigFromSessionRegion(sess)), - cwSvcGetter: cloudwatch.New(v2ConfigFromSessionRegion(sess), v2ConfigFromSessionRegion(sess)), - ecsSvcGetter: awsecs.New(v2ConfigFromSessionRegion(sess)), - aasSvcGetter: aas.New(v2ConfigFromSessionRegion(sess)), - targetHealthGetter: elbv2.New(v2ConfigFromSessionRegion(sess)), + svcDescriber: ecs.New(cfg), + cwSvcGetter: cloudwatch.New(cfg, cfg), + ecsSvcGetter: awsecs.New(cfg), + aasSvcGetter: aas.New(cfg), + targetHealthGetter: elbv2.New(cfg), }, nil } @@ -129,7 +130,7 @@ func NewAppRunnerStatusDescriber(opt *NewServiceStatusConfig) (*appRunnerStatusD env: opt.Env, svc: opt.Svc, svcDescriber: appRunnerSvcDescriber, - eventsGetter: cloudwatchlogs.New(v2ConfigFromSessionRegion(appRunnerSvcDescriber.sess)), + eventsGetter: cloudwatchlogs.New(appRunnerSvcDescriber.cfg), }, nil } @@ -145,12 +146,11 @@ func NewStaticSiteStatusDescriber(opt *NewServiceStatusConfig) (*staticSiteStatu if err != nil { return nil, nil, fmt.Errorf("get environment %s: %w", env, err) } - sess, err := sessions.ImmutableProvider().FromRole(environment.ManagerRoleARN, environment.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), environment.ManagerRoleARN, environment.Region) if err != nil { return nil, nil, err } - cfg := v2ConfigFromSessionRegion(sess) - return awsS3.New(cfg), s3.New(sess, cfg), nil + return awsS3.New(cfg), s3.New(cfg), nil } return describer, nil } @@ -170,7 +170,7 @@ func (s *ecsStatusDescriber) Describe() (HumanJSONStringer, error) { for _, task := range svcDesc.Tasks { status, err := task.TaskStatus() if err != nil { - return nil, fmt.Errorf("get status for task %s: %w", aws.StringValue(task.TaskArn), err) + return nil, fmt.Errorf("get status for task %s: %w", aws.ToString(task.TaskArn), err) } taskStatus = append(taskStatus, *status) } @@ -179,7 +179,7 @@ func (s *ecsStatusDescriber) Describe() (HumanJSONStringer, error) { for _, task := range svcDesc.StoppedTasks { status, err := task.TaskStatus() if err != nil { - return nil, fmt.Errorf("get status for stopped task %s: %w", aws.StringValue(task.TaskArn), err) + return nil, fmt.Errorf("get status for stopped task %s: %w", aws.ToString(task.TaskArn), err) } stoppedTaskStatus = append(stoppedTaskStatus, *status) } @@ -328,7 +328,7 @@ func targetHealthForTasks(targetsHealth []*elbv2.TargetHealth, tasks []*awsecs.T continue } - taskID, err := awsecs.TaskID(aws.StringValue(task.TaskArn)) + taskID, err := awsecs.TaskID(aws.ToString(task.TaskArn)) if err != nil { continue } diff --git a/internal/pkg/describe/status_describe_test.go b/internal/pkg/describe/status_describe_test.go index 2fe9f9c95ac..61b3f1e8b12 100644 --- a/internal/pkg/describe/status_describe_test.go +++ b/internal/pkg/describe/status_describe_test.go @@ -16,9 +16,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/elbv2" "github.com/aproint/copilot-cli/internal/pkg/describe/mocks" "github.com/aproint/copilot-cli/internal/pkg/ecs" + "github.com/aws/aws-sdk-go-v2/aws" ecsapi "github.com/aws/aws-sdk-go-v2/service/ecs/types" elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" - "github.com/aws/aws-sdk-go/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/describe/worker_service.go b/internal/pkg/describe/worker_service.go index dfafc1a958c..4c545f8063e 100644 --- a/internal/pkg/describe/worker_service.go +++ b/internal/pkg/describe/worker_service.go @@ -5,6 +5,7 @@ package describe import ( "bytes" + "context" "encoding/json" "fmt" "text/tabwriter" @@ -66,11 +67,10 @@ func NewWorkerServiceDescriber(opt NewServiceConfig) (*WorkerServiceDescriber, e if err != nil { return nil, fmt.Errorf("get environment %s: %w", envName, err) } - sess, err := sessions.ImmutableProvider().FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return nil, err } - cfg := v2ConfigFromSessionRegion(sess) return cloudwatch.New(cfg, cfg), nil } return describer, nil diff --git a/internal/pkg/describe/workload.go b/internal/pkg/describe/workload.go index a0fcb43976a..b209cd881f7 100644 --- a/internal/pkg/describe/workload.go +++ b/internal/pkg/describe/workload.go @@ -4,6 +4,7 @@ package describe import ( + "context" "fmt" "strings" @@ -11,7 +12,7 @@ import ( cfnstack "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" "github.com/aproint/copilot-cli/internal/pkg/describe/stack" "github.com/aproint/copilot-cli/internal/pkg/version" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -21,8 +22,8 @@ type WorkloadStackDescriber struct { name string env string - cfn stackDescriber - sess *session.Session + cfn stackDescriber + cfg aws.Config // Cache variables. params map[string]string @@ -44,7 +45,7 @@ func NewWorkloadStackDescriber(opt NewWorkloadConfig) (*WorkloadStackDescriber, if err != nil { return nil, fmt.Errorf("get environment %s: %w", opt.Env, err) } - sess, err := sessions.ImmutableProvider().FromRole(environment.ManagerRoleARN, environment.Region) + cfg, err := sessions.ImmutableProvider().ConfigFromRole(context.Background(), environment.ManagerRoleARN, environment.Region) if err != nil { return nil, err } @@ -53,8 +54,8 @@ func NewWorkloadStackDescriber(opt NewWorkloadConfig) (*WorkloadStackDescriber, name: opt.Name, env: opt.Env, - cfn: stack.NewStackDescriber(cfnstack.NameForWorkload(opt.App, opt.Env, opt.Name), sess), - sess: sess, + cfn: stack.NewStackDescriber(cfnstack.NameForWorkload(opt.App, opt.Env, opt.Name), cfg), + cfg: cfg, }, nil } diff --git a/internal/pkg/ecs/ecs.go b/internal/pkg/ecs/ecs.go index 59e836e5d07..a8469760f28 100644 --- a/internal/pkg/ecs/ecs.go +++ b/internal/pkg/ecs/ecs.go @@ -16,10 +16,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/aws/stepfunctions" "github.com/aproint/copilot-cli/internal/pkg/deploy" - awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" ) const ( @@ -79,7 +77,7 @@ type Client struct { } // New creates a new Client. -func New(sess *session.Session, rgConfig awsv2.Config) *Client { +func New(rgConfig aws.Config) *Client { return &Client{ rgGetter: resourcegroups.New(rgConfig), ecsClient: ecs.New(rgConfig), @@ -87,8 +85,8 @@ func New(sess *session.Session, rgConfig awsv2.Config) *Client { } // NewWithStepFunctionsConfig creates a new Client with a Step Functions client configured from SDK v2 config. -func NewWithStepFunctionsConfig(sess *session.Session, cfg awsv2.Config) *Client { - client := New(sess, cfg) +func NewWithStepFunctionsConfig(cfg aws.Config) *Client { + client := New(cfg) client.StepFuncClient = stepfunctions.New(cfg) return client } @@ -154,17 +152,17 @@ func (c Client) ServiceConnectServices(app, env, svc string) ([]*ecs.Service, er return nil, nil } - arns, err := c.ecsClient.ListServicesByNamespace(aws.StringValue(s.Deployments[0].ServiceConnectConfiguration.Namespace)) + arns, err := c.ecsClient.ListServicesByNamespace(aws.ToString(s.Deployments[0].ServiceConnectConfiguration.Namespace)) if err != nil { return nil, fmt.Errorf("get services in the same namespace: %w", err) } // remove this service's arn arns = slices.DeleteFunc(arns, func(arn string) bool { - return arn == aws.StringValue(s.ServiceArn) + return arn == aws.ToString(s.ServiceArn) }) - svcs, err := c.ecsClient.Services(aws.StringValue(s.ClusterArn), arns...) + svcs, err := c.ecsClient.Services(aws.ToString(s.ClusterArn), arns...) if err != nil { return nil, fmt.Errorf("get services: %w", err) } @@ -250,7 +248,7 @@ func (c Client) stopTasks(app, env string, filter ListTasksFilter) error { } taskIDs := make([]string, len(tasks)) for n, task := range tasks { - taskIDs[n] = aws.StringValue(task.TaskArn) + taskIDs[n] = aws.ToString(task.TaskArn) } clusterARN, err := c.ClusterARN(app, env) if err != nil { @@ -271,7 +269,7 @@ func (c Client) StopDefaultClusterTasks(familyName string) error { } taskIDs := make([]string, len(tasks)) for n, task := range tasks { - taskIDs[n] = aws.StringValue(task.TaskArn) + taskIDs[n] = aws.ToString(task.TaskArn) } return c.ecsClient.StopTasks(taskIDs, ecs.WithStopTaskReason(taskStopReason)) } @@ -401,7 +399,7 @@ func (c Client) listActiveCopilotTasks(opts listActiveCopilotTasksOpts) ([]*ecs. func filterTasksByID(tasks []*ecs.Task, taskID string) []*ecs.Task { var filteredTasks []*ecs.Task for _, task := range tasks { - id, _ := ecs.TaskID(aws.StringValue(task.TaskArn)) + id, _ := ecs.TaskID(aws.ToString(task.TaskArn)) if strings.Contains(id, taskID) { filteredTasks = append(filteredTasks, task) } @@ -415,7 +413,7 @@ func filterCopilotTasks(tasks []*ecs.Task, taskID string) []*ecs.Task { for _, task := range filterTasksByID(tasks, taskID) { var copilotTask bool for _, tag := range task.Tags { - if aws.StringValue(tag.Key) == deploy.TaskTagKey { + if aws.ToString(tag.Key) == deploy.TaskTagKey { copilotTask = true break } @@ -561,7 +559,7 @@ func (c Client) HasNonZeroExitCode(taskARNs []string, cluster string) error { return fmt.Errorf("cannot find tasks %s", strings.Join(taskARNs, ", ")) } - taskDefinitonARN := aws.StringValue(tasks[0].TaskDefinitionArn) + taskDefinitonARN := aws.ToString(tasks[0].TaskDefinitionArn) taskDefinition, err := c.ecsClient.TaskDefinition(taskDefinitonARN) if err != nil { return fmt.Errorf("get task definition %s: %w", taskDefinitonARN, err) @@ -569,19 +567,19 @@ func (c Client) HasNonZeroExitCode(taskARNs []string, cluster string) error { isContainerEssential := make(map[string]bool) for _, container := range taskDefinition.ContainerDefinitions { - isContainerEssential[aws.StringValue(container.Name)] = aws.BoolValue(container.Essential) + isContainerEssential[aws.ToString(container.Name)] = aws.ToBool(container.Essential) } for _, describedTask := range tasks { for _, container := range describedTask.Containers { - if isContainerEssential[aws.StringValue(container.Name)] && awsv2.ToInt32(container.ExitCode) != 0 { - taskID, err := ecs.TaskID(aws.StringValue(describedTask.TaskArn)) + if isContainerEssential[aws.ToString(container.Name)] && aws.ToInt32(container.ExitCode) != 0 { + taskID, err := ecs.TaskID(aws.ToString(describedTask.TaskArn)) if err != nil { return err } - return &ErrExitCode{aws.StringValue(container.Name), + return &ErrExitCode{aws.ToString(container.Name), taskID, - int(awsv2.ToInt32(container.ExitCode))} + int(aws.ToInt32(container.ExitCode))} } } } diff --git a/internal/pkg/ecs/ecs_test.go b/internal/pkg/ecs/ecs_test.go index c8d3295ea8d..b90dabe67ad 100644 --- a/internal/pkg/ecs/ecs_test.go +++ b/internal/pkg/ecs/ecs_test.go @@ -13,9 +13,9 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/resourcegroups" "github.com/aproint/copilot-cli/internal/pkg/deploy" "github.com/aproint/copilot-cli/internal/pkg/ecs/mocks" + "github.com/aws/aws-sdk-go-v2/aws" awsv2 "github.com/aws/aws-sdk-go-v2/aws" awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/ecs/run_task_request.go b/internal/pkg/ecs/run_task_request.go index bb89db256e2..a5b4abc611f 100644 --- a/internal/pkg/ecs/run_task_request.go +++ b/internal/pkg/ecs/run_task_request.go @@ -11,7 +11,7 @@ import ( "strings" awsecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -72,7 +72,7 @@ func RunTaskRequestFromECSService(client ECSServiceDescriber, cluster, service s return nil, fmt.Errorf("retrieve service %s in cluster %s: %w", service, cluster, err) } - taskDefNameOrARN := aws.StringValue(svc.TaskDefinition) + taskDefNameOrARN := aws.ToString(svc.TaskDefinition) taskDef, err := client.TaskDefinition(taskDefNameOrARN) if err != nil { return nil, fmt.Errorf("retrieve task definition %s: %w", taskDefNameOrARN, err) @@ -84,7 +84,7 @@ func RunTaskRequestFromECSService(client ECSServiceDescriber, cluster, service s } } - containerName := aws.StringValue(taskDef.ContainerDefinitions[0].Name) + containerName := aws.ToString(taskDef.ContainerDefinitions[0].Name) containerInfo, err := containerInformation(taskDef, containerName) if err != nil { return nil, err @@ -92,8 +92,8 @@ func RunTaskRequestFromECSService(client ECSServiceDescriber, cluster, service s return &RunTaskRequest{ networkConfiguration: *networkConfig, - executionRole: aws.StringValue(taskDef.ExecutionRoleArn), - taskRole: aws.StringValue(taskDef.TaskRoleArn), + executionRole: aws.ToString(taskDef.ExecutionRoleArn), + taskRole: aws.ToString(taskDef.TaskRoleArn), containerInfo: *containerInfo, cluster: cluster, }, nil @@ -125,8 +125,8 @@ func RunTaskRequestFromService(client ServiceDescriber, app, env, svc string) (* return &RunTaskRequest{ networkConfiguration: *networkConfig, - executionRole: aws.StringValue(taskDef.ExecutionRoleArn), - taskRole: aws.StringValue(taskDef.TaskRoleArn), + executionRole: aws.ToString(taskDef.ExecutionRoleArn), + taskRole: aws.ToString(taskDef.TaskRoleArn), containerInfo: *containerInfo, appName: app, envName: env, @@ -159,8 +159,8 @@ func RunTaskRequestFromJob(client JobDescriber, app, env, job string) (*RunTaskR return &RunTaskRequest{ networkConfiguration: *config, - executionRole: aws.StringValue(taskDef.ExecutionRoleArn), - taskRole: aws.StringValue(taskDef.TaskRoleArn), + executionRole: aws.ToString(taskDef.ExecutionRoleArn), + taskRole: aws.ToString(taskDef.TaskRoleArn), containerInfo: *containerInfo, appName: app, envName: env, diff --git a/internal/pkg/ecs/run_task_request_test.go b/internal/pkg/ecs/run_task_request_test.go index d696478432c..6aacab572ea 100644 --- a/internal/pkg/ecs/run_task_request_test.go +++ b/internal/pkg/ecs/run_task_request_test.go @@ -12,8 +12,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/ecs/mocks" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" + "github.com/aws/aws-sdk-go-v2/aws" awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/initialize/workload.go b/internal/pkg/initialize/workload.go index f78fc706b23..bd1162f42e0 100644 --- a/internal/pkg/initialize/workload.go +++ b/internal/pkg/initialize/workload.go @@ -17,7 +17,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -344,7 +344,7 @@ func (w *WorkloadInitializer) newLoadBalancedWebServiceManifest(inProps *Service } // We default to "/" for the first service or if the application is initialized with a domain, but if there's another // Load Balanced Web Service, we use the svc name as the default, instead. - if aws.StringValue(inProps.appDomain) == "" { + if aws.ToString(inProps.appDomain) == "" { for _, existingSvc := range existingSvcs { if existingSvc.Type == manifestinfo.LoadBalancedWebServiceType && existingSvc.Name != inProps.Name { outProps.Path = inProps.Name diff --git a/internal/pkg/initialize/workload_test.go b/internal/pkg/initialize/workload_test.go index 7e8a50dab00..bfe779eacfc 100644 --- a/internal/pkg/initialize/workload_test.go +++ b/internal/pkg/initialize/workload_test.go @@ -12,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/initialize/mocks" "github.com/aproint/copilot-cli/internal/pkg/manifest" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -366,10 +366,10 @@ func TestAppInitOpts_createLoadBalancedAppManifest(t *testing.T) { // THEN if tc.wantedErr == nil { require.NoError(t, err) - require.Equal(t, tc.inSvcName, aws.StringValue(manifest.Workload.Name)) - require.Equal(t, tc.inSvcPort, aws.Uint16Value(manifest.ImageConfig.Port)) - require.Contains(t, tc.inDockerfilePath, aws.StringValue(manifest.ImageConfig.Image.Build.BuildArgs.Dockerfile)) - require.Equal(t, tc.wantedPath, aws.StringValue(manifest.HTTPOrBool.Main.Path)) + require.Equal(t, tc.inSvcName, aws.ToString(manifest.Workload.Name)) + require.Equal(t, tc.inSvcPort, aws.ToUint16(manifest.ImageConfig.Port)) + require.Contains(t, tc.inDockerfilePath, aws.ToString(manifest.ImageConfig.Image.Build.BuildArgs.Dockerfile)) + require.Equal(t, tc.wantedPath, aws.ToString(manifest.HTTPOrBool.Main.Path)) } else { require.EqualError(t, err, tc.wantedErr.Error()) } diff --git a/internal/pkg/logging/aws_config.go b/internal/pkg/logging/aws_config.go deleted file mode 100644 index a770049fc3e..00000000000 --- a/internal/pkg/logging/aws_config.go +++ /dev/null @@ -1,15 +0,0 @@ -package logging - -import ( - "context" - - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - awsv2 "github.com/aws/aws-sdk-go-v2/aws" - awsv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" -) - -func v2ConfigFromSessionRegion(sess *session.Session) awsv2.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), awsv1.StringValue(sess.Config.Region)) - return cfg -} diff --git a/internal/pkg/logging/task.go b/internal/pkg/logging/task.go index 6fb1ea18d62..d4d63b9f9ad 100644 --- a/internal/pkg/logging/task.go +++ b/internal/pkg/logging/task.go @@ -13,7 +13,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/task" "github.com/aproint/copilot-cli/internal/pkg/term/log" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -43,13 +43,13 @@ type TaskClient struct { } // NewTaskClient returns a TaskClient that can retrieve logs from the given tasks under the groupName. -func NewTaskClient(sess *session.Session, groupName string, tasks []*task.Task) *TaskClient { +func NewTaskClient(cfg aws.Config, groupName string, tasks []*task.Task) *TaskClient { return &TaskClient{ groupName: groupName, tasks: tasks, - taskDescriber: ecs.New(v2ConfigFromSessionRegion(sess)), - eventsLogger: cloudwatchlogs.New(v2ConfigFromSessionRegion(sess)), + taskDescriber: ecs.New(cfg), + eventsLogger: cloudwatchlogs.New(cfg), eventsWriter: log.OutputWriter, sleep: func() { diff --git a/internal/pkg/logging/task_test.go b/internal/pkg/logging/task_test.go index 6c1a3c3fe14..bc0d304dadd 100644 --- a/internal/pkg/logging/task_test.go +++ b/internal/pkg/logging/task_test.go @@ -12,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/logging/mocks" "github.com/aproint/copilot-cli/internal/pkg/task" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/logging/workload.go b/internal/pkg/logging/workload.go index 2645aff309c..3bfe0fa2039 100644 --- a/internal/pkg/logging/workload.go +++ b/internal/pkg/logging/workload.go @@ -14,8 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatchlogs" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/term/log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -39,7 +38,7 @@ type NewWorkloadLoggerOpts struct { App string Env string Name string - Sess *session.Session + Cfg aws.Config } // newWorkloadLogger returns a workloadLogger for the service under env and app. @@ -49,7 +48,7 @@ func newWorkloadLogger(opts *NewWorkloadLoggerOpts) *workloadLogger { app: opts.App, env: opts.Env, name: opts.Name, - eventsGetter: cloudwatchlogs.New(v2ConfigFromSessionRegion(opts.Sess)), + eventsGetter: cloudwatchlogs.New(opts.Cfg), w: log.OutputWriter, now: time.Now, } diff --git a/internal/pkg/logging/workload_test.go b/internal/pkg/logging/workload_test.go index 2fa3be8dce5..7b227eea186 100644 --- a/internal/pkg/logging/workload_test.go +++ b/internal/pkg/logging/workload_test.go @@ -12,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatchlogs" "github.com/aproint/copilot-cli/internal/pkg/logging/mocks" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/applyenv_test.go b/internal/pkg/manifest/applyenv_test.go index 537b037cad8..cec35d89f01 100644 --- a/internal/pkg/manifest/applyenv_test.go +++ b/internal/pkg/manifest/applyenv_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/backend_svc.go b/internal/pkg/manifest/backend_svc.go index 7205ca7f0f9..e94ce0c643f 100644 --- a/internal/pkg/manifest/backend_svc.go +++ b/internal/pkg/manifest/backend_svc.go @@ -8,7 +8,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" ) @@ -115,7 +115,7 @@ func (s *BackendService) Port() (port uint16, ok bool) { if value == nil { return 0, false } - return aws.Uint16Value(value), true + return aws.ToUint16(value), true } // Publish returns the list of topics where notifications can be published. @@ -132,7 +132,7 @@ func (s *BackendService) BuildArgs(contextDir string) (map[string]*DockerBuildAr // Creating an map to store buildArgs of all sidecar images and main container image. buildArgsPerContainer := make(map[string]*DockerBuildArgs, len(s.Sidecars)+1) if required { - buildArgsPerContainer[aws.StringValue(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) + buildArgsPerContainer[aws.ToString(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) } return buildArgs(contextDir, buildArgsPerContainer, s.Sidecars) } @@ -147,7 +147,7 @@ func (s *BackendService) EnvFiles() map[string]string { // ContainerDependencies returns a map of ContainerDependency objects for the BackendService // including dependencies for its main container, any logging sidecar, and additional sidecars. func (s *BackendService) ContainerDependencies() map[string]ContainerDependency { - return containerDependencies(aws.StringValue(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) + return containerDependencies(aws.ToString(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) } func (s *BackendService) subnets() *SubnetListOrArgs { @@ -214,7 +214,7 @@ func newDefaultBackendService() *BackendService { func (b *BackendService) ExposedPorts() (ExposedPortsIndex, error) { exposedPorts := make(map[uint16]ExposedPort) - workloadName := aws.StringValue(b.Name) + workloadName := aws.ToString(b.Name) for name, sidecar := range b.Sidecars { newExposedPorts, err := sidecar.exposePorts(exposedPorts, name) if err != nil { diff --git a/internal/pkg/manifest/backend_svc_test.go b/internal/pkg/manifest/backend_svc_test.go index 470fec93c9d..cb07bc10d8b 100644 --- a/internal/pkg/manifest/backend_svc_test.go +++ b/internal/pkg/manifest/backend_svc_test.go @@ -9,7 +9,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/env.go b/internal/pkg/manifest/env.go index dd53599316b..37dbad06e58 100644 --- a/internal/pkg/manifest/env.go +++ b/internal/pkg/manifest/env.go @@ -10,7 +10,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -103,10 +103,10 @@ func (mft *EnvironmentConfig) IsPublicLBIngressRestrictedToCDN() bool { // Check the fixed manifest first. This would be `http.public.ingress.cdn`. // For more information, see https://github.com/aproint/copilot-cli/pull/4068#issuecomment-1275080333 if !mft.HTTPConfig.Public.Ingress.IsEmpty() { - return aws.BoolValue(mft.HTTPConfig.Public.Ingress.CDNIngress) + return aws.ToBool(mft.HTTPConfig.Public.Ingress.CDNIngress) } // Fall through to the old manifest: `http.public.security_groups.ingress.cdn`. - return aws.BoolValue(mft.HTTPConfig.Public.DeprecatedSG.DeprecatedIngress.RestrictiveIngress.CDNIngress) + return aws.ToBool(mft.HTTPConfig.Public.DeprecatedSG.DeprecatedIngress.RestrictiveIngress.CDNIngress) } // GetPublicALBSourceIPs returns list of IPNet. @@ -157,7 +157,7 @@ func (cfg *portsConfig) IsEmpty() bool { // GetPorts returns the from and to ports of a security group rule. func (r securityGroupRule) GetPorts() (from, to int, err error) { if r.Ports.Range == nil { - return aws.IntValue(r.Ports.Port), aws.IntValue(r.Ports.Port), nil // a single value is provided for ports. + return aws.ToInt(r.Ports.Port), aws.ToInt(r.Ports.Port), nil // a single value is provided for ports. } return r.Ports.Range.Parse() } @@ -234,7 +234,7 @@ func (cfg *EnvironmentConfig) CDNEnabled() bool { if !cfg.CDNConfig.Config.isEmpty() { return true } - return aws.BoolValue(cfg.CDNConfig.Enabled) + return aws.ToBool(cfg.CDNConfig.Enabled) } // HasImportedPublicALBCerts returns true when the environment's ALB @@ -246,7 +246,7 @@ func (cfg *EnvironmentConfig) HasImportedPublicALBCerts() bool { // CDNDoesTLSTermination returns true when the environment's CDN // is configured to terminate incoming TLS connections. func (cfg *EnvironmentConfig) CDNDoesTLSTermination() bool { - return aws.BoolValue(cfg.CDNConfig.Config.TerminateTLS) + return aws.ToBool(cfg.CDNConfig.Config.TerminateTLS) } // UnmarshalYAML overrides the default YAML unmarshaling logic for the environmentCDNConfig @@ -341,11 +341,11 @@ func UnmarshalEnvironment(in []byte) (*Environment, error) { } func (cfg *environmentVPCConfig) imported() bool { - return aws.StringValue(cfg.ID) != "" + return aws.ToString(cfg.ID) != "" } func (cfg *environmentVPCConfig) managedVPCCustomized() bool { - return aws.StringValue((*string)(cfg.CIDR)) != "" + return aws.ToString((*string)(cfg.CIDR)) != "" } // ImportedVPC returns configurations that import VPC resources if there is any. @@ -355,13 +355,13 @@ func (cfg *environmentVPCConfig) ImportedVPC() *template.ImportVPC { } var publicSubnetIDs, privateSubnetIDs []string for _, subnet := range cfg.Subnets.Public { - publicSubnetIDs = append(publicSubnetIDs, aws.StringValue(subnet.SubnetID)) + publicSubnetIDs = append(publicSubnetIDs, aws.ToString(subnet.SubnetID)) } for _, subnet := range cfg.Subnets.Private { - privateSubnetIDs = append(privateSubnetIDs, aws.StringValue(subnet.SubnetID)) + privateSubnetIDs = append(privateSubnetIDs, aws.ToString(subnet.SubnetID)) } return &template.ImportVPC{ - ID: aws.StringValue(cfg.ID), + ID: aws.ToString(cfg.ID), PublicSubnetIDs: publicSubnetIDs, PrivateSubnetIDs: privateSubnetIDs, } @@ -386,20 +386,20 @@ func (cfg *environmentVPCConfig) ManagedVPC() *template.ManagedVPC { // For example, if we have two subnets defined: public-subnet-1 ~ us-east-1a, and private-subnet-1 ~ us-east-1a. // We want to make sure that public-subnet-1, us-east-1a and private-subnet-1 are all at index 0 of in perspective lists. sort.SliceStable(cfg.Subnets.Public, func(i, j int) bool { - return aws.StringValue(cfg.Subnets.Public[i].AZ) < aws.StringValue(cfg.Subnets.Public[j].AZ) + return aws.ToString(cfg.Subnets.Public[i].AZ) < aws.ToString(cfg.Subnets.Public[j].AZ) }) sort.SliceStable(cfg.Subnets.Private, func(i, j int) bool { - return aws.StringValue(cfg.Subnets.Private[i].AZ) < aws.StringValue(cfg.Subnets.Private[j].AZ) + return aws.ToString(cfg.Subnets.Private[i].AZ) < aws.ToString(cfg.Subnets.Private[j].AZ) }) for idx, subnet := range cfg.Subnets.Public { - publicSubnetCIDRs[idx] = aws.StringValue((*string)(subnet.CIDR)) - privateSubnetCIDRs[idx] = aws.StringValue((*string)(cfg.Subnets.Private[idx].CIDR)) - if az := aws.StringValue(subnet.AZ); az != "" { + publicSubnetCIDRs[idx] = aws.ToString((*string)(subnet.CIDR)) + privateSubnetCIDRs[idx] = aws.ToString((*string)(cfg.Subnets.Private[idx].CIDR)) + if az := aws.ToString(subnet.AZ); az != "" { azs = append(azs, az) } } return &template.ManagedVPC{ - CIDR: aws.StringValue((*string)(cfg.CIDR)), + CIDR: aws.ToString((*string)(cfg.CIDR)), AZs: azs, PublicSubnetCIDRs: publicSubnetCIDRs, PrivateSubnetCIDRs: privateSubnetCIDRs, @@ -528,7 +528,7 @@ func (cfg *EnvironmentConfig) ELBAccessLogs() (*ELBAccessLogsArgs, bool) { return nil, false } if accessLogs.Enabled != nil { - return nil, aws.BoolValue(accessLogs.Enabled) + return nil, aws.ToBool(accessLogs.Enabled) } return &accessLogs.AdvancedConfig, true } @@ -575,5 +575,5 @@ func (cfg privateHTTPConfig) IsEmpty() bool { // HasVPCIngress returns true if the private ALB allows ingress from within the VPC. func (cfg privateHTTPConfig) HasVPCIngress() bool { - return aws.BoolValue(cfg.Ingress.VPCIngress) || aws.BoolValue(cfg.DeprecatedSG.DeprecatedIngress.VPCIngress) + return aws.ToBool(cfg.Ingress.VPCIngress) || aws.ToBool(cfg.DeprecatedSG.DeprecatedIngress.VPCIngress) } diff --git a/internal/pkg/manifest/env_test.go b/internal/pkg/manifest/env_test.go index 544c77a09b9..2f2f56a9be0 100644 --- a/internal/pkg/manifest/env_test.go +++ b/internal/pkg/manifest/env_test.go @@ -9,7 +9,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/http.go b/internal/pkg/manifest/http.go index 71ff60159ae..1a4c2ca62e5 100644 --- a/internal/pkg/manifest/http.go +++ b/internal/pkg/manifest/http.go @@ -8,7 +8,7 @@ import ( "strings" "time" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -24,7 +24,7 @@ func (r *HTTPOrBool) isEmpty() bool { // Disabled returns true if the routing rule configuration is explicitly disabled. func (r *HTTPOrBool) Disabled() bool { - return r.Enabled != nil && !aws.BoolValue(r.Enabled) + return r.Enabled != nil && !aws.ToBool(r.Enabled) } // UnmarshalYAML implements the yaml(v3) interface. It allows https routing rule to be specified as a @@ -106,13 +106,13 @@ func (r *RoutingRule) IsEmpty() bool { func (r *RoutingRule) HealthCheckPort(mainContainerPort *uint16) uint16 { // healthCheckPort is defined by RoutingRule.HealthCheck.Port, with fallback on RoutingRule.TargetPort, then image.port. if r.HealthCheck.Advanced.Port != nil { - return uint16(aws.IntValue(r.HealthCheck.Advanced.Port)) + return uint16(aws.ToInt(r.HealthCheck.Advanced.Port)) } if r.TargetPort != nil { - return aws.Uint16Value(r.TargetPort) + return aws.ToUint16(r.TargetPort) } if mainContainerPort != nil { - return aws.Uint16Value(mainContainerPort) + return aws.ToUint16(mainContainerPort) } return 0 } @@ -188,7 +188,7 @@ func (a *Alias) ToStringSlice() ([]string, error) { } aliases := make([]string, len(a.AdvancedAliases)) for i, advancedAlias := range a.AdvancedAliases { - aliases[i] = aws.StringValue(advancedAlias.Alias) + aliases[i] = aws.ToString(advancedAlias.Alias) } return aliases, nil } @@ -198,12 +198,12 @@ func (a *Alias) ToString() string { if len(a.AdvancedAliases) != 0 { aliases := make([]string, len(a.AdvancedAliases)) for i, advancedAlias := range a.AdvancedAliases { - aliases[i] = aws.StringValue(advancedAlias.Alias) + aliases[i] = aws.ToString(advancedAlias.Alias) } return strings.Join(aliases, ",") } if a.StringSliceOrString.String != nil { - return aws.StringValue(a.StringSliceOrString.String) + return aws.ToString(a.StringSliceOrString.String) } return strings.Join(a.StringSliceOrString.StringSlice, ",") } diff --git a/internal/pkg/manifest/http_test.go b/internal/pkg/manifest/http_test.go index 31152309bea..23c48dc6f85 100644 --- a/internal/pkg/manifest/http_test.go +++ b/internal/pkg/manifest/http_test.go @@ -6,7 +6,7 @@ package manifest import ( "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/job.go b/internal/pkg/manifest/job.go index cbb7de81294..f75b1888720 100644 --- a/internal/pkg/manifest/job.go +++ b/internal/pkg/manifest/job.go @@ -8,7 +8,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" ) @@ -152,7 +152,7 @@ func (j *ScheduledJob) BuildArgs(contextDir string) (map[string]*DockerBuildArgs // Creating an map to store buildArgs of all sidecar images and main container image. buildArgsPerContainer := make(map[string]*DockerBuildArgs, len(j.Sidecars)+1) if required { - buildArgsPerContainer[aws.StringValue(j.Name)] = j.ImageConfig.Image.BuildConfig(contextDir) + buildArgsPerContainer[aws.ToString(j.Name)] = j.ImageConfig.Image.BuildConfig(contextDir) } return buildArgs(contextDir, buildArgsPerContainer, j.Sidecars) } @@ -167,7 +167,7 @@ func (j *ScheduledJob) EnvFiles() map[string]string { // ContainerDependencies returns a map of ContainerDependency objects for ScheduledJob // including dependencies for its main container, any logging sidecar, and additional sidecars. func (s *ScheduledJob) ContainerDependencies() map[string]ContainerDependency { - return containerDependencies(aws.StringValue(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) + return containerDependencies(aws.ToString(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) } // newDefaultScheduledJob returns an empty ScheduledJob with only the default values set. diff --git a/internal/pkg/manifest/job_test.go b/internal/pkg/manifest/job_test.go index d9d201b6f88..96cf4d5f32c 100644 --- a/internal/pkg/manifest/job_test.go +++ b/internal/pkg/manifest/job_test.go @@ -8,7 +8,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/lb_web_svc.go b/internal/pkg/manifest/lb_web_svc.go index d837c606829..b30c93eb324 100644 --- a/internal/pkg/manifest/lb_web_svc.go +++ b/internal/pkg/manifest/lb_web_svc.go @@ -11,7 +11,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/color" "github.com/aproint/copilot-cli/internal/pkg/term/log" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" @@ -190,7 +190,7 @@ func (s *LoadBalancedWebService) Dockerfile() string { // Port returns the exposed port in the manifest. // A LoadBalancedWebService always has a port exposed therefore the boolean is always true. func (s *LoadBalancedWebService) Port() (port uint16, ok bool) { - return aws.Uint16Value(s.ImageConfig.Port), true + return aws.ToUint16(s.ImageConfig.Port), true } // Publish returns the list of topics where notifications can be published. @@ -207,7 +207,7 @@ func (s *LoadBalancedWebService) BuildArgs(contextDir string) (map[string]*Docke // Creating an map to store buildArgs of all sidecar images and main container image. buildArgsPerContainer := make(map[string]*DockerBuildArgs, len(s.Sidecars)+1) if required { - buildArgsPerContainer[aws.StringValue(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) + buildArgsPerContainer[aws.ToString(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) } return buildArgs(contextDir, buildArgsPerContainer, s.Sidecars) } @@ -222,7 +222,7 @@ func (s *LoadBalancedWebService) EnvFiles() map[string]string { // ContainerDependencies returns a map of ContainerDependency objects for the LoadBalancedWebService // including dependencies for its main container, any logging sidecar, and additional sidecars. func (s *LoadBalancedWebService) ContainerDependencies() map[string]ContainerDependency { - return containerDependencies(aws.StringValue(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) + return containerDependencies(aws.ToString(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) } func (s *LoadBalancedWebService) subnets() *SubnetListOrArgs { @@ -286,24 +286,24 @@ func (c *NetworkLoadBalancerListener) IsEmpty() bool { func (listener NetworkLoadBalancerListener) HealthCheckPort(mainContainerPort *uint16) (uint16, error) { // healthCheckPort is defined by Listener.HealthCheck.Port, with fallback on Listener.TargetPort, then Listener.Port. if listener.HealthCheck.Port != nil { - return uint16(aws.IntValue(listener.HealthCheck.Port)), nil + return uint16(aws.ToInt(listener.HealthCheck.Port)), nil } if listener.TargetPort != nil { - return uint16(aws.IntValue(listener.TargetPort)), nil + return uint16(aws.ToInt(listener.TargetPort)), nil } if listener.Port != nil { port, _, err := ParsePortMapping(listener.Port) if err != nil { return 0, err } - parsedPort, err := strconv.ParseUint(aws.StringValue(port), 10, 16) + parsedPort, err := strconv.ParseUint(aws.ToString(port), 10, 16) if err != nil { return 0, err } return uint16(parsedPort), nil } if mainContainerPort != nil { - return aws.Uint16Value(mainContainerPort), nil + return aws.ToUint16(mainContainerPort), nil } return 0, nil } @@ -311,7 +311,7 @@ func (listener NetworkLoadBalancerListener) HealthCheckPort(mainContainerPort *u // ExposedPorts returns all the ports that are container ports available to receive traffic. func (lbws *LoadBalancedWebService) ExposedPorts() (ExposedPortsIndex, error) { exposedPorts := make(map[uint16]ExposedPort) - workloadName := aws.StringValue(lbws.Name) + workloadName := aws.ToString(lbws.Name) // port from sidecar[x].image.port. for name, sidecar := range lbws.Sidecars { newExposedPorts, err := sidecar.exposePorts(exposedPorts, name) diff --git a/internal/pkg/manifest/lb_web_svc_test.go b/internal/pkg/manifest/lb_web_svc_test.go index c66e274cda3..1485d88917c 100644 --- a/internal/pkg/manifest/lb_web_svc_test.go +++ b/internal/pkg/manifest/lb_web_svc_test.go @@ -11,7 +11,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/loader.go b/internal/pkg/manifest/loader.go index 5f66274cdb7..14aa1385d08 100644 --- a/internal/pkg/manifest/loader.go +++ b/internal/pkg/manifest/loader.go @@ -4,13 +4,8 @@ package manifest import ( - "context" - "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) type subnetIDsGetter interface { @@ -26,23 +21,18 @@ type DynamicWorkloadManifest struct { mft workloadManifest // Clients required to dynamically populate. - newSubnetIDsGetter func(*session.Session) subnetIDsGetter + newSubnetIDsGetter func(aws.Config) subnetIDsGetter } func newDynamicWorkloadManifest(mft workloadManifest) *DynamicWorkloadManifest { return &DynamicWorkloadManifest{ mft: mft, - newSubnetIDsGetter: func(s *session.Session) subnetIDsGetter { - return ec2.New(v2ConfigFromSessionRegion(s)) + newSubnetIDsGetter: func(cfg aws.Config) subnetIDsGetter { + return ec2.New(cfg) }, } } -func v2ConfigFromSessionRegion(sess *session.Session) awsv2.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.StringValue(sess.Config.Region)) - return cfg -} - // Manifest returns the manifest content. func (s *DynamicWorkloadManifest) Manifest() any { return s.mft @@ -65,11 +55,11 @@ func (s *DynamicWorkloadManifest) RequiredEnvironmentFeatures() []string { } // Load dynamically populates all fields in the manifest. -func (s *DynamicWorkloadManifest) Load(sess *session.Session) error { +func (s *DynamicWorkloadManifest) Load(cfg aws.Config) error { loaders := []loader{ &dynamicSubnets{ cfg: s.mft.subnets(), - client: s.newSubnetIDsGetter(sess), + client: s.newSubnetIDsGetter(cfg), }, } return loadAll(loaders) diff --git a/internal/pkg/manifest/loader_test.go b/internal/pkg/manifest/loader_test.go index b4e71c6fa60..30036445def 100644 --- a/internal/pkg/manifest/loader_test.go +++ b/internal/pkg/manifest/loader_test.go @@ -10,8 +10,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" "github.com/aproint/copilot-cli/internal/pkg/manifest/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) @@ -76,11 +75,11 @@ func TestDynamicWorkloadManifest_Load(t *testing.T) { dyn := &DynamicWorkloadManifest{ mft: tc.inMft, - newSubnetIDsGetter: func(s *session.Session) subnetIDsGetter { + newSubnetIDsGetter: func(cfg aws.Config) subnetIDsGetter { return m.mockSubnetGetter }, } - err := dyn.Load(nil) + err := dyn.Load(aws.Config{}) if tc.wantedError != nil { require.EqualError(t, err, tc.wantedError.Error()) } else { diff --git a/internal/pkg/manifest/marshal_manifest_integration_test.go b/internal/pkg/manifest/marshal_manifest_integration_test.go index e193be66b5b..957a6b9e821 100644 --- a/internal/pkg/manifest/marshal_manifest_integration_test.go +++ b/internal/pkg/manifest/marshal_manifest_integration_test.go @@ -12,7 +12,7 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/config" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/rd_web_svc.go b/internal/pkg/manifest/rd_web_svc.go index b56e06f4977..30c3abc7013 100644 --- a/internal/pkg/manifest/rd_web_svc.go +++ b/internal/pkg/manifest/rd_web_svc.go @@ -6,7 +6,7 @@ package manifest import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" ) @@ -68,7 +68,7 @@ func (c *RequestDrivenWebServiceNetworkConfig) IsEmpty() bool { } func (c *RequestDrivenWebServiceNetworkConfig) requiredEnvFeatures() []string { - if aws.StringValue((*string)(c.VPC.Placement.PlacementString)) == string(PrivateSubnetPlacement) { + if aws.ToString((*string)(c.VPC.Placement.PlacementString)) == string(PrivateSubnetPlacement) { return []string{template.NATFeatureName} } return nil @@ -143,7 +143,7 @@ func (s *RequestDrivenWebService) Dockerfile() string { // Port returns the exposed the exposed port in the manifest. // A RequestDrivenWebService always has a port exposed therefore the boolean is always true. func (s *RequestDrivenWebService) Port() (port uint16, ok bool) { - return aws.Uint16Value(s.ImageConfig.Port), true + return aws.ToUint16(s.ImageConfig.Port), true } // Publish returns the list of topics where notifications can be published. @@ -168,7 +168,7 @@ func (s *RequestDrivenWebService) BuildArgs(contextDir string) (map[string]*Dock // Creating an map to store buildArgs of all sidecar images and main container image. buildArgsPerContainer := make(map[string]*DockerBuildArgs, 1) if required { - buildArgsPerContainer[aws.StringValue(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) + buildArgsPerContainer[aws.ToString(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) } return buildArgsPerContainer, nil } diff --git a/internal/pkg/manifest/rd_web_svc_test.go b/internal/pkg/manifest/rd_web_svc_test.go index f274489de24..30df151258b 100644 --- a/internal/pkg/manifest/rd_web_svc_test.go +++ b/internal/pkg/manifest/rd_web_svc_test.go @@ -12,7 +12,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/template/mocks" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" diff --git a/internal/pkg/manifest/static_site.go b/internal/pkg/manifest/static_site.go index f2ca4963603..449eb191040 100644 --- a/internal/pkg/manifest/static_site.go +++ b/internal/pkg/manifest/static_site.go @@ -6,7 +6,7 @@ package manifest import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" ) diff --git a/internal/pkg/manifest/static_site_test.go b/internal/pkg/manifest/static_site_test.go index 8d5aa8ba247..1471a27f245 100644 --- a/internal/pkg/manifest/static_site_test.go +++ b/internal/pkg/manifest/static_site_test.go @@ -7,7 +7,7 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/storage.go b/internal/pkg/manifest/storage.go index 99e4b58ca35..103dd3479fa 100644 --- a/internal/pkg/manifest/storage.go +++ b/internal/pkg/manifest/storage.go @@ -7,7 +7,7 @@ import ( "errors" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -135,7 +135,7 @@ func (e *EFSConfigOrBool) UnmarshalYAML(value *yaml.Node) error { func (e *EFSConfigOrBool) UseManagedFS() bool { // Respect explicitly enabled or disabled value first. if e.Enabled != nil { - return aws.BoolValue(e.Enabled) + return aws.ToBool(e.Enabled) } // Check whether we're implicitly enabling managed EFS via UID/GID. return !e.Advanced.EmptyUIDConfig() @@ -145,7 +145,7 @@ func (e *EFSConfigOrBool) UseManagedFS() bool { // This function is useful for checking that the EFS config has been intentionally turned off // and whether we should ignore any values of the struct which have been populated erroneously. func (e *EFSConfigOrBool) Disabled() bool { - if e.Enabled != nil && !aws.BoolValue(e.Enabled) { + if e.Enabled != nil && !aws.ToBool(e.Enabled) { return true } return false diff --git a/internal/pkg/manifest/storage_test.go b/internal/pkg/manifest/storage_test.go index 6d076cc31c5..279468df810 100644 --- a/internal/pkg/manifest/storage_test.go +++ b/internal/pkg/manifest/storage_test.go @@ -6,7 +6,7 @@ package manifest import ( "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/svc.go b/internal/pkg/manifest/svc.go index 3a877866a07..86a86bac76b 100644 --- a/internal/pkg/manifest/svc.go +++ b/internal/pkg/manifest/svc.go @@ -15,7 +15,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -70,7 +70,7 @@ func (r *Range) Parse() (min int, max int, err error) { if r.Value != nil { return r.Value.Parse() } - return aws.IntValue(r.RangeConfig.Min), aws.IntValue(r.RangeConfig.Max), nil + return aws.ToInt(r.RangeConfig.Min), aws.ToInt(r.RangeConfig.Max), nil } // UnmarshalYAML overrides the default YAML unmarshaling logic for the RangeOpts @@ -206,7 +206,7 @@ func (c *Count) Desired() (*int, error) { } min, _, err := c.AdvancedCount.Range.Parse() if err != nil { - return nil, fmt.Errorf("parse task count value %s: %w", aws.StringValue((*string)(c.AdvancedCount.Range.Value)), err) + return nil, fmt.Errorf("parse task count value %s: %w", aws.ToString((*string)(c.AdvancedCount.Range.Value)), err) } return aws.Int(min), nil } @@ -462,7 +462,7 @@ func (cfg ImageWithPortAndHealthcheck) exposePorts(exposedPorts map[uint16]Expos } newExposedPorts := make(map[uint16]ExposedPort) - targetPort := aws.Uint16Value(cfg.Port) + targetPort := aws.ToUint16(cfg.Port) if exposedPort, ok := exposedPorts[targetPort]; ok { newExposedPorts[targetPort] = ExposedPort{ Port: exposedPort.Port, @@ -488,7 +488,7 @@ func (cfg ImageWithHealthcheckAndOptionalPort) exposePorts(exposedPorts map[uint } newExposedPorts := make(map[uint16]ExposedPort) - targetPort := aws.Uint16Value(cfg.Port) + targetPort := aws.ToUint16(cfg.Port) if exposedPort, ok := exposedPorts[targetPort]; ok { newExposedPorts[targetPort] = ExposedPort{ Port: exposedPort.Port, @@ -516,9 +516,9 @@ func (rule RoutingRule) exposePorts(exposedPorts map[uint16]ExposedPort, workloa } targetContainer := workloadName if rule.TargetContainer != nil { - targetContainer = aws.StringValue(rule.TargetContainer) + targetContainer = aws.ToString(rule.TargetContainer) } - targetPort := aws.Uint16Value(rule.TargetPort) + targetPort := aws.ToUint16(rule.TargetPort) if _, ok := exposedPorts[targetPort]; ok { return nil } @@ -542,18 +542,18 @@ func (cfg NetworkLoadBalancerListener) exposePorts(exposedPorts map[uint16]Expos return nil, err } - port, err := strconv.ParseUint(aws.StringValue(nlbPort), 10, 16) + port, err := strconv.ParseUint(aws.ToString(nlbPort), 10, 16) if err != nil { return nil, err } targetPort := uint16(port) if cfg.TargetPort != nil { - targetPort = uint16(aws.IntValue(cfg.TargetPort)) + targetPort = uint16(aws.ToInt(cfg.TargetPort)) } targetProtocol := TCP if nlbProtocol != nil { // Expose TCP port for TLS listeners. - if protocol := aws.StringValue(nlbProtocol); !strings.EqualFold(protocol, TLS) { + if protocol := aws.ToString(nlbProtocol); !strings.EqualFold(protocol, TLS) { targetProtocol = protocol } } @@ -565,7 +565,7 @@ func (cfg NetworkLoadBalancerListener) exposePorts(exposedPorts map[uint16]Expos } targetContainer := workloadName if cfg.TargetContainer != nil { - targetContainer = aws.StringValue(cfg.TargetContainer) + targetContainer = aws.ToString(cfg.TargetContainer) } newExposedPorts := make(map[uint16]ExposedPort) @@ -586,11 +586,11 @@ func (sidecar SidecarConfig) exposePorts(exposedPorts map[uint16]ExposedPort, si if err != nil { return nil, err } - protocol := aws.StringValue(protocolPtr) + protocol := aws.ToString(protocolPtr) if protocolPtr == nil { protocol = "tcp" } - port, err := strconv.ParseUint(aws.StringValue(sidecarPort), 10, 16) + port, err := strconv.ParseUint(aws.ToString(sidecarPort), 10, 16) if err != nil { return nil, err } @@ -625,8 +625,8 @@ func (l *LoadBalancedWebService) ServiceConnectTarget(exposedPorts ExposedPortsI albContainer, albPort = l.HTTPOrBool.Main.exposedContainerAndPort(exposedPorts) } if albContainer != nil && albPort != nil { - targetContainer = aws.StringValue(albContainer) - targetPort = aws.StringValue(albPort) + targetContainer = aws.ToString(albContainer) + targetPort = aws.ToString(albPort) targetProtocol = TCP } @@ -650,8 +650,8 @@ func (b *BackendService) ServiceConnectTarget(exposedPorts ExposedPortsIndex) *S albContainer, albPort := b.HTTP.Main.exposedContainerAndPort(exposedPorts) if albContainer != nil && albPort != nil { - targetContainer = aws.StringValue(albContainer) - targetPort = aws.StringValue(albPort) + targetContainer = aws.ToString(albContainer) + targetPort = aws.ToString(albPort) targetProtocol = TCP } @@ -675,10 +675,10 @@ func (rule *RoutingRule) Target(exposedPorts ExposedPortsIndex) (targetContainer ruleTargetContainer, ruleTargetPort := rule.exposedContainerAndPort(exposedPorts) if ruleTargetContainer != nil { - targetContainer = aws.StringValue(ruleTargetContainer) + targetContainer = aws.ToString(ruleTargetContainer) } if ruleTargetPort != nil { - targetPort = aws.StringValue(ruleTargetPort) + targetPort = aws.ToString(ruleTargetPort) } return } @@ -692,9 +692,9 @@ func (rule *RoutingRule) exposedContainerAndPort(exposedPorts ExposedPortsIndex) } if rule.TargetPort == nil { // when target_port is nil - if aws.StringValue(rule.TargetContainer) != exposedPorts.WorkloadName { + if aws.ToString(rule.TargetContainer) != exposedPorts.WorkloadName { targetContainer = rule.TargetContainer - targetPort = aws.String(exposedPorts.containerPortDefinedBy(aws.StringValue(rule.TargetContainer))) + targetPort = aws.String(exposedPorts.containerPortDefinedBy(aws.ToString(rule.TargetContainer))) /* NOTE: When the `target_port` is empty, the intended target port should be the port that is explicitly exposed by the container. Consider the following example ``` http: @@ -721,31 +721,31 @@ func (rule *RoutingRule) exposedContainerAndPort(exposedPorts ExposedPortsIndex) // when both target_port and target_container are not nil targetContainer = rule.TargetContainer - targetPort = aws.String(template.StrconvUint16(aws.Uint16Value(rule.TargetPort))) + targetPort = aws.String(template.StrconvUint16(aws.ToUint16(rule.TargetPort))) return targetContainer, targetPort } // targetContainerFromTargetPort returns target container and target port from the given target_port input. func targetContainerFromTargetPort(exposedPorts ExposedPortsIndex, port *uint16) (targetContainer *string, targetPort *string) { // Route load balancer traffic to the target_port if mentioned. - targetPort = aws.String(template.StrconvUint16(aws.Uint16Value(port))) + targetPort = aws.String(template.StrconvUint16(aws.ToUint16(port))) // It shouldn’t be possible that container is empty for the given port as exposed port assigns container to all the ports, this is just for the extra safety. - if exposedPorts.ContainerForPort[aws.Uint16Value(port)] != "" { - targetContainer = aws.String(exposedPorts.ContainerForPort[aws.Uint16Value(port)]) + if exposedPorts.ContainerForPort[aws.ToUint16(port)] != "" { + targetContainer = aws.String(exposedPorts.ContainerForPort[aws.ToUint16(port)]) } return } // MainContainerPort returns the main container port. func (s *LoadBalancedWebService) MainContainerPort() string { - return strconv.FormatUint(uint64(aws.Uint16Value(s.ImageConfig.Port)), 10) + return strconv.FormatUint(uint64(aws.ToUint16(s.ImageConfig.Port)), 10) } // MainContainerPort returns the main container port if given. func (s *BackendService) MainContainerPort() string { port := template.NoExposedContainerPort if s.BackendServiceConfig.ImageConfig.Port != nil { - port = strconv.FormatUint(uint64(aws.Uint16Value(s.BackendServiceConfig.ImageConfig.Port)), 10) + port = strconv.FormatUint(uint64(aws.ToUint16(s.BackendServiceConfig.ImageConfig.Port)), 10) } return port } @@ -777,15 +777,15 @@ func (listener NetworkLoadBalancerListener) Target(exposedPorts ExposedPortsInde return "", "", err } // By default, the target port is the same as listener port. - targetPort = aws.StringValue(port) + targetPort = aws.ToString(port) targetContainer = exposedPorts.WorkloadName if listener.TargetContainer == nil && listener.TargetPort == nil { // both targetPort and targetContainer are nil. return } if listener.TargetPort == nil { // when target_port is nil - if aws.StringValue(listener.TargetContainer) != exposedPorts.WorkloadName { - targetContainer = aws.StringValue(listener.TargetContainer) + if aws.ToString(listener.TargetContainer) != exposedPorts.WorkloadName { + targetContainer = aws.ToString(listener.TargetContainer) for _, portConfig := range exposedPorts.PortsForContainer[targetContainer] { if portConfig.isDefinedByContainer { targetPort = strconv.Itoa(int(portConfig.Port)) @@ -810,17 +810,17 @@ func (listener NetworkLoadBalancerListener) Target(exposedPorts ExposedPortsInde } if listener.TargetContainer == nil { // when target_container is nil - container, port := targetContainerFromTargetPort(exposedPorts, uint16P(uint16(aws.IntValue(listener.TargetPort)))) - targetPort = aws.StringValue(port) + container, port := targetContainerFromTargetPort(exposedPorts, uint16P(uint16(aws.ToInt(listener.TargetPort)))) + targetPort = aws.ToString(port) // In general, containers aren't expected to be empty. But this condition is applied for extra safety. if container != nil { - targetContainer = aws.StringValue(container) + targetContainer = aws.ToString(container) } return } // when both target_port and target_container are not nil - targetContainer = aws.StringValue(listener.TargetContainer) - targetPort = template.StrconvUint16(uint16(aws.IntValue(listener.TargetPort))) + targetContainer = aws.ToString(listener.TargetContainer) + targetPort = template.StrconvUint16(uint16(aws.ToInt(listener.TargetPort))) return } diff --git a/internal/pkg/manifest/svc_test.go b/internal/pkg/manifest/svc_test.go index 3e12874783a..665b5f10deb 100644 --- a/internal/pkg/manifest/svc_test.go +++ b/internal/pkg/manifest/svc_test.go @@ -10,7 +10,7 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/transform_test.go b/internal/pkg/manifest/transform_test.go index ecb6051d3f8..04e095288c9 100644 --- a/internal/pkg/manifest/transform_test.go +++ b/internal/pkg/manifest/transform_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" "github.com/stretchr/testify/require" diff --git a/internal/pkg/manifest/union_test.go b/internal/pkg/manifest/union_test.go index c870c2b5545..b878064e856 100644 --- a/internal/pkg/manifest/union_test.go +++ b/internal/pkg/manifest/union_test.go @@ -8,7 +8,7 @@ import ( "strings" "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/validate.go b/internal/pkg/manifest/validate.go index ff2651a5c56..093e68654fe 100644 --- a/internal/pkg/manifest/validate.go +++ b/internal/pkg/manifest/validate.go @@ -18,8 +18,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/graph" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/term/color" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/dustin/go-humanize/english" ) @@ -100,7 +100,7 @@ func (l LoadBalancedWebService) validate() error { return err } if err = validateTargetContainer(validateTargetContainerOpts{ - mainContainerName: aws.StringValue(l.Name), + mainContainerName: aws.ToString(l.Name), mainContainerPort: l.ImageConfig.Port, targetContainer: l.HTTPOrBool.Main.TargetContainer, sidecarConfig: l.Sidecars, @@ -109,7 +109,7 @@ func (l LoadBalancedWebService) validate() error { } for idx, rule := range l.HTTPOrBool.AdditionalRoutingRules { if err = validateTargetContainer(validateTargetContainerOpts{ - mainContainerName: aws.StringValue(l.Name), + mainContainerName: aws.ToString(l.Name), mainContainerPort: l.ImageConfig.Port, targetContainer: rule.TargetContainer, sidecarConfig: l.Sidecars, @@ -118,7 +118,7 @@ func (l LoadBalancedWebService) validate() error { } } if err = validateTargetContainer(validateTargetContainerOpts{ - mainContainerName: aws.StringValue(l.Name), + mainContainerName: aws.ToString(l.Name), mainContainerPort: l.ImageConfig.Port, targetContainer: l.NLBConfig.Listener.TargetContainer, sidecarConfig: l.Sidecars, @@ -127,7 +127,7 @@ func (l LoadBalancedWebService) validate() error { } for idx, listener := range l.NLBConfig.AdditionalListeners { if err = validateTargetContainer(validateTargetContainerOpts{ - mainContainerName: aws.StringValue(l.Name), + mainContainerName: aws.ToString(l.Name), mainContainerPort: l.ImageConfig.Port, targetContainer: listener.TargetContainer, sidecarConfig: l.Sidecars, @@ -138,13 +138,13 @@ func (l LoadBalancedWebService) validate() error { if err = validateContainerDeps(validateDependenciesOpts{ sidecarConfig: l.Sidecars, imageConfig: l.ImageConfig.Image, - mainContainerName: aws.StringValue(l.Name), + mainContainerName: aws.ToString(l.Name), logging: l.Logging, }); err != nil { return fmt.Errorf("validate container dependencies: %w", err) } if err = validateExposedPorts(validateExposedPortsOpts{ - mainContainerName: aws.StringValue(l.Name), + mainContainerName: aws.ToString(l.Name), mainContainerPort: l.ImageConfig.Port, sidecarConfig: l.Sidecars, alb: &l.HTTPOrBool.HTTP, @@ -196,12 +196,12 @@ func (w WorkerDeploymentConfig) validate() error { func (d DeploymentControllerConfig) validate() error { if d.Rolling != nil { for _, validStrategy := range ecsRollingUpdateStrategies { - if strings.EqualFold(aws.StringValue(d.Rolling), validStrategy) { + if strings.EqualFold(aws.ToString(d.Rolling), validStrategy) { return nil } } return fmt.Errorf("invalid rolling deployment strategy %q, must be one of %s", - aws.StringValue(d.Rolling), + aws.ToString(d.Rolling), english.WordSeries(ecsRollingUpdateStrategies, "or")) } return nil @@ -298,7 +298,7 @@ func (b BackendService) validate() error { return err } if err = validateTargetContainer(validateTargetContainerOpts{ - mainContainerName: aws.StringValue(b.Name), + mainContainerName: aws.ToString(b.Name), mainContainerPort: b.ImageConfig.Port, targetContainer: b.HTTP.Main.TargetContainer, sidecarConfig: b.Sidecars, @@ -307,7 +307,7 @@ func (b BackendService) validate() error { } for idx, rule := range b.HTTP.AdditionalRoutingRules { if err = validateTargetContainer(validateTargetContainerOpts{ - mainContainerName: aws.StringValue(b.Name), + mainContainerName: aws.ToString(b.Name), mainContainerPort: b.ImageConfig.Port, targetContainer: rule.TargetContainer, sidecarConfig: b.Sidecars, @@ -318,13 +318,13 @@ func (b BackendService) validate() error { if err = validateContainerDeps(validateDependenciesOpts{ sidecarConfig: b.Sidecars, imageConfig: b.ImageConfig.Image, - mainContainerName: aws.StringValue(b.Name), + mainContainerName: aws.ToString(b.Name), logging: b.Logging, }); err != nil { return fmt.Errorf("validate container dependencies: %w", err) } if err = validateExposedPorts(validateExposedPortsOpts{ - mainContainerName: aws.StringValue(b.Name), + mainContainerName: aws.ToString(b.Name), mainContainerPort: b.ImageConfig.Port, sidecarConfig: b.Sidecars, alb: &b.HTTP, @@ -453,7 +453,7 @@ func (w WorkerService) validate() error { if err = validateContainerDeps(validateDependenciesOpts{ sidecarConfig: w.Sidecars, imageConfig: w.ImageConfig.Image, - mainContainerName: aws.StringValue(w.Name), + mainContainerName: aws.ToString(w.Name), logging: w.Logging, }); err != nil { return fmt.Errorf("validate container dependencies: %w", err) @@ -529,7 +529,7 @@ func (s ScheduledJob) validate() error { if err = validateContainerDeps(validateDependenciesOpts{ sidecarConfig: s.Sidecars, imageConfig: s.ImageConfig.Image, - mainContainerName: aws.StringValue(s.Name), + mainContainerName: aws.ToString(s.Name), logging: s.Logging, }); err != nil { return fmt.Errorf("validate container dependencies: %w", err) @@ -1050,7 +1050,7 @@ func (c NetworkLoadBalancerConfiguration) validate() error { } func (c NetworkLoadBalancerListener) validate() error { - if aws.StringValue(c.Port) == "" { + if aws.ToString(c.Port) == "" { return &errFieldMustBeSpecified{ missingField: "port", } @@ -1072,7 +1072,7 @@ func validateNLBPort(port *string) error { if protocol == nil { return nil } - protocolVal := aws.StringValue(protocol) + protocolVal := aws.ToString(protocol) var isValidProtocol bool for _, valid := range nlbValidProtocols { if strings.EqualFold(protocolVal, valid) { @@ -1112,7 +1112,7 @@ func (t TaskConfig) validate() error { } } if t.EnvFile != nil { - envFile := aws.StringValue(t.EnvFile) + envFile := aws.ToString(t.EnvFile) if filepath.Ext(envFile) != envFileExt { return fmt.Errorf("environment file %s must have a %s file extension", envFile, envFileExt) } @@ -1145,10 +1145,10 @@ func (p PlatformArgs) validate() error { } prettyValidPlatforms := strings.Join(ss, ", ") - os := strings.ToLower(aws.StringValue(p.OSFamily)) - arch := strings.ToLower(aws.StringValue(p.Arch)) + os := strings.ToLower(aws.ToString(p.OSFamily)) + arch := strings.ToLower(aws.ToString(p.Arch)) for _, vap := range validAdvancedPlatforms { - if os == aws.StringValue(vap.OSFamily) && arch == aws.StringValue(vap.Arch) { + if os == aws.ToString(vap.OSFamily) && arch == aws.ToString(vap.Arch) { return nil } } @@ -1367,7 +1367,7 @@ func (r RangeConfig) validate() error { missingField: "min/max", } } - min, max, spotFrom := aws.IntValue(r.Min), aws.IntValue(r.Max), aws.IntValue(r.SpotFrom) + min, max, spotFrom := aws.ToInt(r.Min), aws.ToInt(r.Max), aws.ToInt(r.SpotFrom) if min < 0 || max < 0 || spotFrom < 0 { return &errRangeValueLessThanZero{ min: min, @@ -1403,7 +1403,7 @@ func (s Storage) validate() error { return nil } if s.Ephemeral != nil { - ephemeral := aws.IntValue(s.Ephemeral) + ephemeral := aws.ToInt(s.Ephemeral) if ephemeral < ephemeralMinValueGiB || ephemeral > ephemeralMaxValueGiB { return fmt.Errorf(`validate "ephemeral": ephemeral storage must be between 20 GiB and 200 GiB`) } @@ -1433,7 +1433,7 @@ func (v Volume) validate() error { // validate returns nil if MountPointOpts is configured correctly. func (m MountPointOpts) validate() error { - path := aws.StringValue(m.ContainerPath) + path := aws.ToString(m.ContainerPath) if path == "" { return &errFieldMustBeSpecified{ missingField: "path", @@ -1483,14 +1483,14 @@ func (e EFSVolumeConfiguration) validate() error { return fmt.Errorf(`validate "auth": %w`, err) } if e.AuthConfig.AccessPointID != nil { - if (aws.StringValue(e.RootDirectory) == "" || aws.StringValue(e.RootDirectory) == "/") && - (e.AuthConfig.IAM == nil || aws.BoolValue(e.AuthConfig.IAM)) { + if (aws.ToString(e.RootDirectory) == "" || aws.ToString(e.RootDirectory) == "/") && + (e.AuthConfig.IAM == nil || aws.ToBool(e.AuthConfig.IAM)) { return nil } return fmt.Errorf(`"root_dir" must be either empty or "/" and "auth.iam" must be true when "access_point_id" is used`) } if e.RootDirectory != nil { - if err := validateVolumePath(aws.StringValue(e.RootDirectory)); err != nil { + if err := validateVolumePath(aws.ToString(e.RootDirectory)); err != nil { return fmt.Errorf(`validate "root_dir": %w`, err) } } @@ -1511,7 +1511,7 @@ func (l Logging) validate() error { return nil } if l.EnvFile != nil { - envFile := aws.StringValue(l.EnvFile) + envFile := aws.ToString(l.EnvFile) if filepath.Ext(envFile) != envFileExt { return fmt.Errorf("environment file %s must have a %s file extension", envFile, envFileExt) } @@ -1534,7 +1534,7 @@ func (s SidecarConfig) validate() error { return err } if protocol != nil { - protocolVal := aws.StringValue(protocol) + protocolVal := aws.ToString(protocol) var isValidProtocol bool for _, valid := range validContainerProtocols { if strings.EqualFold(protocolVal, valid) { @@ -1553,7 +1553,7 @@ func (s SidecarConfig) validate() error { return fmt.Errorf(`validate "depends_on": %w`, err) } if s.EnvFile != nil { - envFile := aws.StringValue(s.EnvFile) + envFile := aws.ToString(s.EnvFile) if filepath.Ext(envFile) != envFileExt { return fmt.Errorf("environment file %s must have a %s file extension", envFile, envFileExt) } @@ -1572,7 +1572,7 @@ func (s SidecarConfig) validateImage() error { // validate returns nil if SidecarMountPoint is configured correctly. func (s SidecarMountPoint) validate() error { - if aws.StringValue(s.SourceVolume) == "" { + if aws.ToString(s.SourceVolume) == "" { return &errFieldMustBeSpecified{ missingField: "source_volume", } @@ -1739,12 +1739,12 @@ func (o Observability) validate() error { return nil } for _, validVendor := range tracingValidVendors { - if strings.EqualFold(aws.StringValue(o.Tracing), validVendor) { + if strings.EqualFold(aws.ToString(o.Tracing), validVendor) { return nil } } return fmt.Errorf("invalid tracing vendor %s: %s %s", - aws.StringValue(o.Tracing), + aws.ToString(o.Tracing), english.PluralWord(len(tracingValidVendors), "the valid vendor is", "valid vendors are"), english.WordSeries(tracingValidVendors, "and")) } @@ -1776,7 +1776,7 @@ func (p PublishConfig) validate() error { // validate returns nil if Topic is configured correctly. func (t Topic) validate() error { - if err := validatePubSubName(aws.StringValue(t.Name)); err != nil { + if err := validatePubSubName(aws.ToString(t.Name)); err != nil { return err } return t.FIFO.validate() @@ -1813,10 +1813,10 @@ func (s SubscribeConfig) validate() error { // validate returns nil if TopicSubscription is configured correctly. func (t TopicSubscription) validate() error { - if err := validatePubSubName(aws.StringValue(t.Name)); err != nil { + if err := validatePubSubName(aws.ToString(t.Name)); err != nil { return err } - svcName := aws.StringValue(t.Service) + svcName := aws.ToString(t.Service) if svcName == "" { return &errFieldMustBeSpecified{ missingField: "service", @@ -1865,7 +1865,7 @@ func (q FIFOAdvanceConfig) validate() error { if err := q.validateFIFOThroughputLimit(); err != nil { return err } - if aws.StringValue(q.FIFOThroughputLimit) == sqsFIFOThroughputLimitPerMessageGroupID && aws.StringValue(q.DeduplicationScope) == sqsDeduplicationScopeQueue { + if aws.ToString(q.FIFOThroughputLimit) == sqsFIFOThroughputLimitPerMessageGroupID && aws.ToString(q.DeduplicationScope) == sqsDeduplicationScopeQueue { return fmt.Errorf(`"throughput_limit" must be set to "perQueue" when "deduplication_scope" is set to "queue"`) } return nil @@ -1902,14 +1902,14 @@ func (q FIFOAdvanceConfig) validateHighThroughputFIFO() error { } func (q FIFOAdvanceConfig) validateDeduplicationScope() error { - if q.DeduplicationScope != nil && !slices.Contains(validSQSDeduplicationScopeValues, aws.StringValue(q.DeduplicationScope)) { + if q.DeduplicationScope != nil && !slices.Contains(validSQSDeduplicationScopeValues, aws.ToString(q.DeduplicationScope)) { return fmt.Errorf(`validate "deduplication_scope": deduplication scope value must be one of %s`, english.WordSeries(validSQSDeduplicationScopeValues, "or")) } return nil } func (q FIFOAdvanceConfig) validateFIFOThroughputLimit() error { - if q.FIFOThroughputLimit != nil && !slices.Contains(validSQSFIFOThroughputLimitValues, aws.StringValue(q.FIFOThroughputLimit)) { + if q.FIFOThroughputLimit != nil && !slices.Contains(validSQSFIFOThroughputLimitValues, aws.ToString(q.FIFOThroughputLimit)) { return fmt.Errorf(`validate "throughput_limit": fifo throughput limit value must be one of %s`, english.WordSeries(validSQSFIFOThroughputLimitValues, "or")) } return nil @@ -1955,7 +1955,7 @@ func (cfg fromCFN) validate() error { if cfg.isEmpty() { return nil } - if len(aws.StringValue(cfg.Name)) == 0 { + if len(aws.ToString(cfg.Name)) == 0 { return errors.New("name cannot be an empty string") } return nil @@ -2043,7 +2043,7 @@ func validateTargetContainer(opts validateTargetContainerOpts) error { if opts.targetContainer == nil { return nil } - targetContainer := aws.StringValue(opts.targetContainer) + targetContainer := aws.ToString(opts.targetContainer) if targetContainer == opts.mainContainerName { if opts.mainContainerPort == nil { return fmt.Errorf("target container %q doesn't expose a port", targetContainer) @@ -2110,7 +2110,7 @@ func validateAndPopulateMainContainerPort(portExposedTo map[uint16]containerName return nil } - targetPort := aws.Uint16Value(opts.mainContainerPort) + targetPort := aws.ToUint16(opts.mainContainerPort) targetProtocol := defaultProtocol if existingContainerNameAndProtocol, ok := portExposedTo[targetPort]; ok { targetProtocol = existingContainerNameAndProtocol.containerProtocol @@ -2128,13 +2128,13 @@ func validateAndPopulateSidecarContainerPorts(portExposedTo map[uint16]container if err != nil { return err } - parsedPort, err := strconv.ParseUint(aws.StringValue(sidecarPort), 10, 16) + parsedPort, err := strconv.ParseUint(aws.ToString(sidecarPort), 10, 16) if err != nil { return err } protocol := defaultProtocol if sidecarProtocol != nil { - protocol = aws.StringValue(sidecarProtocol) + protocol = aws.ToString(sidecarProtocol) } if err = validateAndPopulateExposedPortMapping(portExposedTo, uint16(parsedPort), protocol, name); err != nil { @@ -2154,7 +2154,7 @@ func validateAndPopulateALBPorts(portExposedTo map[uint16]containerNameAndProtoc if rule.TargetPort == nil { continue } - targetPort := aws.Uint16Value(rule.TargetPort) + targetPort := aws.ToUint16(rule.TargetPort) // Prefer `http.target_container`, then existing exposed port mapping, then fallback on name of main container targetContainer := opts.mainContainerName @@ -2162,7 +2162,7 @@ func validateAndPopulateALBPorts(portExposedTo map[uint16]containerNameAndProtoc targetContainer = existingContainerNameAndProtocol.containerName } if rule.TargetContainer != nil { - targetContainer = aws.StringValue(rule.TargetContainer) + targetContainer = aws.ToString(rule.TargetContainer) } if err := validateAndPopulateExposedPortMapping(portExposedTo, targetPort, TCP, targetContainer); err != nil { @@ -2196,20 +2196,20 @@ func validateAndPopulateNLBListenerPorts(listener NetworkLoadBalancerListener, p return err } - port, err := strconv.ParseUint(aws.StringValue(nlbReceiverPort), 10, 16) + port, err := strconv.ParseUint(aws.ToString(nlbReceiverPort), 10, 16) if err != nil { return err } targetPort := uint16(port) if listener.TargetPort != nil { - targetPort = uint16(aws.IntValue(listener.TargetPort)) + targetPort = uint16(aws.ToInt(listener.TargetPort)) } // Prefer `nlb.port`, then fallback on default protocol targetProtocol := defaultProtocol if nlbProtocol != nil { - targetProtocol = strings.ToUpper(aws.StringValue(nlbProtocol)) + targetProtocol = strings.ToUpper(aws.ToString(nlbProtocol)) } // Handle TLS termination of container exposed port protocol @@ -2223,7 +2223,7 @@ func validateAndPopulateNLBListenerPorts(listener NetworkLoadBalancerListener, p targetContainer = existingContainerNameAndProtocol.containerName } if listener.TargetContainer != nil { - targetContainer = aws.StringValue(listener.TargetContainer) + targetContainer = aws.ToString(listener.TargetContainer) } return validateAndPopulateExposedPortMapping(portExposedTo, targetPort, targetProtocol, targetContainer) @@ -2346,7 +2346,7 @@ func isValidSubSvcName(name string) bool { } func validateWindows(opts validateWindowsOpts) error { - if aws.BoolValue(opts.readOnlyFS) { + if aws.ToBool(opts.readOnlyFS) { return fmt.Errorf(`%q can not be set to 'true' when deploying a Windows container`, "readonly_fs") } for _, volume := range opts.efsVolumes { @@ -2383,7 +2383,7 @@ func (r *RoutingRule) validateConditionValuesPerRule() error { } if len(aliases)+len(allowedSourceIps) >= maxConditionsPerRule { return &errMaxConditionValuesPerRule{ - path: aws.StringValue(r.Path), + path: aws.ToString(r.Path), aliases: aliases, allowedSourceIps: allowedSourceIps, } diff --git a/internal/pkg/manifest/validate_env.go b/internal/pkg/manifest/validate_env.go index 454937aa95c..4537b7accc8 100644 --- a/internal/pkg/manifest/validate_env.go +++ b/internal/pkg/manifest/validate_env.go @@ -8,8 +8,8 @@ import ( "fmt" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudfront" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" ) var ( @@ -49,7 +49,7 @@ func (e EnvironmentConfig) validate() error { if e.CDNEnabled() { cdnCert := e.CDNConfig.Config.Certificate if e.HTTPConfig.Public.Certificates == nil { - if cdnCert != nil && !aws.BoolValue(e.CDNConfig.Config.TerminateTLS) { + if cdnCert != nil && !aws.ToBool(e.CDNConfig.Config.TerminateTLS) { return errors.New(`"cdn.terminate_tls" must be true if "cdn.certificate" is set without "http.public.certificates"`) } } else { @@ -135,7 +135,7 @@ func (cfg portsConfig) validate() error { var targetErr *errInvalidRange if errors.As(err, &targetErr) { return &errInvalidRange{ - value: aws.StringValue((*string)(cfg.Range)), + value: aws.ToString((*string)(cfg.Range)), validFormat: "${from_port}-${to_port}", } } @@ -161,14 +161,14 @@ func (cfg securityGroupConfig) validate() error { func (cfg environmentVPCConfig) validateImportedVPC() error { for idx, subnet := range cfg.Subnets.Public { - if aws.StringValue(subnet.SubnetID) == "" { + if aws.ToString(subnet.SubnetID) == "" { return fmt.Errorf(`validate public[%d]: %w`, idx, &errFieldMustBeSpecified{ missingField: "id", }) } } for idx, subnet := range cfg.Subnets.Private { - if aws.StringValue(subnet.SubnetID) == "" { + if aws.ToString(subnet.SubnetID) == "" { return fmt.Errorf(`validate private[%d]: %w`, idx, &errFieldMustBeSpecified{ missingField: "id", }) @@ -194,25 +194,25 @@ func (cfg environmentVPCConfig) validateManagedVPC() error { ) var exists = struct{}{} for idx, subnet := range cfg.Subnets.Public { - if aws.StringValue((*string)(subnet.CIDR)) == "" { + if aws.ToString((*string)(subnet.CIDR)) == "" { return fmt.Errorf(`validate public[%d]: %w`, idx, &errFieldMustBeSpecified{ missingField: "cidr", }) } - publicCIDRs[aws.StringValue((*string)(subnet.CIDR))] = exists - if aws.StringValue(subnet.AZ) != "" { - publicAZs[aws.StringValue(subnet.AZ)] = exists + publicCIDRs[aws.ToString((*string)(subnet.CIDR))] = exists + if aws.ToString(subnet.AZ) != "" { + publicAZs[aws.ToString(subnet.AZ)] = exists } } for idx, subnet := range cfg.Subnets.Private { - if aws.StringValue((*string)(subnet.CIDR)) == "" { + if aws.ToString((*string)(subnet.CIDR)) == "" { return fmt.Errorf(`validate private[%d]: %w`, idx, &errFieldMustBeSpecified{ missingField: "cidr", }) } - privateCIDRs[aws.StringValue((*string)(subnet.CIDR))] = exists - if aws.StringValue(subnet.AZ) != "" { - privateAZs[aws.StringValue(subnet.AZ)] = exists + privateCIDRs[aws.ToString((*string)(subnet.CIDR))] = exists + if aws.ToString(subnet.AZ) != "" { + privateAZs[aws.ToString(subnet.AZ)] = exists } } // NOTE: the following are constraints on az: @@ -433,7 +433,7 @@ func (c EnvironmentConfig) validateInternalALBSubnets() error { isImported := make(map[string]bool) for _, placementSubnet := range c.HTTPConfig.Private.InternalALBSubnets { for _, subnet := range append(c.Network.VPC.Subnets.Private, c.Network.VPC.Subnets.Public...) { - if placementSubnet == aws.StringValue(subnet.SubnetID) { + if placementSubnet == aws.ToString(subnet.SubnetID) { isImported[placementSubnet] = true } } diff --git a/internal/pkg/manifest/validate_env_test.go b/internal/pkg/manifest/validate_env_test.go index 05ba94c8bf4..2b94592d4de 100644 --- a/internal/pkg/manifest/validate_env_test.go +++ b/internal/pkg/manifest/validate_env_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/validate_test.go b/internal/pkg/manifest/validate_test.go index c19b9d3c7c5..6f345ce2e2d 100644 --- a/internal/pkg/manifest/validate_test.go +++ b/internal/pkg/manifest/validate_test.go @@ -10,7 +10,7 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/manifest/worker_svc.go b/internal/pkg/manifest/worker_svc.go index 14683de6121..b0ccae44deb 100644 --- a/internal/pkg/manifest/worker_svc.go +++ b/internal/pkg/manifest/worker_svc.go @@ -11,7 +11,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/imdario/mergo" "gopkg.in/yaml.v3" ) @@ -138,7 +138,7 @@ func (f *FIFOAdvanceConfigOrBool) IsEmpty() bool { // IsEnabled returns true if the FifoAdvanceConfigOrBool struct has all nil values. func (f *FIFOAdvanceConfigOrBool) IsEnabled() bool { - return aws.BoolValue(f.Enable) || !f.Advanced.IsEmpty() + return aws.ToBool(f.Enable) || !f.Advanced.IsEmpty() } // FIFOAdvanceConfig represents the advanced fifo queue config. @@ -242,7 +242,7 @@ func NewWorkerService(props WorkerServiceProps) *WorkerService { func setSubscriptionQueueDefaults(topics []TopicSubscription, eventsQueue *SQSQueue) { var isFIFOEnabled bool for _, topic := range topics { - if isFIFO(aws.StringValue(topic.Name)) { + if isFIFO(aws.ToString(topic.Name)) { isFIFOEnabled = true break } @@ -252,8 +252,8 @@ func setSubscriptionQueueDefaults(topics []TopicSubscription, eventsQueue *SQSQu } eventsQueue.FIFO.Enable = aws.Bool(true) for idx, topic := range topics { - if isFIFO(aws.StringValue(topic.Name)) { - topics[idx].Name = aws.String(strings.TrimSuffix(aws.StringValue(topic.Name), ".fifo")) + if isFIFO(aws.ToString(topic.Name)) { + topics[idx].Name = aws.String(strings.TrimSuffix(aws.ToString(topic.Name), ".fifo")) } else { topics[idx].Queue.Enabled = aws.Bool(true) } @@ -286,7 +286,7 @@ func (s *WorkerService) BuildArgs(contextDir string) (map[string]*DockerBuildArg // Creating an map to store buildArgs of all sidecar images and main container image. buildArgsPerContainer := make(map[string]*DockerBuildArgs, len(s.Sidecars)+1) if required { - buildArgsPerContainer[aws.StringValue(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) + buildArgsPerContainer[aws.ToString(s.Name)] = s.ImageConfig.Image.BuildConfig(contextDir) } return buildArgs(contextDir, buildArgsPerContainer, s.Sidecars) } @@ -301,7 +301,7 @@ func (s *WorkerService) EnvFiles() map[string]string { // ContainerDependencies returns a map of ContainerDependency objects for the WorkerService // including dependencies for its main container, any logging sidecar, and additional sidecars. func (s *WorkerService) ContainerDependencies() map[string]ContainerDependency { - return containerDependencies(aws.StringValue(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) + return containerDependencies(aws.ToString(s.Name), s.ImageConfig.Image, s.Logging, s.Sidecars) } // Subscriptions returns a list of TopicSubscriotion objects which represent the SNS topics the service @@ -312,9 +312,9 @@ func (s *WorkerService) Subscriptions() []TopicSubscription { topicSubscription := topic // if condition appends .fifo suffix to the topic which doesn't have topic specific queue and subscribing to default FIFO queue. if topic.Queue.IsEmpty() && !s.Subscribe.Queue.IsEmpty() && s.Subscribe.Queue.FIFO.IsEnabled() { - topicSubscription.Name = aws.String(aws.StringValue(topic.Name) + ".fifo") + topicSubscription.Name = aws.String(aws.ToString(topic.Name) + ".fifo") } else if !topic.Queue.IsEmpty() && !topic.Queue.Advanced.IsEmpty() && topic.Queue.Advanced.FIFO.IsEnabled() { // else if condition appends .fifo suffix to the topic which has topic specific FIFO queue configuration. - topicSubscription.Name = aws.String(aws.StringValue(topic.Name) + ".fifo") + topicSubscription.Name = aws.String(aws.ToString(topic.Name) + ".fifo") } subs = append(subs, topicSubscription) } diff --git a/internal/pkg/manifest/worker_svc_test.go b/internal/pkg/manifest/worker_svc_test.go index e36cc8269c9..1f669778d2e 100644 --- a/internal/pkg/manifest/worker_svc_test.go +++ b/internal/pkg/manifest/worker_svc_test.go @@ -9,7 +9,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/workload.go b/internal/pkg/manifest/workload.go index c5d2343be5b..e157161e43d 100644 --- a/internal/pkg/manifest/workload.go +++ b/internal/pkg/manifest/workload.go @@ -13,11 +13,10 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws/session" "github.com/google/shlex" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -68,7 +67,7 @@ type DynamicWorkload interface { ApplyEnv(envName string) (DynamicWorkload, error) Validate() error RequiredEnvironmentFeatures() []string - Load(sess *session.Session) error + Load(cfg aws.Config) error Manifest() any } @@ -87,7 +86,7 @@ func UnmarshalWorkload(in []byte) (DynamicWorkload, error) { if err := yaml.Unmarshal(in, &am); err != nil { return nil, fmt.Errorf("unmarshal to workload manifest: %w", err) } - typeVal := aws.StringValue(am.Type) + typeVal := aws.ToString(am.Type) var m workloadManifest switch typeVal { case manifestinfo.LoadBalancedWebServiceType: @@ -162,7 +161,7 @@ func (i *Image) UnmarshalYAML(value *yaml.Node) error { // GetLocation returns the location of the image. func (i Image) GetLocation() string { - return aws.StringValue(i.Location) + return aws.ToString(i.Location) } // BuildConfig populates a docker.BuildArguments struct from the fields available in the manifest. @@ -205,12 +204,12 @@ func (i *ImageLocationOrBuild) dockerfile() string { // Prefer to use the "Dockerfile" string in BuildArgs. Otherwise, // "BuildString". If no dockerfile specified, return "". if i.Build.BuildArgs.Dockerfile != nil { - return aws.StringValue(i.Build.BuildArgs.Dockerfile) + return aws.ToString(i.Build.BuildArgs.Dockerfile) } var dfPath string if i.Build.BuildString != nil { - dfPath = aws.StringValue(i.Build.BuildString) + dfPath = aws.ToString(i.Build.BuildString) } return dfPath @@ -218,7 +217,7 @@ func (i *ImageLocationOrBuild) dockerfile() string { // context returns the build context directory if it exists, otherwise an empty string. func (i *ImageLocationOrBuild) context() string { - return aws.StringValue(i.Build.BuildArgs.Context) + return aws.ToString(i.Build.BuildArgs.Context) } // args returns the args section, if it exists, to override args in the dockerfile. @@ -360,7 +359,7 @@ type BuildArgsOrString struct { } func (b *BuildArgsOrString) isEmpty() bool { - if aws.StringValue(b.BuildString) == "" && b.BuildArgs.isEmpty() { + if aws.ToString(b.BuildString) == "" && b.BuildArgs.isEmpty() { return true } return false @@ -431,7 +430,7 @@ func (f *FIFOTopicAdvanceConfigOrBool) IsEmpty() bool { // IsEnabled returns true if the FIFO is enabled on the SQS queue. func (f *FIFOTopicAdvanceConfigOrBool) IsEnabled() bool { - return aws.BoolValue(f.Enable) || !f.Advanced.IsEmpty() + return aws.ToBool(f.Enable) || !f.Advanced.IsEmpty() } // FIFOTopicAdvanceConfig represents the advanced fifo topic config. @@ -475,7 +474,7 @@ func (c *NetworkConfig) IsEmpty() bool { } func (c *NetworkConfig) requiredEnvFeatures() []string { - if aws.StringValue((*string)(c.VPC.Placement.PlacementString)) == string(PrivateSubnetPlacement) { + if aws.ToString((*string)(c.VPC.Placement.PlacementString)) == string(PrivateSubnetPlacement) { return []string{template.NATFeatureName} } return nil @@ -489,7 +488,7 @@ type ServiceConnectBoolOrArgs struct { // Enabled returns if ServiceConnect is enabled or not. func (s *ServiceConnectBoolOrArgs) Enabled() bool { - return aws.BoolValue(s.EnableServiceConnect) || !s.ServiceConnectArgs.isEmpty() + return aws.ToBool(s.EnableServiceConnect) || !s.ServiceConnectArgs.isEmpty() } // UnmarshalYAML overrides the default YAML unmarshaling logic for the ServiceConnect @@ -696,7 +695,7 @@ func (s *SecurityGroupsIDsOrConfig) GetIDs() []StringOrFromCFN { // in SecurityGroupsIDsOrConfig.AdvancedConfig. Otherwise, false is returned. func (s *SecurityGroupsIDsOrConfig) IsDefaultSecurityGroupDenied() bool { if !s.AdvancedConfig.isEmpty() { - return aws.BoolValue(s.AdvancedConfig.DenyDefault) + return aws.ToBool(s.AdvancedConfig.DenyDefault) } return false } @@ -741,20 +740,20 @@ func (p *PlatformArgsOrString) UnmarshalYAML(value *yaml.Node) error { // OS returns the operating system family. func (p *PlatformArgsOrString) OS() string { - if p := aws.StringValue((*string)(p.PlatformString)); p != "" { + if p := aws.ToString((*string)(p.PlatformString)); p != "" { args := strings.Split(p, "/") return strings.ToLower(args[0]) } - return strings.ToLower(aws.StringValue(p.PlatformArgs.OSFamily)) + return strings.ToLower(aws.ToString(p.PlatformArgs.OSFamily)) } // Arch returns the architecture of PlatformArgsOrString. func (p *PlatformArgsOrString) Arch() string { - if p := aws.StringValue((*string)(p.PlatformString)); p != "" { + if p := aws.ToString((*string)(p.PlatformString)); p != "" { args := strings.Split(p, "/") return strings.ToLower(args[1]) } - return strings.ToLower(aws.StringValue(p.PlatformArgs.Arch)) + return strings.ToLower(aws.ToString(p.PlatformArgs.Arch)) } // PlatformArgs represents the specifics of a target OS. @@ -768,7 +767,7 @@ type PlatformString string // String implements the fmt.Stringer interface. func (p *PlatformArgs) String() string { - return fmt.Sprintf("('%s', '%s')", aws.StringValue(p.OSFamily), aws.StringValue(p.Arch)) + return fmt.Sprintf("('%s', '%s')", aws.ToString(p.OSFamily), aws.ToString(p.Arch)) } // IsEmpty returns if the platform field is empty. @@ -859,7 +858,7 @@ func (cfg PublishConfig) publishedTopics() []Topic { pubs := make([]Topic, len(cfg.Topics)) for i, topic := range cfg.Topics { if topic.FIFO.IsEnabled() { - topic.Name = aws.String(aws.StringValue(topic.Name) + ".fifo") + topic.Name = aws.String(aws.ToString(topic.Name) + ".fifo") } pubs[i] = topic } diff --git a/internal/pkg/manifest/workload_ecs.go b/internal/pkg/manifest/workload_ecs.go index 4514dedc457..4efefb861e0 100644 --- a/internal/pkg/manifest/workload_ecs.go +++ b/internal/pkg/manifest/workload_ecs.go @@ -10,7 +10,7 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "gopkg.in/yaml.v3" ) @@ -180,9 +180,9 @@ func (v *Variable) RequiresImport() bool { // Value returns the value, whether it is used for import or not. func (v *Variable) Value() string { if v.RequiresImport() { - return aws.StringValue(v.FromCFN.Name) + return aws.ToString(v.FromCFN.Name) } - return aws.StringValue(v.Plain) + return aws.ToString(v.Plain) } // ContainerPlatform returns the platform for the service. @@ -239,11 +239,11 @@ func (s *Secret) RequiresImport() bool { // Value returns the secret value provided by clients. func (s *Secret) Value() string { if !s.fromSecretsManager.IsEmpty() { - return aws.StringValue(s.fromSecretsManager.Name) + return aws.ToString(s.fromSecretsManager.Name) } else if s.RequiresImport() { - return aws.StringValue(s.from.FromCFN.Name) + return aws.ToString(s.from.FromCFN.Name) } - return aws.StringValue(s.from.Plain) + return aws.ToString(s.from.Plain) } // secretsManagerSecret represents the name of a secret stored in SecretsManager. @@ -312,10 +312,10 @@ type SidecarConfig struct { // If the image needs to be build, return "" and false. func (cfg *SidecarConfig) ImageURI() (string, bool) { if cfg.Image.Basic != nil { - return aws.StringValue(cfg.Image.Basic), true + return aws.ToString(cfg.Image.Basic), true } if cfg.Image.Advanced.Location != nil { - return aws.StringValue(cfg.Image.Advanced.Location), true + return aws.ToString(cfg.Image.Advanced.Location), true } return "", false } @@ -415,13 +415,13 @@ func (hc *ContainerHealthCheck) ApplyIfNotSet(other *ContainerHealthCheck) { func envFiles(name *string, tc TaskConfig, lc Logging, sc map[string]*SidecarConfig) map[string]string { envFiles := make(map[string]string) // Grab the workload container's env file, if present. - envFiles[aws.StringValue(name)] = aws.StringValue(tc.EnvFile) + envFiles[aws.ToString(name)] = aws.ToString(tc.EnvFile) // Grab sidecar env files, if present. for sidecarName, sidecar := range sc { - envFiles[sidecarName] = aws.StringValue(sidecar.EnvFile) + envFiles[sidecarName] = aws.ToString(sidecar.EnvFile) } // If the Firelens Sidecar Pattern has an env file specified, get it as well. - envFiles[FirelensContainerName] = aws.StringValue(lc.EnvFile) + envFiles[FirelensContainerName] = aws.ToString(lc.EnvFile) return envFiles } @@ -453,7 +453,7 @@ func containerDependencies(name string, img Image, lc Logging, sc map[string]*Si for name, config := range sc { containerDependencies[name] = ContainerDependency{ DependsOn: config.DependsOn, - IsEssential: config.Essential == nil || aws.BoolValue(config.Essential), + IsEssential: config.Essential == nil || aws.ToBool(config.Essential), } } return containerDependencies diff --git a/internal/pkg/manifest/workload_ecs_test.go b/internal/pkg/manifest/workload_ecs_test.go index 7187a624e3f..516ae76be66 100644 --- a/internal/pkg/manifest/workload_ecs_test.go +++ b/internal/pkg/manifest/workload_ecs_test.go @@ -7,7 +7,7 @@ import ( "errors" "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) diff --git a/internal/pkg/manifest/workload_test.go b/internal/pkg/manifest/workload_test.go index 02b27288bad..53108ca73b5 100644 --- a/internal/pkg/manifest/workload_test.go +++ b/internal/pkg/manifest/workload_test.go @@ -10,7 +10,7 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" ) @@ -39,7 +39,7 @@ location: mockLocation`), require.EqualError(t, err, tc.wantedError.Error()) } else { require.NoError(t, err) - require.Equal(t, "mockLocation", aws.StringValue(i.Location)) + require.Equal(t, "mockLocation", aws.ToString(i.Location)) } }) } diff --git a/internal/pkg/runner/jobrunner/jobrunner.go b/internal/pkg/runner/jobrunner/jobrunner.go index 3f94d8588da..473cf6fac40 100644 --- a/internal/pkg/runner/jobrunner/jobrunner.go +++ b/internal/pkg/runner/jobrunner/jobrunner.go @@ -9,7 +9,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation/stack" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) // StateMachineExecutor is the interface that implements the Execute method to invoke a state machine. @@ -65,8 +65,8 @@ func (job *JobRunner) Run() error { var arn string for _, resource := range resources { - if aws.StringValue(resource.ResourceType) == "AWS::StepFunctions::StateMachine" { - arn = aws.StringValue(resource.PhysicalResourceId) + if aws.ToString(resource.ResourceType) == "AWS::StepFunctions::StateMachine" { + arn = aws.ToString(resource.PhysicalResourceId) break } } diff --git a/internal/pkg/runner/jobrunner/jobrunner_test.go b/internal/pkg/runner/jobrunner/jobrunner_test.go index aa0f9e1310a..ce6c70796c0 100644 --- a/internal/pkg/runner/jobrunner/jobrunner_test.go +++ b/internal/pkg/runner/jobrunner/jobrunner_test.go @@ -10,7 +10,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/runner/jobrunner/mocks" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/s3/s3.go b/internal/pkg/s3/s3.go index 612e4fa10ae..c633a88889d 100644 --- a/internal/pkg/s3/s3.go +++ b/internal/pkg/s3/s3.go @@ -13,7 +13,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/s3" "github.com/aproint/copilot-cli/internal/pkg/deploy" awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws/session" ) const ( @@ -30,7 +29,7 @@ type Client struct { } // New inits a new Client. -func New(sess *session.Session, rgConfig awsv2.Config) *Client { +func New(rgConfig awsv2.Config) *Client { return &Client{ rgGetter: resourcegroups.New(rgConfig), } diff --git a/internal/pkg/stream/cfnstack.go b/internal/pkg/stream/cfnstack.go index c52e7d7de68..5948d4903aa 100644 --- a/internal/pkg/stream/cfnstack.go +++ b/internal/pkg/stream/cfnstack.go @@ -10,12 +10,10 @@ import ( "sync" "time" - awsarn "github.com/aws/aws-sdk-go/aws/arn" - cfn "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/cloudformation" + "github.com/aws/aws-sdk-go-v2/aws" + awsarn "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/cloudformation" ) // StackEventsDescriber is the CloudFormation interface needed to describe stack events. @@ -126,7 +124,7 @@ func (s *StackStreamer) Fetch() (next time.Time, done bool, err error) { }) if err != nil { // Check for throttles and wait to try again using the StackStreamer's interval. - if request.IsErrorThrottle(err) { + if isThrottleError(err) { s.retries += 1 return nextFetchDate(s.clock, s.rand, s.retries), false, nil } @@ -140,24 +138,28 @@ func (s *StackStreamer) Fetch() (next time.Time, done bool, err error) { finished = true break } - if _, seen := s.pastEventIDs[aws.StringValue(event.EventId)]; seen { + if _, seen := s.pastEventIDs[aws.ToString(event.EventId)]; seen { finished = true break } - logicalID, resourceStatus := aws.StringValue(event.LogicalResourceId), aws.StringValue(event.ResourceStatus) + logicalID, resourceStatus := aws.ToString(event.LogicalResourceId), string(event.ResourceStatus) if logicalID == s.stackName && !cfn.StackStatus(resourceStatus).InProgress() { done = true } + var eventTime time.Time + if event.Timestamp != nil { + eventTime = *event.Timestamp + } events = append(events, StackEvent{ LogicalResourceID: logicalID, - PhysicalResourceID: aws.StringValue(event.PhysicalResourceId), - ResourceType: aws.StringValue(event.ResourceType), + PhysicalResourceID: aws.ToString(event.PhysicalResourceId), + ResourceType: aws.ToString(event.ResourceType), ResourceStatus: resourceStatus, - ResourceStatusReason: aws.StringValue(event.ResourceStatusReason), - Timestamp: aws.TimeValue(event.Timestamp), + ResourceStatusReason: aws.ToString(event.ResourceStatusReason), + Timestamp: eventTime, }) - s.pastEventIDs[aws.StringValue(event.EventId)] = true + s.pastEventIDs[aws.ToString(event.EventId)] = true } if finished || out.NextToken == nil { break diff --git a/internal/pkg/stream/cfnstack_test.go b/internal/pkg/stream/cfnstack_test.go index c4cb477e648..8590b063bbf 100644 --- a/internal/pkg/stream/cfnstack_test.go +++ b/internal/pkg/stream/cfnstack_test.go @@ -8,9 +8,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/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" + "github.com/aws/smithy-go" "github.com/stretchr/testify/require" ) @@ -130,19 +131,19 @@ func testStackStreamer_Fetch_Success(t *testing.T) { client := mockStackClient{ // Events are in reverse chronological order. out: &cloudformation.DescribeStackEventsOutput{ - StackEvents: []*cloudformation.StackEvent{ + StackEvents: []types.StackEvent{ { EventId: aws.String("5"), LogicalResourceId: aws.String("phonetool-test"), PhysicalResourceId: aws.String("phonetool-test"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(startTime.Add(time.Hour)), }, { EventId: aws.String("4"), LogicalResourceId: aws.String("CloudformationExecutionRole"), PhysicalResourceId: aws.String("CloudformationExecutionRole-123a"), - ResourceStatus: aws.String("CREATE_FAILED"), + ResourceStatus: types.ResourceStatus("CREATE_FAILED"), ResourceStatusReason: aws.String("phonetool-test-CFNExecutionRole already exists"), Timestamp: aws.Time(startTime.Add(time.Hour + 30*time.Minute)), }, @@ -150,21 +151,21 @@ func testStackStreamer_Fetch_Success(t *testing.T) { EventId: aws.String("3"), LogicalResourceId: aws.String("Cluster"), PhysicalResourceId: aws.String("Cluster-6574"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(startTime.Add(2 * time.Hour)), }, { EventId: aws.String("2"), LogicalResourceId: aws.String("Cluster"), PhysicalResourceId: aws.String("Cluster-6574"), - ResourceStatus: aws.String("CREATE_IN_PROGRESS"), + ResourceStatus: types.ResourceStatus("CREATE_IN_PROGRESS"), Timestamp: aws.Time(startTime.Add(3 * time.Hour)), }, { EventId: aws.String("1"), LogicalResourceId: aws.String("PublicLoadBalancer"), PhysicalResourceId: aws.String("PublicLoadBalancer-2139"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(startTime.Add(4 * time.Hour)), }, }, @@ -212,11 +213,11 @@ func testStackStreamer_Fetch_PostChangeSet(t *testing.T) { // GIVEN client := mockStackClient{ out: &cloudformation.DescribeStackEventsOutput{ - StackEvents: []*cloudformation.StackEvent{ + StackEvents: []types.StackEvent{ { EventId: aws.String("abc"), LogicalResourceId: aws.String("Cluster"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(time.Date(2020, time.November, 23, 18, 0, 0, 0, time.UTC)), }, }, @@ -245,17 +246,17 @@ func testStackStreamer_Fetch_WithSeenEvents(t *testing.T) { client := mockStackClient{ out: &cloudformation.DescribeStackEventsOutput{ - StackEvents: []*cloudformation.StackEvent{ + StackEvents: []types.StackEvent{ { EventId: aws.String("abc"), LogicalResourceId: aws.String("Cluster"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(startTime.Add(2 * time.Hour)), }, { EventId: aws.String("def"), LogicalResourceId: aws.String("PublicLoadBalancer"), - ResourceStatus: aws.String("CREATE_COMPLETE"), + ResourceStatus: types.ResourceStatus("CREATE_COMPLETE"), Timestamp: aws.Time(startTime.Add(time.Hour)), }, }, @@ -311,7 +312,10 @@ func testStackStreamer_Fetch_WithError(t *testing.T) { func testStackStreamer_Fetch_withThrottle(t *testing.T) { // GIVEN client := &mockStackClient{ - err: awserr.New("RequestThrottled", "throttle err", errors.New("abc")), + err: &smithy.GenericAPIError{ + Code: "RequestThrottled", + Message: "throttle err", + }, } streamer := &StackStreamer{ client: *client, diff --git a/internal/pkg/stream/cfnstackset.go b/internal/pkg/stream/cfnstackset.go index f7cd05b02c4..fcd8e48b767 100644 --- a/internal/pkg/stream/cfnstackset.go +++ b/internal/pkg/stream/cfnstackset.go @@ -9,8 +9,6 @@ import ( "sync" "time" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation/stackset" ) @@ -120,7 +118,7 @@ func (s *StackSetStreamer) Fetch() (next time.Time, done bool, err error) { op, err := s.stackset.DescribeOperation(s.ssName, s.opID) if err != nil { // Check for throttles and wait to try again using the StackSetStreamer's interval. - if request.IsErrorThrottle(err) { + if isThrottleError(err) { s.retries += 1 return nextFetchDate(s.clock, s.rand, s.retries), false, nil } diff --git a/internal/pkg/stream/cfnstackset_test.go b/internal/pkg/stream/cfnstackset_test.go index 65c245f37b2..f12ac442d77 100644 --- a/internal/pkg/stream/cfnstackset_test.go +++ b/internal/pkg/stream/cfnstackset_test.go @@ -8,8 +8,7 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws/awserr" - + "github.com/aws/smithy-go" "github.com/stretchr/testify/require" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation/stackset" @@ -210,7 +209,10 @@ func TestStackSetStreamer_Fetch(t *testing.T) { // GIVEN client := &mockStackSetClient{ describeOpFn: func(_, _ string) (stackset.Operation, error) { - return stackset.Operation{}, awserr.New("RequestThrottled", "throttle err", errors.New("abc")) + return stackset.Operation{}, &smithy.GenericAPIError{ + Code: "RequestThrottled", + Message: "throttle err", + } }, } startTime := time.Date(2020, time.November, 23, 16, 0, 0, 0, time.UTC) diff --git a/internal/pkg/stream/ecs.go b/internal/pkg/stream/ecs.go index 595a8d03a7c..8f409c30de3 100644 --- a/internal/pkg/stream/ecs.go +++ b/internal/pkg/stream/ecs.go @@ -13,8 +13,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -134,7 +133,7 @@ func (s *ECSDeploymentStreamer) Subscribe() <-chan ECSService { func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { out, err := s.client.Service(s.cluster, s.service) if err != nil { - if request.IsErrorThrottle(err) { + if isThrottleError(err) { s.ecsRetries += 1 return nextFetchDate(s.clock, s.rand, s.ecsRetries), false, nil } @@ -145,18 +144,18 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { var deployments []ECSDeployment var primaryDeploymentId string for _, deployment := range out.Deployments { - status := aws.StringValue(deployment.Status) + status := aws.ToString(deployment.Status) rollingDeploy := ECSDeployment{ Status: status, - TaskDefRevision: parseRevisionFromTaskDefARN(aws.StringValue(deployment.TaskDefinition)), + TaskDefRevision: parseRevisionFromTaskDefARN(aws.ToString(deployment.TaskDefinition)), DesiredCount: int(deployment.DesiredCount), RunningCount: int(deployment.RunningCount), FailedCount: int(deployment.FailedTasks), PendingCount: int(deployment.PendingCount), RolloutState: string(deployment.RolloutState), - CreatedAt: aws.TimeValue(deployment.CreatedAt), - UpdatedAt: aws.TimeValue(deployment.UpdatedAt), - Id: aws.StringValue(deployment.Id), + CreatedAt: aws.ToTime(deployment.CreatedAt), + UpdatedAt: aws.ToTime(deployment.UpdatedAt), + Id: aws.ToString(deployment.Id), } deployments = append(deployments, rollingDeploy) if isDeploymentDone(rollingDeploy, s.deploymentCreationTime) { @@ -168,7 +167,7 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { } stoppedSvcTasks, err := s.client.StoppedServiceTasks(s.cluster, s.service) if err != nil { - if request.IsErrorThrottle(err) { + if isThrottleError(err) { s.ecsRetries += 1 return nextFetchDate(s.clock, s.rand, s.ecsRetries), false, nil } @@ -178,8 +177,8 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { var stoppedTasks []ecs.Task for _, st := range stoppedSvcTasks { - if stoppingAt := aws.TimeValue(st.StoppingAt); aws.StringValue(st.StartedBy) != primaryDeploymentId || stoppingAt.Before(s.deploymentCreationTime) || - (strings.Contains(aws.StringValue(st.StoppedReason), ecsScalingActivity)) { + if stoppingAt := aws.ToTime(st.StoppingAt); aws.ToString(st.StartedBy) != primaryDeploymentId || stoppingAt.Before(s.deploymentCreationTime) || + (strings.Contains(aws.ToString(st.StoppedReason), ecsScalingActivity)) { continue } stoppedTasks = append(stoppedTasks, ecs.Task{ @@ -191,19 +190,19 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { }) } sort.SliceStable(stoppedTasks, func(i, j int) bool { - return aws.TimeValue(stoppedTasks[i].StoppingAt).After(aws.TimeValue(stoppedTasks[j].StoppingAt)) + return aws.ToTime(stoppedTasks[i].StoppingAt).After(aws.ToTime(stoppedTasks[j].StoppingAt)) }) var failureMsgs []string for _, event := range out.Events { - if createdAt := aws.TimeValue(event.CreatedAt); createdAt.Before(s.deploymentCreationTime) { + if createdAt := aws.ToTime(event.CreatedAt); createdAt.Before(s.deploymentCreationTime) { break } - id := aws.StringValue(event.Id) + id := aws.ToString(event.Id) if _, ok := s.pastEventIDs[id]; ok { break } - if msg := aws.StringValue(event.Message); isFailureServiceEvent(msg) { + if msg := aws.ToString(event.Message); isFailureServiceEvent(msg) { failureMsgs = append(failureMsgs, msg) } s.pastEventIDs[id] = true @@ -214,7 +213,7 @@ func (s *ECSDeploymentStreamer) Fetch() (next time.Time, done bool, err error) { alarmNames := out.DeploymentConfiguration.Alarms.AlarmNames alarms, err = s.cw.AlarmStatuses(cloudwatch.WithNames(alarmNames)) if err != nil { - if request.IsErrorThrottle(err) { + if isThrottleError(err) { s.cwRetries += 1 return nextFetchDate(s.clock, s.rand, s.cwRetries), false, nil } diff --git a/internal/pkg/stream/ecs_test.go b/internal/pkg/stream/ecs_test.go index 0d742aaf6ba..e8f6edc9753 100644 --- a/internal/pkg/stream/ecs_test.go +++ b/internal/pkg/stream/ecs_test.go @@ -11,8 +11,8 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" + "github.com/aws/aws-sdk-go-v2/aws" awsecs "github.com/aws/aws-sdk-go-v2/service/ecs/types" - "github.com/aws/aws-sdk-go/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/stream/throttle.go b/internal/pkg/stream/throttle.go new file mode 100644 index 00000000000..057378138a9 --- /dev/null +++ b/internal/pkg/stream/throttle.go @@ -0,0 +1,10 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package stream + +import "github.com/aws/aws-sdk-go-v2/aws/retry" + +func isThrottleError(err error) bool { + return retry.IsErrorThrottles(retry.DefaultThrottles).IsErrorThrottle(err).Bool() +} diff --git a/internal/pkg/task/config_runner_test.go b/internal/pkg/task/config_runner_test.go index 065be149237..810aaa684c3 100644 --- a/internal/pkg/task/config_runner_test.go +++ b/internal/pkg/task/config_runner_test.go @@ -13,7 +13,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ec2" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/task/mocks" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/task/env_runner_test.go b/internal/pkg/task/env_runner_test.go index ad0e6593002..3df64f7f9a2 100644 --- a/internal/pkg/task/env_runner_test.go +++ b/internal/pkg/task/env_runner_test.go @@ -14,7 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/describe" "github.com/aproint/copilot-cli/internal/pkg/task/mocks" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/task/task.go b/internal/pkg/task/task.go index b03d7943117..20791d8b4ee 100644 --- a/internal/pkg/task/task.go +++ b/internal/pkg/task/task.go @@ -14,7 +14,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/docker/dockerengine" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) // VPCGetter wraps methods of getting VPC info. @@ -99,11 +99,11 @@ func taskFamilyName(groupName string) string { } func newTaskFromECS(ecsTask *ecs.Task) *Task { - taskARN := aws.StringValue(ecsTask.TaskArn) + taskARN := aws.ToString(ecsTask.TaskArn) eni, _ := ecsTask.ENI() // Best-effort parse the ENI. If we can't find an IP address, we won't show it to the customers instead of erroring. return &Task{ TaskARN: taskARN, - ClusterARN: aws.StringValue(ecsTask.ClusterArn), + ClusterARN: aws.ToString(ecsTask.ClusterArn), StartedAt: ecsTask.StartedAt, ENI: eni, } diff --git a/internal/pkg/template/template_functions.go b/internal/pkg/template/template_functions.go index 021a8abfe65..6936f625073 100644 --- a/internal/pkg/template/template_functions.go +++ b/internal/pkg/template/template_functions.go @@ -13,9 +13,9 @@ import ( "golang.org/x/text/cases" "golang.org/x/text/language" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws/arn" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -131,10 +131,10 @@ func generateMountPointJSON(mountPoints []*MountPoint) string { // Skip adding mount points with empty container paths to the map. // This is validated elsewhere so this condition should never happen, but it // will fail to inject mountpoints with empty paths. - if aws.StringValue(mp.ContainerPath) == "" { + if aws.ToString(mp.ContainerPath) == "" { continue } - volumeMap[aws.StringValue(mp.SourceVolume)] = aws.StringValue(mp.ContainerPath) + volumeMap[aws.ToString(mp.SourceVolume)] = aws.ToString(mp.ContainerPath) } out, ok := getJSONMap(volumeMap) @@ -160,7 +160,7 @@ func generateSNSJSON(topics []*Topic) string { if topic.Name == nil { continue } - topicMap[aws.StringValue(topic.Name)] = topic.ARN() + topicMap[aws.ToString(topic.Name)] = topic.ARN() } out, ok := getJSONMap(topicMap) @@ -184,8 +184,8 @@ func generateQueueURIJSON(ts []*TopicSubscription) string { if sub.Name == nil || sub.Service == nil || sub.Queue == nil { continue } - svc := StripNonAlphaNumFunc(aws.StringValue(sub.Service)) - topicName := StripNonAlphaNumFunc(aws.StringValue(sub.Name)) + svc := StripNonAlphaNumFunc(aws.ToString(sub.Service)) + topicName := StripNonAlphaNumFunc(aws.ToString(sub.Name)) subName := fmt.Sprintf("%s%sEventsQueue", svc, cases.Title(language.English).String(topicName)) urlMap[subName] = fmt.Sprintf("${%s%sURL}", svc, topicName) diff --git a/internal/pkg/template/template_functions_test.go b/internal/pkg/template/template_functions_test.go index 2d532648034..65ffce41b45 100644 --- a/internal/pkg/template/template_functions_test.go +++ b/internal/pkg/template/template_functions_test.go @@ -6,7 +6,7 @@ package template import ( "testing" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/template/template_integration_test.go b/internal/pkg/template/template_integration_test.go index de20e3999af..250b56f60ae 100644 --- a/internal/pkg/template/template_integration_test.go +++ b/internal/pkg/template/template_integration_test.go @@ -6,12 +6,13 @@ package template_test import ( + "context" "testing" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/template" - "github.com/aws/aws-sdk-go/aws" - "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/stretchr/testify/require" "gopkg.in/yaml.v3" ) @@ -111,9 +112,9 @@ func TestTemplate_ParseScheduledJob(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { // GIVEN - sess, err := sessions.ImmutableProvider().Default() + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - cfn := cloudformation.New(sess) + cfn := cloudformation.NewFromConfig(cfg) tpl := template.New() // WHEN @@ -121,7 +122,7 @@ func TestTemplate_ParseScheduledJob(t *testing.T) { require.NoError(t, err) // THEN - _, err = cfn.ValidateTemplate(&cloudformation.ValidateTemplateInput{ + _, err = cfn.ValidateTemplate(context.Background(), &cloudformation.ValidateTemplateInput{ TemplateBody: aws.String(content.String()), }) require.NoError(t, err, content.String()) @@ -501,9 +502,9 @@ DiscoveryServiceArn: for name, tc := range testCases { t.Run(name, func(t *testing.T) { // GIVEN - sess, err := sessions.ImmutableProvider().Default() + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - cfn := cloudformation.New(sess) + cfn := cloudformation.NewFromConfig(cfg) tpl := template.New() // WHEN @@ -511,7 +512,7 @@ DiscoveryServiceArn: require.NoError(t, err) // THEN - _, err = cfn.ValidateTemplate(&cloudformation.ValidateTemplateInput{ + _, err = cfn.ValidateTemplate(context.Background(), &cloudformation.ValidateTemplateInput{ TemplateBody: aws.String(content.String()), }) require.NoError(t, err, content.String()) diff --git a/internal/pkg/template/workload.go b/internal/pkg/template/workload.go index 0b5a2f88f57..230b6138fd5 100644 --- a/internal/pkg/template/workload.go +++ b/internal/pkg/template/workload.go @@ -11,13 +11,11 @@ import ( "strconv" "text/template" - "github.com/aws/aws-sdk-go/service/secretsmanager" - "github.com/dustin/go-humanize/english" "github.com/google/uuid" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" ) // Constants for template paths. @@ -415,7 +413,7 @@ func (s secretsManagerName) ValueFrom() string { // Service returns the name of the SecretsManager service for populating the ARN. func (s secretsManagerName) Service() string { - return secretsmanager.ServiceName + return "secretsmanager" } // SecretFromSecretsManager returns a Secret that refers to SecretsManager secret name. @@ -1077,5 +1075,5 @@ func requiresVPCConnector(o WorkloadOpts) bool { // ARN determines the arn for a topic using the SNSTopic name and account information func (t Topic) ARN() string { - return fmt.Sprintf(snsARNPattern, t.Partition, t.Region, t.AccountID, t.App, t.Env, t.Svc, aws.StringValue(t.Name)) + return fmt.Sprintf(snsARNPattern, t.Partition, t.Region, t.AccountID, t.App, t.Env, t.Svc, aws.ToString(t.Name)) } diff --git a/internal/pkg/template/workload_test.go b/internal/pkg/template/workload_test.go index 3ce75194316..b7d357bea3e 100644 --- a/internal/pkg/template/workload_test.go +++ b/internal/pkg/template/workload_test.go @@ -9,7 +9,7 @@ import ( "github.com/spf13/afero" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/term/progress/ecs.go b/internal/pkg/term/progress/ecs.go index 53f17d6d06c..012cf74aa9d 100644 --- a/internal/pkg/term/progress/ecs.go +++ b/internal/pkg/term/progress/ecs.go @@ -14,7 +14,7 @@ import ( "time" "github.com/aproint/copilot-cli/internal/pkg/aws/cloudwatch" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/dustin/go-humanize/english" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" @@ -221,25 +221,25 @@ func (c *rollingUpdateComponent) renderStoppedTasks(out io.Writer) (numLines int } stopReason2Tasks := make(map[string]*stoppedTasksInfo, len(c.stoppedTasks)) for _, st := range c.stoppedTasks { - id, err := ecs.TaskID(aws.StringValue(st.TaskArn)) + id, err := ecs.TaskID(aws.ToString(st.TaskArn)) if err != nil { return 0, err } - tasks, ok := stopReason2Tasks[aws.StringValue(st.StoppedReason)] + tasks, ok := stopReason2Tasks[aws.ToString(st.StoppedReason)] if ok { tasks.ids = append(tasks.ids, ecs.ShortTaskID(id)) - tasks.latestStoppingAt = aws.TimeValue(st.StoppingAt) - stopReason2Tasks[aws.StringValue(st.StoppedReason)] = tasks + tasks.latestStoppingAt = aws.ToTime(st.StoppingAt) + stopReason2Tasks[aws.ToString(st.StoppedReason)] = tasks } else { - stopReason2Tasks[aws.StringValue(st.StoppedReason)] = &stoppedTasksInfo{ + stopReason2Tasks[aws.ToString(st.StoppedReason)] = &stoppedTasksInfo{ ids: []string{ecs.ShortTaskID(id)}, - latestStoppingAt: aws.TimeValue(st.StoppingAt), + latestStoppingAt: aws.ToTime(st.StoppingAt), } } rows = append(rows, []string{ ecs.ShortTaskID(id), - aws.StringValue(st.LastStatus), - aws.StringValue(st.DesiredStatus), + aws.ToString(st.LastStatus), + aws.ToString(st.DesiredStatus), }) } var sortedReasons []string diff --git a/internal/pkg/term/progress/ecs_test.go b/internal/pkg/term/progress/ecs_test.go index 9afa8682c21..ba0e66a976d 100644 --- a/internal/pkg/term/progress/ecs_test.go +++ b/internal/pkg/term/progress/ecs_test.go @@ -13,7 +13,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" "github.com/aproint/copilot-cli/internal/pkg/stream" "github.com/aproint/copilot-cli/internal/pkg/term/color" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/stretchr/testify/require" ) diff --git a/internal/pkg/term/selector/creds.go b/internal/pkg/term/selector/creds.go index 5d0d4be944c..060497e7b2c 100644 --- a/internal/pkg/term/selector/creds.go +++ b/internal/pkg/term/selector/creds.go @@ -4,12 +4,13 @@ package selector import ( + "context" "fmt" "strings" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/term/prompt" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" ) const ( @@ -26,9 +27,9 @@ type Names interface { // SessionProvider wraps the methods to create AWS sessions. type SessionProvider interface { - Default() (*session.Session, error) - FromProfile(name string) (*session.Session, error) - FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) + DefaultConfig(ctx context.Context) (aws.Config, error) + ConfigFromProfile(ctx context.Context, name string) (aws.Config, error) + ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (aws.Config, error) } // CredsSelect prompts users for credentials. @@ -39,7 +40,7 @@ type CredsSelect struct { } // Creds prompts users to choose either use temporary credentials or choose from one of their existing AWS named profiles. -func (s *CredsSelect) Creds(msg, help string) (*session.Session, error) { +func (s *CredsSelect) Creds(msg, help string) (aws.Config, error) { profileFrom := make(map[string]string) options := []string{tempCredsOption} for _, name := range s.Profile.Names() { @@ -54,40 +55,40 @@ func (s *CredsSelect) Creds(msg, help string) (*session.Session, error) { options, prompt.WithFinalMessage("Credential source:")) if err != nil { - return nil, fmt.Errorf("select credential source: %w", err) + return aws.Config{}, fmt.Errorf("select credential source: %w", err) } if selected == tempCredsOption { return s.askTempCreds() } - sess, err := s.Session.FromProfile(profileFrom[selected]) + cfg, err := s.Session.ConfigFromProfile(context.Background(), profileFrom[selected]) if err != nil { - return nil, fmt.Errorf("create session from profile %s: %w", profileFrom[selected], err) + return aws.Config{}, fmt.Errorf("create config from profile %s: %w", profileFrom[selected], err) } - return sess, nil + return cfg, nil } -func (s *CredsSelect) askTempCreds() (*session.Session, error) { +func (s *CredsSelect) askTempCreds() (aws.Config, error) { defaultAccessKey, defaultSecretAccessKey, defaultSessToken := defaultCreds(s.Session) accessKeyID, err := s.askWithMaskedDefault(accessKeyIDPrompt, defaultAccessKey, prompt.RequireNonEmpty, prompt.WithFinalMessage("AWS Access Key ID:")) if err != nil { - return nil, fmt.Errorf("get access key id: %w", err) + return aws.Config{}, fmt.Errorf("get access key id: %w", err) } secretAccessKey, err := s.askWithMaskedDefault(secretAccessKeyPrompt, defaultSecretAccessKey, prompt.RequireNonEmpty, prompt.WithFinalMessage("AWS Secret Access Key:")) if err != nil { - return nil, fmt.Errorf("get secret access key: %w", err) + return aws.Config{}, fmt.Errorf("get secret access key: %w", err) } sessionToken, err := s.askWithMaskedDefault(sessionTokenPrompt, defaultSessToken, nil, prompt.WithFinalMessage("AWS Session Token:")) if err != nil { - return nil, fmt.Errorf("get session token: %w", err) + return aws.Config{}, fmt.Errorf("get session token: %w", err) } - sess, err := s.Session.FromStaticCreds(accessKeyID, secretAccessKey, sessionToken) + cfg, err := s.Session.ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken) if err != nil { - return nil, fmt.Errorf("create session from temporary credentials: %w", err) + return aws.Config{}, fmt.Errorf("create config from temporary credentials: %w", err) } - return sess, nil + return cfg, nil } func (s *CredsSelect) askWithMaskedDefault(msg, defaultValue string, f prompt.ValidatorFunc, opts ...prompt.PromptConfig) (string, error) { @@ -106,11 +107,11 @@ func (s *CredsSelect) askWithMaskedDefault(msg, defaultValue string, f prompt.Va // If an error occurs, returns empty strings. func defaultCreds(session SessionProvider) (accessKeyID, secretAccessKey, sessionToken string) { // If we cannot retrieve default creds, return empty credentials as default instead of an error. - defaultSess, err := session.Default() + defaultConfig, err := session.DefaultConfig(context.Background()) if err != nil { return } - v, err := sessions.Creds(defaultSess) + v, err := sessions.V2Creds(context.Background(), defaultConfig) if err != nil { return } diff --git a/internal/pkg/term/selector/creds_test.go b/internal/pkg/term/selector/creds_test.go index 544a8c0b978..58890e43502 100644 --- a/internal/pkg/term/selector/creds_test.go +++ b/internal/pkg/term/selector/creds_test.go @@ -7,30 +7,12 @@ import ( "testing" "github.com/aproint/copilot-cli/internal/pkg/term/selector/mocks" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/credentials" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" ) -// mockProvider implements the AWS SDK's credentials.Provider interface. -type mockProvider struct { - value credentials.Value - err error -} - -func (m mockProvider) Retrieve() (credentials.Value, error) { - if m.err != nil { - return credentials.Value{}, m.err - } - return m.value, nil -} - -func (m mockProvider) IsExpired() bool { - return false -} - func TestCredsSelect_Creds(t *testing.T) { testCases := map[string]struct { inMsg string @@ -54,7 +36,7 @@ func TestCredsSelect_Creds(t *testing.T) { }, gomock.Any()).Return("[profile prod]", nil) provider := mocks.NewMockSessionProvider(ctrl) - provider.EXPECT().FromProfile("prod").Return(&session.Session{}, nil) + provider.EXPECT().ConfigFromProfile(gomock.Any(), "prod").Return(aws.Config{}, nil) return &CredsSelect{ Prompt: prompter, @@ -72,16 +54,12 @@ func TestCredsSelect_Creds(t *testing.T) { prompter.EXPECT().SelectOne(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return("Enter temporary credentials", nil) provider := mocks.NewMockSessionProvider(ctrl) - provider.EXPECT().Default().Return(&session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(mockProvider{ - value: credentials.Value{ - AccessKeyID: "11111", - SecretAccessKey: "22222", - SessionToken: "33333", - }, - }), - }, + provider.EXPECT().DefaultConfig(gomock.Any()).Return(aws.Config{ + Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider( + "11111", + "22222", + "33333", + )), }, nil) prompter.EXPECT().Get("What's your AWS Access Key ID?", "", gomock.Any(), gomock.Any()). @@ -91,8 +69,8 @@ func TestCredsSelect_Creds(t *testing.T) { prompter.EXPECT().Get("What's your AWS Session Token?", "", nil, gomock.Any()). Return("****************3333", nil) - provider.EXPECT().FromStaticCreds("11111", "22222", "33333"). - Return(&session.Session{}, nil) + provider.EXPECT().ConfigFromStaticCreds("11111", "22222", "33333"). + Return(aws.Config{}, nil) return &CredsSelect{ Prompt: prompter, diff --git a/internal/pkg/term/selector/mocks/mock_creds.go b/internal/pkg/term/selector/mocks/mock_creds.go index bff3ae4410f..64be9fd2c15 100644 --- a/internal/pkg/term/selector/mocks/mock_creds.go +++ b/internal/pkg/term/selector/mocks/mock_creds.go @@ -5,9 +5,10 @@ package mocks import ( + context "context" reflect "reflect" - session "github.com/aws/aws-sdk-go/aws/session" + aws "github.com/aws/aws-sdk-go-v2/aws" gomock "github.com/golang/mock/gomock" ) @@ -71,47 +72,47 @@ func (m *MockSessionProvider) EXPECT() *MockSessionProviderMockRecorder { return m.recorder } -// Default mocks base method. -func (m *MockSessionProvider) Default() (*session.Session, error) { +// ConfigFromProfile mocks base method. +func (m *MockSessionProvider) ConfigFromProfile(ctx context.Context, name string) (aws.Config, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Default") - ret0, _ := ret[0].(*session.Session) + ret := m.ctrl.Call(m, "ConfigFromProfile", ctx, name) + ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } -// Default indicates an expected call of Default. -func (mr *MockSessionProviderMockRecorder) Default() *gomock.Call { +// ConfigFromProfile indicates an expected call of ConfigFromProfile. +func (mr *MockSessionProviderMockRecorder) ConfigFromProfile(ctx, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Default", reflect.TypeOf((*MockSessionProvider)(nil).Default)) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromProfile", reflect.TypeOf((*MockSessionProvider)(nil).ConfigFromProfile), ctx, name) } -// FromProfile mocks base method. -func (m *MockSessionProvider) FromProfile(name string) (*session.Session, error) { +// ConfigFromStaticCreds mocks base method. +func (m *MockSessionProvider) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (aws.Config, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromProfile", name) - ret0, _ := ret[0].(*session.Session) + ret := m.ctrl.Call(m, "ConfigFromStaticCreds", accessKeyID, secretAccessKey, sessionToken) + ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } -// FromProfile indicates an expected call of FromProfile. -func (mr *MockSessionProviderMockRecorder) FromProfile(name interface{}) *gomock.Call { +// ConfigFromStaticCreds indicates an expected call of ConfigFromStaticCreds. +func (mr *MockSessionProviderMockRecorder) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromProfile", reflect.TypeOf((*MockSessionProvider)(nil).FromProfile), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromStaticCreds", reflect.TypeOf((*MockSessionProvider)(nil).ConfigFromStaticCreds), accessKeyID, secretAccessKey, sessionToken) } -// FromStaticCreds mocks base method. -func (m *MockSessionProvider) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) { +// DefaultConfig mocks base method. +func (m *MockSessionProvider) DefaultConfig(ctx context.Context) (aws.Config, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromStaticCreds", accessKeyID, secretAccessKey, sessionToken) - ret0, _ := ret[0].(*session.Session) + ret := m.ctrl.Call(m, "DefaultConfig", ctx) + ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } -// FromStaticCreds indicates an expected call of FromStaticCreds. -func (mr *MockSessionProviderMockRecorder) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken interface{}) *gomock.Call { +// DefaultConfig indicates an expected call of DefaultConfig. +func (mr *MockSessionProviderMockRecorder) DefaultConfig(ctx interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromStaticCreds", reflect.TypeOf((*MockSessionProvider)(nil).FromStaticCreds), accessKeyID, secretAccessKey, sessionToken) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfig", reflect.TypeOf((*MockSessionProvider)(nil).DefaultConfig), ctx) } diff --git a/internal/pkg/term/selector/selector_test.go b/internal/pkg/term/selector/selector_test.go index 1967e6d684b..25ff6f1b5ee 100644 --- a/internal/pkg/term/selector/selector_test.go +++ b/internal/pkg/term/selector/selector_test.go @@ -16,7 +16,7 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/prompt" "github.com/aproint/copilot-cli/internal/pkg/term/selector/mocks" "github.com/aproint/copilot-cli/internal/pkg/workspace" - "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go-v2/aws" "github.com/dustin/go-humanize" "github.com/golang/mock/gomock" "github.com/stretchr/testify/require" From 684915ddd011df2fd773e9fda2f6d00fc44e358b Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 16:09:28 +0200 Subject: [PATCH 10/17] fix mocks --- .../mocks/mock_cloudformation.go | 2 +- .../stackset/mocks/mock_stackset.go | 2 +- internal/pkg/cli/mocks/mock_interfaces.go | 39 +++++++++++++------ .../mocks/mock_cloudformation.go | 2 +- .../stack/mocks/mock_workload.go | 2 +- 5 files changed, 31 insertions(+), 16 deletions(-) diff --git a/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go b/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go index 2c01d4784a2..7429bdcff82 100644 --- a/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go +++ b/internal/pkg/aws/cloudformation/mocks/mock_cloudformation.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: internal/pkg/aws/cloudformation/interfaces.go +// Source: ./internal/pkg/aws/cloudformation/interfaces.go // Package mocks is a generated GoMock package. package mocks diff --git a/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go b/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go index 9d3ea9d82b6..1379b100a29 100644 --- a/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go +++ b/internal/pkg/aws/cloudformation/stackset/mocks/mock_stackset.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: internal/pkg/aws/cloudformation/stackset/stackset.go +// Source: ./internal/pkg/aws/cloudformation/stackset/stackset.go // Package mocks is a generated GoMock package. package mocks diff --git a/internal/pkg/cli/mocks/mock_interfaces.go b/internal/pkg/cli/mocks/mock_interfaces.go index b2189d5d5bc..c9454fd1b98 100644 --- a/internal/pkg/cli/mocks/mock_interfaces.go +++ b/internal/pkg/cli/mocks/mock_interfaces.go @@ -1938,6 +1938,21 @@ func (mr *MockdefaultSessionProviderMockRecorder) Default() *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Default", reflect.TypeOf((*MockdefaultSessionProvider)(nil).Default)) } +// DefaultConfig mocks base method. +func (m *MockdefaultSessionProvider) DefaultConfig(ctx context.Context) (aws.Config, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DefaultConfig", ctx) + ret0, _ := ret[0].(aws.Config) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// DefaultConfig indicates an expected call of DefaultConfig. +func (mr *MockdefaultSessionProviderMockRecorder) DefaultConfig(ctx interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfig", reflect.TypeOf((*MockdefaultSessionProvider)(nil).DefaultConfig), ctx) +} + // MockregionalSessionProvider is a mock of regionalSessionProvider interface. type MockregionalSessionProvider struct { ctrl *gomock.Controller @@ -2173,34 +2188,34 @@ func (m *MocksessionProvider) EXPECT() *MocksessionProviderMockRecorder { return m.recorder } -// ConfigFromRole mocks base method. -func (m *MocksessionProvider) ConfigFromRole(ctx context.Context, roleARN, region string) (aws.Config, error) { +// ConfigFromProfile mocks base method. +func (m *MocksessionProvider) ConfigFromProfile(ctx context.Context, name string) (aws.Config, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ConfigFromRole", ctx, roleARN, region) + ret := m.ctrl.Call(m, "ConfigFromProfile", ctx, name) ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } -// ConfigFromRole indicates an expected call of ConfigFromRole. -func (mr *MocksessionProviderMockRecorder) ConfigFromRole(ctx, roleARN, region interface{}) *gomock.Call { +// ConfigFromProfile indicates an expected call of ConfigFromProfile. +func (mr *MocksessionProviderMockRecorder) ConfigFromProfile(ctx, name interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromRole), ctx, roleARN, region) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromProfile", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromProfile), ctx, name) } -// ConfigFromProfile mocks base method. -func (m *MocksessionProvider) ConfigFromProfile(ctx context.Context, name string) (aws.Config, error) { +// ConfigFromRole mocks base method. +func (m *MocksessionProvider) ConfigFromRole(ctx context.Context, roleARN, region string) (aws.Config, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ConfigFromProfile", ctx, name) + ret := m.ctrl.Call(m, "ConfigFromRole", ctx, roleARN, region) ret0, _ := ret[0].(aws.Config) ret1, _ := ret[1].(error) return ret0, ret1 } -// ConfigFromProfile indicates an expected call of ConfigFromProfile. -func (mr *MocksessionProviderMockRecorder) ConfigFromProfile(ctx, name interface{}) *gomock.Call { +// ConfigFromRole indicates an expected call of ConfigFromRole. +func (mr *MocksessionProviderMockRecorder) ConfigFromRole(ctx, roleARN, region interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromProfile", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromProfile), ctx, name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromRole), ctx, roleARN, region) } // ConfigFromStaticCreds mocks base method. diff --git a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go index 31796bf2272..3802592ce0e 100644 --- a/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go +++ b/internal/pkg/deploy/cloudformation/mocks/mock_cloudformation.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: internal/pkg/deploy/cloudformation/cloudformation.go +// Source: ./internal/pkg/deploy/cloudformation/cloudformation.go // Package mocks is a generated GoMock package. package mocks diff --git a/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go b/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go index 4c23ae8abb5..3cdf239843c 100644 --- a/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go +++ b/internal/pkg/deploy/cloudformation/stack/mocks/mock_workload.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: internal/pkg/deploy/cloudformation/stack/workload.go +// Source: ./internal/pkg/deploy/cloudformation/stack/workload.go // Package mocks is a generated GoMock package. package mocks From 823026a4444b9e8c2b6d17a1c85f028302f85600 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 16:26:47 +0200 Subject: [PATCH 11/17] migrate final set of v1 references --- .../app_with_domain_suite_test.go | 3 +- e2e/cloudfront/cloudfront_suite_test.go | 25 +- e2e/cloudfront/cloudfront_test.go | 17 +- .../pkg/aws/sessions/mocks/mock_sessions.go | 40 +-- internal/pkg/aws/sessions/sessions.go | 193 +------------- internal/pkg/aws/sessions/sessions_test.go | 245 ------------------ internal/pkg/aws/sessions/sessions_v2.go | 4 - internal/pkg/cli/app_delete.go | 13 +- internal/pkg/cli/app_init.go | 17 +- internal/pkg/cli/app_list.go | 11 +- internal/pkg/cli/app_show.go | 13 +- internal/pkg/cli/app_upgrade.go | 13 +- internal/pkg/cli/config_store.go | 13 - internal/pkg/cli/deploy.go | 12 +- internal/pkg/cli/env_delete.go | 30 +-- internal/pkg/cli/env_deploy.go | 10 +- internal/pkg/cli/env_init.go | 13 +- internal/pkg/cli/env_init_test.go | 6 +- internal/pkg/cli/env_list.go | 8 +- internal/pkg/cli/env_override.go | 10 +- internal/pkg/cli/env_package.go | 13 +- internal/pkg/cli/env_show.go | 8 +- internal/pkg/cli/init.go | 20 +- internal/pkg/cli/interfaces.go | 6 - internal/pkg/cli/job_delete.go | 9 +- internal/pkg/cli/job_deploy.go | 7 +- internal/pkg/cli/job_init.go | 10 +- internal/pkg/cli/job_list.go | 8 +- internal/pkg/cli/job_logs.go | 7 +- internal/pkg/cli/job_package.go | 8 +- internal/pkg/cli/job_run.go | 7 +- internal/pkg/cli/mocks/mock_interfaces.go | 151 ----------- internal/pkg/cli/pipeline_delete.go | 19 +- internal/pkg/cli/pipeline_deploy.go | 19 +- internal/pkg/cli/pipeline_list.go | 12 +- internal/pkg/cli/pipeline_override.go | 10 +- internal/pkg/cli/pipeline_package.go | 15 +- internal/pkg/cli/pipeline_show.go | 15 +- internal/pkg/cli/pipeline_status.go | 15 +- internal/pkg/cli/secret_init.go | 7 +- internal/pkg/cli/storage_init.go | 8 +- internal/pkg/cli/svc_delete.go | 9 +- internal/pkg/cli/svc_deploy.go | 7 +- internal/pkg/cli/svc_exec.go | 7 +- internal/pkg/cli/svc_init.go | 10 +- internal/pkg/cli/svc_list.go | 10 +- internal/pkg/cli/svc_logs.go | 9 +- internal/pkg/cli/svc_override.go | 10 +- internal/pkg/cli/svc_package.go | 9 +- internal/pkg/cli/svc_pause.go | 14 +- internal/pkg/cli/svc_resume.go | 14 +- internal/pkg/cli/svc_show.go | 10 +- internal/pkg/cli/svc_status.go | 10 +- internal/pkg/cli/task_delete.go | 9 +- internal/pkg/cli/task_exec.go | 9 +- internal/pkg/cli/task_run.go | 9 +- internal/pkg/config/store_integration_test.go | 14 +- .../cloudformation_integration_test.go | 183 +++++++------ 58 files changed, 356 insertions(+), 1057 deletions(-) delete mode 100644 internal/pkg/aws/sessions/sessions_test.go diff --git a/e2e/app-with-domain/app_with_domain_suite_test.go b/e2e/app-with-domain/app_with_domain_suite_test.go index b4c327b945c..3aa8d5961cd 100644 --- a/e2e/app-with-domain/app_with_domain_suite_test.go +++ b/e2e/app-with-domain/app_with_domain_suite_test.go @@ -11,7 +11,6 @@ import ( "time" "github.com/aproint/copilot-cli/e2e/internal/client" - "github.com/aws/aws-sdk-go/service/cloudformation" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) @@ -45,7 +44,7 @@ var _ = AfterSuite(func() { // isStackSetOperationInProgress returns if the current stack set is in operation. func isStackSetOperationInProgress(s string) bool { - return strings.Contains(s, cloudformation.ErrCodeOperationInProgressException) + return strings.Contains(s, "OperationInProgressException") } // isImagePushingToECRInProgress returns if we are pushing images to ECR. Pushing images concurrently would fail because diff --git a/e2e/cloudfront/cloudfront_suite_test.go b/e2e/cloudfront/cloudfront_suite_test.go index 1b0c68868b0..90e467430ce 100644 --- a/e2e/cloudfront/cloudfront_suite_test.go +++ b/e2e/cloudfront/cloudfront_suite_test.go @@ -4,16 +4,17 @@ package cloudfront_test import ( + "context" "fmt" "os" "testing" "time" "github.com/aproint/copilot-cli/e2e/internal/client" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" + "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/feature/s3/manager" + "github.com/aws/aws-sdk-go-v2/service/s3" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" ) @@ -21,8 +22,8 @@ import ( var cli *client.CLI var appName string var bucketName string -var s3Client *s3.S3 -var s3Manager *s3manager.Uploader +var s3Client *s3.Client +var s3Manager *manager.Uploader var staticPath string const domainName = "cloudfront.copilot-e2e-tests.ecs.aws.dev" @@ -47,12 +48,10 @@ var _ = BeforeSuite(func() { err = os.Setenv("TIMENOW", fmt.Sprint(timeNow)) Expect(err).NotTo(HaveOccurred()) staticPath = "static/index.html" - sess, err := session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, - }) + cfg, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) Expect(err).NotTo(HaveOccurred()) - s3Client = s3.New(sess) - s3Manager = s3manager.NewUploader(sess) + s3Client = s3.NewFromConfig(cfg) + s3Manager = manager.NewUploader(s3Client) }) var _ = AfterSuite(func() { @@ -63,14 +62,14 @@ var _ = AfterSuite(func() { }) func cleanUpS3Resources() error { - _, err := s3Client.DeleteObject(&s3.DeleteObjectInput{ + _, err := s3Client.DeleteObject(context.Background(), &s3.DeleteObjectInput{ Bucket: aws.String(bucketName), Key: aws.String(staticPath), }) if err != nil { return err } - _, err = s3Client.DeleteBucket(&s3.DeleteBucketInput{ + _, err = s3Client.DeleteBucket(context.Background(), &s3.DeleteBucketInput{ Bucket: aws.String(bucketName), }) return err diff --git a/e2e/cloudfront/cloudfront_test.go b/e2e/cloudfront/cloudfront_test.go index 3f05800d7c1..b41dadb4326 100644 --- a/e2e/cloudfront/cloudfront_test.go +++ b/e2e/cloudfront/cloudfront_test.go @@ -5,32 +5,33 @@ package cloudfront_test import ( "bytes" + "context" "fmt" "net/http" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/aws/arn" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/aws-sdk-go-v2/service/s3/types" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/aproint/copilot-cli/e2e/internal/client" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" ) var _ = Describe("CloudFront", func() { Context("when creating an S3 bucket and upload static files", Ordered, func() { It("bucket creation should succeed", func() { - _, err := s3Client.CreateBucket(&s3.CreateBucketInput{ + _, err := s3Client.CreateBucket(context.Background(), &s3.CreateBucketInput{ Bucket: aws.String(bucketName), - ObjectOwnership: aws.String(s3.ObjectOwnershipBucketOwnerEnforced), + ObjectOwnership: types.ObjectOwnershipBucketOwnerEnforced, }) Expect(err).NotTo(HaveOccurred()) }) It("upload should succeed", func() { - _, err := s3Manager.Upload(&s3manager.UploadInput{ + _, err := s3Manager.Upload(context.Background(), &s3.PutObjectInput{ Bucket: aws.String(bucketName), Key: aws.String(staticPath), Body: bytes.NewBufferString("hello static"), @@ -141,7 +142,7 @@ var _ = Describe("CloudFront", func() { } Expect(accountID).ToNot(BeEmpty()) Expect(cfDistID).ToNot(BeEmpty()) - _, err = s3Client.PutBucketPolicy(&s3.PutBucketPolicyInput{ + _, err = s3Client.PutBucketPolicy(context.Background(), &s3.PutBucketPolicyInput{ Bucket: aws.String(bucketName), Policy: aws.String(fmt.Sprintf(`{ "Version": "2012-10-17", diff --git a/internal/pkg/aws/sessions/mocks/mock_sessions.go b/internal/pkg/aws/sessions/mocks/mock_sessions.go index d2636021f9f..6658a793108 100644 --- a/internal/pkg/aws/sessions/mocks/mock_sessions.go +++ b/internal/pkg/aws/sessions/mocks/mock_sessions.go @@ -5,47 +5,47 @@ package mocks import ( + context "context" reflect "reflect" - credentials "github.com/aws/aws-sdk-go/aws/credentials" - session "github.com/aws/aws-sdk-go/aws/session" + aws "github.com/aws/aws-sdk-go-v2/aws" gomock "github.com/golang/mock/gomock" ) -// MocksessionValidator is a mock of sessionValidator interface. -type MocksessionValidator struct { +// Mockv2ConfigValidator is a mock of v2ConfigValidator interface. +type Mockv2ConfigValidator struct { ctrl *gomock.Controller - recorder *MocksessionValidatorMockRecorder + recorder *Mockv2ConfigValidatorMockRecorder } -// MocksessionValidatorMockRecorder is the mock recorder for MocksessionValidator. -type MocksessionValidatorMockRecorder struct { - mock *MocksessionValidator +// Mockv2ConfigValidatorMockRecorder is the mock recorder for Mockv2ConfigValidator. +type Mockv2ConfigValidatorMockRecorder struct { + mock *Mockv2ConfigValidator } -// NewMocksessionValidator creates a new mock instance. -func NewMocksessionValidator(ctrl *gomock.Controller) *MocksessionValidator { - mock := &MocksessionValidator{ctrl: ctrl} - mock.recorder = &MocksessionValidatorMockRecorder{mock} +// NewMockv2ConfigValidator creates a new mock instance. +func NewMockv2ConfigValidator(ctrl *gomock.Controller) *Mockv2ConfigValidator { + mock := &Mockv2ConfigValidator{ctrl: ctrl} + mock.recorder = &Mockv2ConfigValidatorMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use. -func (m *MocksessionValidator) EXPECT() *MocksessionValidatorMockRecorder { +func (m *Mockv2ConfigValidator) EXPECT() *Mockv2ConfigValidatorMockRecorder { return m.recorder } -// ValidateCredentials mocks base method. -func (m *MocksessionValidator) ValidateCredentials(sess *session.Session) (credentials.Value, error) { +// ValidateV2Credentials mocks base method. +func (m *Mockv2ConfigValidator) ValidateV2Credentials(arg0 context.Context, arg1 aws.Config) (aws.Credentials, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateCredentials", sess) - ret0, _ := ret[0].(credentials.Value) + ret := m.ctrl.Call(m, "ValidateV2Credentials", arg0, arg1) + ret0, _ := ret[0].(aws.Credentials) ret1, _ := ret[1].(error) return ret0, ret1 } -// ValidateCredentials indicates an expected call of ValidateCredentials. -func (mr *MocksessionValidatorMockRecorder) ValidateCredentials(sess interface{}) *gomock.Call { +// ValidateV2Credentials indicates an expected call of ValidateV2Credentials. +func (mr *Mockv2ConfigValidatorMockRecorder) ValidateV2Credentials(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateCredentials", reflect.TypeOf((*MocksessionValidator)(nil).ValidateCredentials), sess) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateV2Credentials", reflect.TypeOf((*Mockv2ConfigValidator)(nil).ValidateV2Credentials), arg0, arg1) } diff --git a/internal/pkg/aws/sessions/sessions.go b/internal/pkg/aws/sessions/sessions.go index b9a4cb184bb..f5fcae13d0a 100644 --- a/internal/pkg/aws/sessions/sessions.go +++ b/internal/pkg/aws/sessions/sessions.go @@ -1,25 +1,15 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -// Package sessions provides functions that return AWS sessions to use in the AWS SDK. +// Package sessions provides functions that return AWS SDK configs to use in the AWS SDK. package sessions import ( "context" - "fmt" - "net/http" - "runtime" "sync" "time" - "github.com/aproint/copilot-cli/internal/pkg/version" awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials/stscreds" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/aws/session" ) // Timeout settings. @@ -34,23 +24,20 @@ const ( userAgentProductName = "aws-copilot" ) -// Provider provides methods to create sessions. -// Once a session is created, it's cached locally so that the same session is not re-created. +// Provider provides methods to create AWS SDK configs. +// Once a config is created, it's cached locally so that the same config is not re-created. type Provider struct { - defaultSess *session.Session - defaultConfigV2 awsv2.Config hasDefaultConfigV2 bool // Metadata associated with the provider. userAgentExtras []string - sessionValidator sessionValidator loadV2Config v2ConfigLoader configV2Validator v2ConfigValidator } -type sessionValidator interface { - ValidateCredentials(sess *session.Session) (credentials.Value, error) +type v2ConfigValidator interface { + ValidateV2Credentials(context.Context, awsv2.Config) (awsv2.Credentials, error) } var instance *Provider @@ -59,9 +46,7 @@ var once sync.Once // ImmutableProvider returns an immutable session Provider with the options applied. func ImmutableProvider(options ...func(*Provider)) *Provider { once.Do(func() { - instance = &Provider{ - sessionValidator: &validator{}, - } + instance = &Provider{} for _, option := range options { option(instance) } @@ -76,171 +61,7 @@ func UserAgentExtras(extras ...string) func(*Provider) { } } -// UserAgentExtras adds additional User-Agent extras to cached sessions and any new sessions. +// UserAgentExtras adds additional User-Agent extras to cached configs and any new configs. func (p *Provider) UserAgentExtras(extras ...string) { p.userAgentExtras = append(p.userAgentExtras, extras...) - if p.defaultSess != nil { - p.defaultSess.Handlers.Build.SwapNamed(p.userAgentHandler()) - } -} - -// Default returns a session configured against the "default" AWS profile. -// Default assumes that a region must be present with a session, otherwise it returns an error. -func (p *Provider) Default() (*session.Session, error) { - sess, err := p.defaultSession() - if err != nil { - return nil, err - } - if aws.StringValue(sess.Config.Region) == "" { - return nil, &errMissingRegion{} - } - return sess, nil -} - -// DefaultWithRegion returns a session configured against the "default" AWS profile and the input region. -func (p *Provider) DefaultWithRegion(region string) (*session.Session, error) { - sess, err := session.NewSessionWithOptions(session.Options{ - Config: *newConfig().WithRegion(region), - SharedConfigState: session.SharedConfigEnable, - AssumeRoleTokenProvider: stscreds.StdinTokenProvider, - }) - if err != nil { - return nil, err - } - sess.Handlers.Build.PushBackNamed(p.userAgentHandler()) - return sess, nil -} - -// FromProfile returns a session configured against the input profile name. -func (p *Provider) FromProfile(name string) (*session.Session, error) { - sess, err := session.NewSessionWithOptions(session.Options{ - Config: *newConfig(), - SharedConfigState: session.SharedConfigEnable, - Profile: name, - AssumeRoleTokenProvider: stscreds.StdinTokenProvider, - }) - if err != nil { - return nil, err - } - if aws.StringValue(sess.Config.Region) == "" { - return nil, &errMissingRegion{} - } - if _, err := p.sessionValidator.ValidateCredentials(sess); err != nil { - if isCredRetrievalErr(err) { - return nil, &errCredRetrieval{profile: name, parentErr: err} - } - return nil, err - } - sess.Handlers.Build.PushBackNamed(p.userAgentHandler()) - return sess, nil -} - -// FromRole returns a session configured against the input role and region. -func (p *Provider) FromRole(roleARN string, region string) (*session.Session, error) { - defaultSession, err := p.defaultSession() - if err != nil { - return nil, fmt.Errorf("create default session: %w", err) - } - - creds := stscreds.NewCredentials(defaultSession, roleARN) - sess, err := session.NewSession( - newConfig(). - WithCredentials(creds). - WithRegion(region), - ) - if err != nil { - return nil, err - } - sess.Handlers.Build.PushBackNamed(p.userAgentHandler()) - return sess, nil -} - -// FromStaticCreds returns a session from static credentials. -func (p *Provider) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) { - conf := newConfig() - conf.Credentials = credentials.NewStaticCredentials(accessKeyID, secretAccessKey, sessionToken) - sess, err := session.NewSessionWithOptions(session.Options{ - Config: *conf, - }) - if err != nil { - return nil, fmt.Errorf("create session from static credentials: %w", err) - } - sess.Handlers.Build.PushBackNamed(p.userAgentHandler()) - return sess, nil -} - -func (p *Provider) defaultSession() (*session.Session, error) { - if p.defaultSess != nil { - return p.defaultSess, nil - } - - sess, err := session.NewSessionWithOptions(session.Options{ - Config: *newConfig(), - SharedConfigState: session.SharedConfigEnable, - AssumeRoleTokenProvider: stscreds.StdinTokenProvider, - }) - if err != nil { - return nil, err - } - if _, err = p.sessionValidator.ValidateCredentials(sess); err != nil { - if isCredRetrievalErr(err) { - return nil, &errCredRetrieval{parentErr: err} - } - return nil, err - } - - sess.Handlers.Build.PushBackNamed(p.userAgentHandler()) - p.defaultSess = sess - return sess, nil -} - -// AreCredsFromEnvVars returns true if the session's credentials provider is environment variables, false otherwise. -// An error is returned if the credentials are invalid or the request times out. -func AreCredsFromEnvVars(sess *session.Session) (bool, error) { - v, err := Creds(sess) - if err != nil { - return false, err - } - return v.ProviderName == session.EnvProviderName, nil -} - -// Creds returns the credential values from a session. -func Creds(sess *session.Session) (credentials.Value, error) { - ctx, cancel := context.WithTimeout(context.Background(), credsTimeout) - defer cancel() - - v, err := sess.Config.Credentials.GetWithContext(ctx) - if err != nil { - return credentials.Value{}, fmt.Errorf("get credentials of session: %w", err) - } - return v, nil -} - -// newConfig returns a config with an end-to-end request timeout and verbose credentials errors. -func newConfig() *aws.Config { - c := &http.Client{ - Timeout: clientTimeout, - } - return aws.NewConfig(). - WithHTTPClient(c). - WithCredentialsChainVerboseErrors(true). - WithMaxRetries(maxRetriesOnRecoverableFailures) -} - -// userAgentHandler returns a http request handler that sets the AWS Copilot custom user agent to all aws requests. -// The User-Agent is of the format "product/version (extra1; extra2; ...; extraN)". -func (p *Provider) userAgentHandler() request.NamedHandler { - extras := append([]string{runtime.GOOS}, p.userAgentExtras...) - return request.NamedHandler{ - Name: "UserAgentHandler", - Fn: request.MakeAddToUserAgentHandler(userAgentProductName, version.Version, extras...), - } -} - -type validator struct{} - -func (v *validator) ValidateCredentials(sess *session.Session) (credentials.Value, error) { - ctx, cancel := context.WithTimeout(context.Background(), credsTimeout) - defer cancel() - return sess.Config.Credentials.GetWithContext(ctx) } diff --git a/internal/pkg/aws/sessions/sessions_test.go b/internal/pkg/aws/sessions/sessions_test.go deleted file mode 100644 index d952421da18..00000000000 --- a/internal/pkg/aws/sessions/sessions_test.go +++ /dev/null @@ -1,245 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -package sessions - -import ( - "context" - "errors" - "os" - "testing" - - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions/mocks" - "github.com/golang/mock/gomock" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/stretchr/testify/require" -) - -// mockProvider implements the AWS SDK's credentials.Provider interface. -type mockProvider struct { - value credentials.Value - err error -} - -func (m mockProvider) Retrieve() (credentials.Value, error) { - if m.err != nil { - return credentials.Value{}, m.err - } - return m.value, nil -} - -func (m mockProvider) IsExpired() bool { - return false -} - -func TestAreCredsFromEnvVars(t *testing.T) { - testCases := map[string]struct { - inSess *session.Session - - wantedOk bool - wantedErr error - }{ - "returns true if the credentials come from environment variables": { - inSess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(mockProvider{ - value: credentials.Value{ - ProviderName: session.EnvProviderName, - }, - err: nil, - }), - }, - }, - wantedOk: true, - }, - "returns false if credentials are provided from a named profile": { - inSess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(mockProvider{ - value: credentials.Value{ - ProviderName: credentials.SharedCredsProviderName, - }, - err: nil, - }), - }, - }, - wantedOk: false, - }, - "returns a wrapped error if fails to fetch credentials": { - inSess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(mockProvider{ - value: credentials.Value{}, - err: errors.New("some error"), - }), - }, - }, - wantedErr: errors.New("get credentials of session: some error"), - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - ok, err := AreCredsFromEnvVars(tc.inSess) - - if tc.wantedErr != nil { - require.EqualError(t, err, tc.wantedErr.Error()) - } else { - require.Equal(t, tc.wantedOk, ok) - } - - }) - } -} - -func TestCreds(t *testing.T) { - testCases := map[string]struct { - inSess *session.Session - - wantedCreds credentials.Value - wantedErr error - }{ - "returns values if provider is valid": { - inSess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(mockProvider{ - value: credentials.Value{ - AccessKeyID: "abc", - SecretAccessKey: "def", - }, - err: nil, - }), - }, - }, - wantedCreds: credentials.Value{ - AccessKeyID: "abc", - SecretAccessKey: "def", - }, - }, - "returns a wrapped error if fails to fetch credentials": { - inSess: &session.Session{ - Config: &aws.Config{ - Credentials: credentials.NewCredentials(mockProvider{ - value: credentials.Value{}, - err: errors.New("some error"), - }), - }, - }, - wantedErr: errors.New("get credentials of session: some error"), - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - creds, err := Creds(tc.inSess) - - if tc.wantedErr != nil { - require.EqualError(t, err, tc.wantedErr.Error()) - } else { - require.Equal(t, tc.wantedCreds, creds) - } - - }) - } -} - -func TestProvider_FromProfile(t *testing.T) { - t.Run("error if region is missing", func(t *testing.T) { - ogRegion := os.Getenv("AWS_REGION") - ogDefaultRegion := os.Getenv("AWS_DEFAULT_REGION") - defer func() { - err := restoreEnvVar("AWS_REGION", ogRegion) - require.NoError(t, err) - - err = restoreEnvVar("AWS_DEFAULT_REGION", ogDefaultRegion) - require.NoError(t, err) - }() - - // Since "walk-like-an-egyptian" is (very likely) a non-existent profile, whether the region information - // is missing depends on whether the `AWS_REGION` environment variable is set. - err := os.Unsetenv("AWS_REGION") - require.NoError(t, err) - err = os.Unsetenv("AWS_DEFAULT_REGION") - require.NoError(t, err) - - // When - sess, err := ImmutableProvider().FromProfile("walk-like-an-egyptian") - - // THEN - require.NotNil(t, err) - require.EqualError(t, errors.New("missing region configuration"), err.Error()) - require.Nil(t, sess) - }) - - t.Run("region information present", func(t *testing.T) { - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - m := mocks.NewMocksessionValidator(ctrl) - m.EXPECT().ValidateCredentials(gomock.Any()).Return(credentials.Value{}, nil) - - ogRegion := os.Getenv("AWS_REGION") - defer func() { - err := restoreEnvVar("AWS_REGION", ogRegion) - require.NoError(t, err) - }() - - // Since "walk-like-an-egyptian" is (very likely) a non-existent profile, whether the region information - // is missing depends on whether the `AWS_REGION` environment variable is set. - err := os.Setenv("AWS_REGION", "us-west-2") - require.NoError(t, err) - - // WHEN - provider := &Provider{ - sessionValidator: m, - } - - sess, err := provider.FromProfile("walk-like-an-egyptian") - - // THEN - require.NoError(t, err) - require.Equal(t, "us-west-2", *sess.Config.Region) - }) - - t.Run("session credentials are incorrect", func(t *testing.T) { - - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - m := mocks.NewMocksessionValidator(ctrl) - m.EXPECT().ValidateCredentials(gomock.Any()).Return(credentials.Value{}, context.DeadlineExceeded) - - ogRegion := os.Getenv("AWS_REGION") - defer func() { - err := restoreEnvVar("AWS_REGION", ogRegion) - require.NoError(t, err) - }() - - // Since "walk-like-an-egyptian" is (very likely) a non-existent profile, whether the region information - // is missing depends on whether the `AWS_REGION` environment variable is set. - err := os.Setenv("AWS_REGION", "us-west-2") - require.NoError(t, err) - - // WHEN - provider := &Provider{ - sessionValidator: m, - } - - sess, err := provider.FromProfile("walk-like-an-egyptian") - - // THEN - require.EqualError(t, err, "context deadline exceeded") - require.Nil(t, sess) - }) -} - -func restoreEnvVar(key string, originalValue string) error { - if originalValue == "" { - return os.Unsetenv(key) - } - return os.Setenv(key, originalValue) -} diff --git a/internal/pkg/aws/sessions/sessions_v2.go b/internal/pkg/aws/sessions/sessions_v2.go index 5257f8a2406..5c84ecb3bb6 100644 --- a/internal/pkg/aws/sessions/sessions_v2.go +++ b/internal/pkg/aws/sessions/sessions_v2.go @@ -24,10 +24,6 @@ import ( type v2ConfigLoader func(context.Context, ...func(*v2config.LoadOptions) error) (awsv2.Config, error) -type v2ConfigValidator interface { - ValidateV2Credentials(context.Context, awsv2.Config) (awsv2.Credentials, error) -} - // DefaultConfig returns an SDK v2 config configured against the default AWS profile. // DefaultConfig assumes that a region must be present with the config, otherwise it returns an error. func (p *Provider) DefaultConfig(ctx context.Context) (awsv2.Config, error) { diff --git a/internal/pkg/cli/app_delete.go b/internal/pkg/cli/app_delete.go index 04bcb8feae2..c70e795e6f8 100644 --- a/internal/pkg/cli/app_delete.go +++ b/internal/pkg/cli/app_delete.go @@ -72,26 +72,23 @@ type deleteAppOpts struct { func newDeleteAppOpts(vars deleteAppVars) (*deleteAppOpts, error) { provider := sessions.ImmutableProvider(sessions.UserAgentExtras("app delete")) - defaultSession, err := provider.Default() + defaultConfig, err := provider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } prompter := prompt.New() - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) return &deleteAppOpts{ deleteAppVars: vars, spinner: termprogress.NewSpinner(log.DiagnosticWriter), store: store, sessProvider: provider, - cfn: cloudformation.New(v2ConfigFromSessionRegion(defaultSession), cloudformation.WithProgressTracker(os.Stderr)), + cfn: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), prompt: prompter, s3: func(cfg aws.Config) bucketEmptier { return s3.New(cfg) }, - pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), + pipelineLister: deploy.NewPipelineStore(rg.New(defaultConfig)), sel: selector.NewAppEnvSelector(prompter, store), svcDeleteExecutor: func(appName, svcName string) (executor, error) { opts, err := newDeleteSvcOpts(deleteSvcVars{ diff --git a/internal/pkg/cli/app_init.go b/internal/pkg/cli/app_init.go index 931bf9275b4..53b111f0246 100644 --- a/internal/pkg/cli/app_init.go +++ b/internal/pkg/cli/app_init.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -13,7 +14,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/spf13/afero" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/aws/arn" "github.com/spf13/cobra" @@ -66,26 +66,25 @@ type initAppOpts struct { } func newInitAppOpts(vars initAppVars) (*initAppOpts, error) { - sess, err := sessions.ImmutableProvider(sessions.UserAgentExtras("app init")).Default() + cfg, err := sessions.ImmutableProvider(sessions.UserAgentExtras("app init")).DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } fs := afero.NewOsFs() - cfg := v2ConfigFromSessionRegion(sess) identity := identity.New(cfg) - iamClient := iam.New(v2ConfigFromSessionRegion(sess)) + iamClient := iam.New(cfg) return &initAppOpts{ initAppVars: vars, identity: identity, - store: config.NewSSMStore(identity, config.NewSSMClient(cfg), aws.ToString(sess.Config.Region)), - route53: route53.New(v2ConfigFromSessionRegion(sess)), - cfn: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), + store: config.NewSSMStore(identity, config.NewSSMClient(cfg), cfg.Region), + route53: route53.New(cfg), + cfn: cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)), prompt: prompt.New(), prog: termprogress.NewSpinner(log.DiagnosticWriter), iam: iamClient, iamRoleManager: iamClient, isSessionFromEnvVars: func() (bool, error) { - return sessions.AreCredsFromEnvVars(sess) + return sessions.AreV2CredsFromEnvVars(context.Background(), cfg) }, existingWorkspace: func() (wsAppManager, error) { return workspace.Use(fs) diff --git a/internal/pkg/cli/app_list.go b/internal/pkg/cli/app_list.go index 1eb223f8550..976ecd6b6a0 100644 --- a/internal/pkg/cli/app_list.go +++ b/internal/pkg/cli/app_list.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "io" "os" @@ -43,15 +44,11 @@ func buildAppListCommand() *cobra.Command { opts := listAppOpts{ w: os.Stdout, } - sess, err := sessions.ImmutableProvider(sessions.UserAgentExtras("app ls")).Default() + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("app ls")).DefaultConfig(context.Background()) if err != nil { - return fmt.Errorf("default session: %v", err) + return fmt.Errorf("default config: %v", err) } - store, err := newSSMConfigStore(sess) - if err != nil { - return err - } - opts.store = store + opts.store = newSSMConfigStoreFromConfig(defaultConfig) return opts.Execute() }), } diff --git a/internal/pkg/cli/app_show.go b/internal/pkg/cli/app_show.go index 7054ce12e22..08d2dce76e8 100644 --- a/internal/pkg/cli/app_show.go +++ b/internal/pkg/cli/app_show.go @@ -52,14 +52,11 @@ type showAppOpts struct { func newShowAppOpts(vars showAppVars) (*showAppOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("app show")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) - } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err + return nil, fmt.Errorf("default config: %w", err) } + store := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) @@ -70,8 +67,8 @@ func newShowAppOpts(vars showAppVars) (*showAppOpts, error) { w: log.OutputWriter, sel: selector.NewAppEnvSelector(prompt.New(), store), deployStore: deployStore, - codepipeline: codepipeline.New(v2ConfigFromSessionRegion(defaultSession), v2ConfigFromSessionRegion(defaultSession)), - pipelineLister: deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSession))), + codepipeline: codepipeline.New(defaultConfig, defaultConfig), + pipelineLister: deploy.NewPipelineStore(rg.New(defaultConfig)), newVersionGetter: func(s string) (versionGetter, error) { d, err := describe.NewAppDescriber(s) if err != nil { diff --git a/internal/pkg/cli/app_upgrade.go b/internal/pkg/cli/app_upgrade.go index e300327b379..8fd554a1bb3 100644 --- a/internal/pkg/cli/app_upgrade.go +++ b/internal/pkg/cli/app_upgrade.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "os" @@ -54,22 +55,18 @@ type appUpgradeOpts struct { } func newAppUpgradeOpts(vars appUpgradeVars) (*appUpgradeOpts, error) { - sess, err := sessions.ImmutableProvider(sessions.UserAgentExtras("app upgrade")).Default() + cfg, err := sessions.ImmutableProvider(sessions.UserAgentExtras("app upgrade")).DefaultConfig(context.Background()) if err != nil { return nil, err } - store, err := newSSMConfigStore(sess) - if err != nil { - return nil, err - } - cfg := v2ConfigFromSessionRegion(sess) + store := newSSMConfigStoreFromConfig(cfg) return &appUpgradeOpts{ appUpgradeVars: vars, store: store, identity: identity.New(cfg), - route53: route53.New(v2ConfigFromSessionRegion(sess)), + route53: route53.New(cfg), sel: selector.NewAppEnvSelector(prompt.New(), store), - upgrader: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), + upgrader: cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)), newVersionGetter: func(appName string) (versionGetter, error) { d, err := describe.NewAppDescriber(appName) if err != nil { diff --git a/internal/pkg/cli/config_store.go b/internal/pkg/cli/config_store.go index 50543430727..75f4382e164 100644 --- a/internal/pkg/cli/config_store.go +++ b/internal/pkg/cli/config_store.go @@ -1,24 +1,11 @@ package cli import ( - "context" - "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws/session" ) -func newSSMConfigStore(sess *session.Session) (*config.Store, error) { - return newSSMConfigStoreFromConfig(v2ConfigFromSessionRegion(sess)), nil -} - func newSSMConfigStoreFromConfig(cfg aws.Config) *config.Store { return config.NewSSMStore(identity.New(cfg), config.NewSSMClient(cfg), cfg.Region) } - -func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(sess.Config.Region)) - return cfg -} diff --git a/internal/pkg/cli/deploy.go b/internal/pkg/cli/deploy.go index 728ce741398..29458c38bd8 100644 --- a/internal/pkg/cli/deploy.go +++ b/internal/pkg/cli/deploy.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "math" @@ -114,14 +115,11 @@ type deployOpts struct { func newDeployOpts(vars deployVars) (*deployOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("deploy")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) - } - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err + return nil, fmt.Errorf("default config: %v", err) } + store := newSSMConfigStoreFromConfig(defaultConfig) ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err @@ -137,7 +135,7 @@ func newDeployOpts(vars deployVars) (*deployOpts, error) { newWorkloadAdder: func() wkldInitializerWithoutManifest { return &initialize.WorkloadInitializer{ Store: store, - Deployer: cloudformation.New(v2ConfigFromSessionRegion(defaultSess)), + Deployer: cloudformation.New(defaultConfig), Ws: ws, Prog: termprogress.NewSpinner(log.DiagnosticWriter), } diff --git a/internal/pkg/cli/env_delete.go b/internal/pkg/cli/env_delete.go index c212b080b80..1150c5b844b 100644 --- a/internal/pkg/cli/env_delete.go +++ b/internal/pkg/cli/env_delete.go @@ -106,14 +106,11 @@ type deleteEnvOpts struct { func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env delete")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) - } - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err + return nil, fmt.Errorf("default config: %v", err) } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &deleteEnvOpts{ @@ -129,19 +126,18 @@ func newDeleteEnvOpts(vars deleteEnvVars) (*deleteEnvOpts, error) { if err != nil { return err } - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { - return fmt.Errorf("create session from environment manager role %s in region %s: %w", env.ManagerRoleARN, env.Region, err) + return fmt.Errorf("create config from environment manager role %s in region %s: %w", env.ManagerRoleARN, env.Region, err) } - o.rg = &resourceGroupsClient{client: resourcegroupstaggingapi.NewFromConfig(v2ConfigFromSessionRegion(sess))} - o.iam = iam.New(v2ConfigFromSessionRegion(sess)) - o.s3 = s3.New(v2ConfigFromSessionRegion(sess)) - o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), v2ConfigFromSessionRegion(sess)) - o.deployer = cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)) - o.envDeleterFromApp = cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)) - defaultV2Config := v2ConfigFromSessionRegion(defaultSess) - o.pipelineGetter = codepipeline.New(defaultV2Config, defaultV2Config) - o.deployedPipelineLister = deploy.NewPipelineStore(rg.New(v2ConfigFromSessionRegion(defaultSess))) + o.rg = &resourceGroupsClient{client: resourcegroupstaggingapi.NewFromConfig(cfg)} + o.iam = iam.New(cfg) + o.s3 = s3.New(cfg) + o.envStackDescriber = stackdescr.NewStackDescriber(stack.NameForEnv(o.appName, o.name), cfg) + o.deployer = cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) + o.envDeleterFromApp = cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)) + o.pipelineGetter = codepipeline.New(defaultConfig, defaultConfig) + o.deployedPipelineLister = deploy.NewPipelineStore(rg.New(defaultConfig)) return nil }, }, nil diff --git a/internal/pkg/cli/env_deploy.go b/internal/pkg/cli/env_deploy.go index fa01791b027..efc999d1284 100644 --- a/internal/pkg/cli/env_deploy.go +++ b/internal/pkg/cli/env_deploy.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -71,14 +72,11 @@ type deployEnvOpts struct { func newEnvDeployOpts(vars deployEnvVars) (*deployEnvOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env deploy")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) fs := afero.NewOsFs() ws, err := workspace.Use(fs) if err != nil { @@ -102,7 +100,7 @@ func newEnvDeployOpts(vars deployEnvVars) (*deployEnvOpts, error) { fs: fs, ws: ws, - identity: identity.New(v2ConfigFromSessionRegion(defaultSess)), + identity: identity.New(defaultConfig), templateVersion: version.LatestTemplateVersion(), newInterpolator: newManifestInterpolator, } diff --git a/internal/pkg/cli/env_init.go b/internal/pkg/cli/env_init.go index a905d535916..6d0ac314cad 100644 --- a/internal/pkg/cli/env_init.go +++ b/internal/pkg/cli/env_init.go @@ -189,14 +189,11 @@ type initEnvOpts struct { func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env init")) - defaultSession, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSession) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() ws, err := workspace.Use(afero.NewOsFs()) if err != nil { @@ -206,8 +203,8 @@ func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { initEnvVars: vars, sessProvider: sessProvider, store: store, - appDeployer: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), - identity: identity.New(v2ConfigFromSessionRegion(defaultSession)), + appDeployer: deploycfn.New(defaultConfig, deploycfn.WithProgressTracker(os.Stderr)), + identity: identity.New(defaultConfig), prog: termprogress.NewSpinner(log.DiagnosticWriter), prompt: prompter, selCreds: func() (credsSelector, error) { @@ -225,7 +222,7 @@ func newInitEnvOpts(vars initEnvVars) (*initEnvOpts, error) { return describe.NewAppDescriber(appName) }, selApp: selector.NewAppEnvSelector(prompt.New(), store), - appCFN: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), + appCFN: deploycfn.New(defaultConfig, deploycfn.WithProgressTracker(os.Stderr)), manifestWriter: ws, envLister: ws, diff --git a/internal/pkg/cli/env_init_test.go b/internal/pkg/cli/env_init_test.go index d6effb34648..8f8c5b7aaf5 100644 --- a/internal/pkg/cli/env_init_test.go +++ b/internal/pkg/cli/env_init_test.go @@ -16,7 +16,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/aws/cloudformation" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" - "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" "github.com/aproint/copilot-cli/internal/pkg/config" "github.com/aproint/copilot-cli/internal/pkg/deploy" deploycfn "github.com/aproint/copilot-cli/internal/pkg/deploy/cloudformation" @@ -1306,9 +1305,6 @@ func TestInitEnvOpts_Execute(t *testing.T) { appVersionGetter: mocks.NewMockversionGetter(ctrl), } tc.setupMocks(m) - provider := sessions.ImmutableProvider() - sess, _ := provider.DefaultWithRegion("us-west-2") - opts := &initEnvOpts{ initEnvVars: initEnvVars{ name: "test", @@ -1326,7 +1322,7 @@ func TestInitEnvOpts_Execute(t *testing.T) { iam: m.iam, cfn: m.cfn, prog: m.progress, - cfg: v2ConfigFromSessionRegion(sess), + cfg: aws.Config{Region: "us-west-2"}, appCFN: m.appCFN, newAppVersionGetter: func(appName string) (versionGetter, error) { return m.appVersionGetter, nil diff --git a/internal/pkg/cli/env_list.go b/internal/pkg/cli/env_list.go index 34bd01b607c..0f700798d2d 100644 --- a/internal/pkg/cli/env_list.go +++ b/internal/pkg/cli/env_list.go @@ -4,6 +4,7 @@ package cli import ( + "context" "encoding/json" "fmt" "io" @@ -39,14 +40,11 @@ type listEnvOpts struct { func newListEnvOpts(vars listEnvVars) (*listEnvOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env ls")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &listEnvOpts{ listEnvVars: vars, diff --git a/internal/pkg/cli/env_override.go b/internal/pkg/cli/env_override.go index bfb6be73ed4..e24cfdc6907 100644 --- a/internal/pkg/cli/env_override.go +++ b/internal/pkg/cli/env_override.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "slices" @@ -33,14 +34,11 @@ func newOverrideEnvOpts(vars overrideVars) (*overrideEnvOpts, error) { } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env override")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) - } - cfgStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err + return nil, fmt.Errorf("default config: %v", err) } + cfgStore := newSSMConfigStoreFromConfig(defaultConfig) vars.requiresEnv = true prompt := prompt.New() cmd := &overrideEnvOpts{ diff --git a/internal/pkg/cli/env_package.go b/internal/pkg/cli/env_package.go index b1581bf19fa..9468fb26463 100644 --- a/internal/pkg/cli/env_package.go +++ b/internal/pkg/cli/env_package.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -84,9 +85,9 @@ type packageEnvOpts struct { func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env package")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } fs := afero.NewOsFs() @@ -94,11 +95,7 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { if err != nil { return nil, err } - cfgStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } - cfg := v2ConfigFromSessionRegion(defaultSess) + cfgStore := newSSMConfigStoreFromConfig(defaultConfig) opts := &packageEnvOpts{ packageEnvVars: vars, @@ -106,7 +103,7 @@ func newPackageEnvOpts(vars packageEnvVars) (*packageEnvOpts, error) { cfgStore: cfgStore, ws: ws, sel: selector.NewLocalEnvironmentSelector(prompt.New(), cfgStore, ws), - caller: identity.New(cfg), + caller: identity.New(defaultConfig), fs: fs, tplWriter: os.Stdout, paramsWriter: discardFile{}, diff --git a/internal/pkg/cli/env_show.go b/internal/pkg/cli/env_show.go index 5015b2a01ff..fb1abbab456 100644 --- a/internal/pkg/cli/env_show.go +++ b/internal/pkg/cli/env_show.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "io" @@ -45,14 +46,11 @@ type showEnvOpts struct { func newShowEnvOpts(vars showEnvVars) (*showEnvOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("env show")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { diff --git a/internal/pkg/cli/init.go b/internal/pkg/cli/init.go index 0a27cf94b4c..20fe426142c 100644 --- a/internal/pkg/cli/init.go +++ b/internal/pkg/cli/init.go @@ -5,6 +5,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -103,14 +104,11 @@ type initOpts struct { func newInitOpts(vars initVars) (*initOpts, error) { fs := afero.NewOsFs() sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("init")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - configStore, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + configStore := newSSMConfigStoreFromConfig(defaultConfig) prompt := prompt.New() sel := selector.NewConfigSelector(prompt, configStore) deployStore, err := deploy.NewStore(sessProvider, configStore) @@ -119,9 +117,9 @@ func newInitOpts(vars initVars) (*initOpts, error) { } snsSel := selector.NewDeploySelect(prompt, configStore, deployStore) spin := termprogress.NewSpinner(log.DiagnosticWriter) - id := identity.New(v2ConfigFromSessionRegion(defaultSess)) - deployer := cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)) - iamClient := iam.New(v2ConfigFromSessionRegion(defaultSess)) + id := identity.New(defaultConfig) + deployer := cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)) + iamClient := iam.New(defaultConfig) initAppCmd := &initAppOpts{ initAppVars: initAppVars{ name: vars.appName, @@ -132,7 +130,7 @@ func newInitOpts(vars initVars) (*initOpts, error) { cfn: deployer, prog: spin, isSessionFromEnvVars: func() (bool, error) { - return sessions.AreCredsFromEnvVars(defaultSess) + return sessions.AreV2CredsFromEnvVars(context.Background(), defaultConfig) }, existingWorkspace: func() (wsAppManager, error) { return workspace.Use(fs) @@ -152,8 +150,8 @@ func newInitOpts(vars initVars) (*initOpts, error) { newAppVersionGetter: func(appName string) (versionGetter, error) { return describe.NewAppDescriber(appName) }, - appCFN: cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)), - cfg: v2ConfigFromSessionRegion(defaultSess), + appCFN: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), + cfg: defaultConfig, templateVersion: version.LatestTemplateVersion(), } deployEnvCmd := &deployEnvOpts{ diff --git a/internal/pkg/cli/interfaces.go b/internal/pkg/cli/interfaces.go index a638d98c2c4..3e28add545a 100644 --- a/internal/pkg/cli/interfaces.go +++ b/internal/pkg/cli/interfaces.go @@ -36,7 +36,6 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/term/selector" "github.com/aproint/copilot-cli/internal/pkg/workspace" awsv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws/session" ) type cmd interface { @@ -203,27 +202,22 @@ type eventsWriter interface { } type defaultSessionProvider interface { - Default() (*session.Session, error) DefaultConfig(ctx context.Context) (awsv2.Config, error) } type regionalSessionProvider interface { - DefaultWithRegion(region string) (*session.Session, error) DefaultConfigWithRegion(ctx context.Context, region string) (awsv2.Config, error) } type sessionFromRoleProvider interface { - FromRole(roleARN string, region string) (*session.Session, error) ConfigFromRole(ctx context.Context, roleARN string, region string) (awsv2.Config, error) } type sessionFromStaticProvider interface { - FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) ConfigFromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (awsv2.Config, error) } type sessionFromProfileProvider interface { - FromProfile(name string) (*session.Session, error) ConfigFromProfile(ctx context.Context, name string) (awsv2.Config, error) } diff --git a/internal/pkg/cli/job_delete.go b/internal/pkg/cli/job_delete.go index 0161a1e8028..c39b2d66d80 100644 --- a/internal/pkg/cli/job_delete.go +++ b/internal/pkg/cli/job_delete.go @@ -72,14 +72,11 @@ type deleteJobOpts struct { func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { provider := sessions.ImmutableProvider(sessions.UserAgentExtras("job delete")) - defaultSession, err := provider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSession) + defaultConfig, err := provider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &deleteJobOpts{ deleteJobVars: vars, @@ -89,7 +86,7 @@ func newDeleteJobOpts(vars deleteJobVars) (*deleteJobOpts, error) { prompt: prompt.New(), sel: selector.NewConfigSelector(prompter, store), sess: provider, - appCFN: cloudformation.New(v2ConfigFromSessionRegion(defaultSession), cloudformation.WithProgressTracker(os.Stderr)), + appCFN: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), newWlDeleter: func(cfg aws.Config) wlDeleter { return cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) }, diff --git a/internal/pkg/cli/job_deploy.go b/internal/pkg/cli/job_deploy.go index b26c2ae5845..9a7c53c7565 100644 --- a/internal/pkg/cli/job_deploy.go +++ b/internal/pkg/cli/job_deploy.go @@ -66,14 +66,11 @@ type deployJobOpts struct { func newJobDeployOpts(vars deployWkldVars) (*deployJobOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("job deploy")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err diff --git a/internal/pkg/cli/job_init.go b/internal/pkg/cli/job_init.go index b9ad10250e7..3957451cc32 100644 --- a/internal/pkg/cli/job_init.go +++ b/internal/pkg/cli/job_init.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -96,19 +97,16 @@ func newInitJobOpts(vars initJobVars) (*initJobOpts, error) { } p := sessions.ImmutableProvider(sessions.UserAgentExtras("job init")) - sess, err := p.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(sess) + defaultConfig, err := p.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) jobInitter := &initialize.WorkloadInitializer{ Store: store, Ws: ws, Prog: termprogress.NewSpinner(log.DiagnosticWriter), - Deployer: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), + Deployer: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), } prompter := prompt.New() diff --git a/internal/pkg/cli/job_list.go b/internal/pkg/cli/job_list.go index a98b223d9c4..23866028983 100644 --- a/internal/pkg/cli/job_list.go +++ b/internal/pkg/cli/job_list.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "os" @@ -30,14 +31,11 @@ type listJobOpts struct { } func newListJobOpts(vars listWkldVars) (*listJobOpts, error) { - defaultSession, err := sessions.ImmutableProvider(sessions.UserAgentExtras("job ls")).Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSession) + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("job ls")).DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err diff --git a/internal/pkg/cli/job_logs.go b/internal/pkg/cli/job_logs.go index 39d792d0eea..38addd90e4d 100644 --- a/internal/pkg/cli/job_logs.go +++ b/internal/pkg/cli/job_logs.go @@ -45,14 +45,11 @@ type jobLogsOpts struct { func newJobLogOpts(vars jobLogsVars) (*jobLogsOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("job logs")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - configStore, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + configStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { diff --git a/internal/pkg/cli/job_package.go b/internal/pkg/cli/job_package.go index a115bc02cbc..97685f6ceb0 100644 --- a/internal/pkg/cli/job_package.go +++ b/internal/pkg/cli/job_package.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "os" "slices" @@ -53,14 +54,11 @@ type packageJobOpts struct { func newPackageJobOpts(vars packageJobVars) (*packageJobOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("job package")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) fs := afero.NewOsFs() ws, err := workspace.Use(fs) if err != nil { diff --git a/internal/pkg/cli/job_run.go b/internal/pkg/cli/job_run.go index 479ddc245d9..a4e919fe8bd 100644 --- a/internal/pkg/cli/job_run.go +++ b/internal/pkg/cli/job_run.go @@ -47,14 +47,11 @@ type jobRunOpts struct { func newJobRunOpts(vars jobRunVars) (*jobRunOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("job deploy")) - defaultSess, err := sessProvider.Default() - if err != nil { - return nil, err - } - configStore, err := newSSMConfigStore(defaultSess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + configStore := newSSMConfigStoreFromConfig(defaultConfig) ws, err := workspace.Use(afero.NewOsFs()) if err != nil { return nil, err diff --git a/internal/pkg/cli/mocks/mock_interfaces.go b/internal/pkg/cli/mocks/mock_interfaces.go index c9454fd1b98..bc2b0ecdb09 100644 --- a/internal/pkg/cli/mocks/mock_interfaces.go +++ b/internal/pkg/cli/mocks/mock_interfaces.go @@ -37,7 +37,6 @@ import ( workspace "github.com/aproint/copilot-cli/internal/pkg/workspace" aws "github.com/aws/aws-sdk-go-v2/aws" types "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - session "github.com/aws/aws-sdk-go/aws/session" gomock "github.com/golang/mock/gomock" ) @@ -1923,21 +1922,6 @@ func (m *MockdefaultSessionProvider) EXPECT() *MockdefaultSessionProviderMockRec return m.recorder } -// Default mocks base method. -func (m *MockdefaultSessionProvider) Default() (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Default") - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Default indicates an expected call of Default. -func (mr *MockdefaultSessionProviderMockRecorder) Default() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Default", reflect.TypeOf((*MockdefaultSessionProvider)(nil).Default)) -} - // DefaultConfig mocks base method. func (m *MockdefaultSessionProvider) DefaultConfig(ctx context.Context) (aws.Config, error) { m.ctrl.T.Helper() @@ -1991,21 +1975,6 @@ func (mr *MockregionalSessionProviderMockRecorder) DefaultConfigWithRegion(ctx, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfigWithRegion", reflect.TypeOf((*MockregionalSessionProvider)(nil).DefaultConfigWithRegion), ctx, region) } -// DefaultWithRegion mocks base method. -func (m *MockregionalSessionProvider) DefaultWithRegion(region string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefaultWithRegion", region) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DefaultWithRegion indicates an expected call of DefaultWithRegion. -func (mr *MockregionalSessionProviderMockRecorder) DefaultWithRegion(region interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultWithRegion", reflect.TypeOf((*MockregionalSessionProvider)(nil).DefaultWithRegion), region) -} - // MocksessionFromRoleProvider is a mock of sessionFromRoleProvider interface. type MocksessionFromRoleProvider struct { ctrl *gomock.Controller @@ -2044,21 +2013,6 @@ func (mr *MocksessionFromRoleProviderMockRecorder) ConfigFromRole(ctx, roleARN, return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromRole", reflect.TypeOf((*MocksessionFromRoleProvider)(nil).ConfigFromRole), ctx, roleARN, region) } -// FromRole mocks base method. -func (m *MocksessionFromRoleProvider) FromRole(roleARN, region string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromRole", roleARN, region) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FromRole indicates an expected call of FromRole. -func (mr *MocksessionFromRoleProviderMockRecorder) FromRole(roleARN, region interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromRole", reflect.TypeOf((*MocksessionFromRoleProvider)(nil).FromRole), roleARN, region) -} - // MocksessionFromStaticProvider is a mock of sessionFromStaticProvider interface. type MocksessionFromStaticProvider struct { ctrl *gomock.Controller @@ -2097,21 +2051,6 @@ func (mr *MocksessionFromStaticProviderMockRecorder) ConfigFromStaticCreds(acces return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromStaticCreds", reflect.TypeOf((*MocksessionFromStaticProvider)(nil).ConfigFromStaticCreds), accessKeyID, secretAccessKey, sessionToken) } -// FromStaticCreds mocks base method. -func (m *MocksessionFromStaticProvider) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromStaticCreds", accessKeyID, secretAccessKey, sessionToken) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FromStaticCreds indicates an expected call of FromStaticCreds. -func (mr *MocksessionFromStaticProviderMockRecorder) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromStaticCreds", reflect.TypeOf((*MocksessionFromStaticProvider)(nil).FromStaticCreds), accessKeyID, secretAccessKey, sessionToken) -} - // MocksessionFromProfileProvider is a mock of sessionFromProfileProvider interface. type MocksessionFromProfileProvider struct { ctrl *gomock.Controller @@ -2150,21 +2089,6 @@ func (mr *MocksessionFromProfileProviderMockRecorder) ConfigFromProfile(ctx, nam return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromProfile", reflect.TypeOf((*MocksessionFromProfileProvider)(nil).ConfigFromProfile), ctx, name) } -// FromProfile mocks base method. -func (m *MocksessionFromProfileProvider) FromProfile(name string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromProfile", name) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FromProfile indicates an expected call of FromProfile. -func (mr *MocksessionFromProfileProviderMockRecorder) FromProfile(name interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromProfile", reflect.TypeOf((*MocksessionFromProfileProvider)(nil).FromProfile), name) -} - // MocksessionProvider is a mock of sessionProvider interface. type MocksessionProvider struct { ctrl *gomock.Controller @@ -2233,21 +2157,6 @@ func (mr *MocksessionProviderMockRecorder) ConfigFromStaticCreds(accessKeyID, se return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConfigFromStaticCreds", reflect.TypeOf((*MocksessionProvider)(nil).ConfigFromStaticCreds), accessKeyID, secretAccessKey, sessionToken) } -// Default mocks base method. -func (m *MocksessionProvider) Default() (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Default") - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// Default indicates an expected call of Default. -func (mr *MocksessionProviderMockRecorder) Default() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Default", reflect.TypeOf((*MocksessionProvider)(nil).Default)) -} - // DefaultConfig mocks base method. func (m *MocksessionProvider) DefaultConfig(ctx context.Context) (aws.Config, error) { m.ctrl.T.Helper() @@ -2278,66 +2187,6 @@ func (mr *MocksessionProviderMockRecorder) DefaultConfigWithRegion(ctx, region i return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultConfigWithRegion", reflect.TypeOf((*MocksessionProvider)(nil).DefaultConfigWithRegion), ctx, region) } -// DefaultWithRegion mocks base method. -func (m *MocksessionProvider) DefaultWithRegion(region string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "DefaultWithRegion", region) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DefaultWithRegion indicates an expected call of DefaultWithRegion. -func (mr *MocksessionProviderMockRecorder) DefaultWithRegion(region interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DefaultWithRegion", reflect.TypeOf((*MocksessionProvider)(nil).DefaultWithRegion), region) -} - -// FromProfile mocks base method. -func (m *MocksessionProvider) FromProfile(name string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromProfile", name) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FromProfile indicates an expected call of FromProfile. -func (mr *MocksessionProviderMockRecorder) FromProfile(name interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromProfile", reflect.TypeOf((*MocksessionProvider)(nil).FromProfile), name) -} - -// FromRole mocks base method. -func (m *MocksessionProvider) FromRole(roleARN, region string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromRole", roleARN, region) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FromRole indicates an expected call of FromRole. -func (mr *MocksessionProviderMockRecorder) FromRole(roleARN, region interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromRole", reflect.TypeOf((*MocksessionProvider)(nil).FromRole), roleARN, region) -} - -// FromStaticCreds mocks base method. -func (m *MocksessionProvider) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken string) (*session.Session, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "FromStaticCreds", accessKeyID, secretAccessKey, sessionToken) - ret0, _ := ret[0].(*session.Session) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// FromStaticCreds indicates an expected call of FromStaticCreds. -func (mr *MocksessionProviderMockRecorder) FromStaticCreds(accessKeyID, secretAccessKey, sessionToken interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FromStaticCreds", reflect.TypeOf((*MocksessionProvider)(nil).FromStaticCreds), accessKeyID, secretAccessKey, sessionToken) -} - // Mockdescriber is a mock of describer interface. type Mockdescriber struct { ctrl *gomock.Controller diff --git a/internal/pkg/cli/pipeline_delete.go b/internal/pkg/cli/pipeline_delete.go index fdbb0b8a19f..eddb2bb28ff 100644 --- a/internal/pkg/cli/pipeline_delete.go +++ b/internal/pkg/cli/pipeline_delete.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -79,26 +80,22 @@ func newDeletePipelineOpts(vars deletePipelineVars) (*deletePipelineOpts, error) return nil, err } - defaultSess, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline delete")).Default() + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline delete")).DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) - } - ssmStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err + return nil, fmt.Errorf("default config: %w", err) } + ssmStore := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() - v2Config := v2ConfigFromSessionRegion(defaultSess) - codepipeline := codepipeline.New(v2Config, v2Config) - pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) + codepipeline := codepipeline.New(defaultConfig, defaultConfig) + pipelineLister := deploy.NewPipelineStore(rg.New(defaultConfig)) opts := &deletePipelineOpts{ deletePipelineVars: vars, codepipeline: codepipeline, prog: termprogress.NewSpinner(log.DiagnosticWriter), prompt: prompter, - secretsmanager: secretsmanager.New(v2Config), - pipelineDeployer: cloudformation.New(v2ConfigFromSessionRegion(defaultSess), cloudformation.WithProgressTracker(os.Stderr)), + secretsmanager: secretsmanager.New(defaultConfig), + pipelineDeployer: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), deployedPipelineLister: pipelineLister, ws: ws, store: ssmStore, diff --git a/internal/pkg/cli/pipeline_deploy.go b/internal/pkg/cli/pipeline_deploy.go index 2e3b2c11f1c..26c37f4120b 100644 --- a/internal/pkg/cli/pipeline_deploy.go +++ b/internal/pkg/cli/pipeline_deploy.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "encoding/json" "errors" "fmt" @@ -116,15 +117,11 @@ type deployPipelineOpts struct { func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline deploy")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } - v2Config := v2ConfigFromSessionRegion(defaultSession) + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() ws, err := workspace.Use(afero.NewOsFs()) @@ -139,8 +136,8 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) opts := &deployPipelineOpts{ ws: ws, - pipelineDeployer: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), - region: aws.ToString(defaultSession.Config.Region), + pipelineDeployer: deploycfn.New(defaultConfig, deploycfn.WithProgressTracker(os.Stderr)), + region: defaultConfig.Region, deployPipelineVars: vars, store: store, prog: termprogress.NewSpinner(log.DiagnosticWriter), @@ -148,7 +145,7 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) diffWriter: os.Stdout, sessProvider: sessProvider, sel: selector.NewWsPipelineSelector(prompter, ws), - codestar: cs.New(v2Config), + codestar: cs.New(defaultConfig), templateVersion: version.LatestTemplateVersion(), pipelineStackConfig: func(in *deploy.CreatePipelineInput) stackConfiguration { return stack.NewPipelineStackConfig(in) @@ -191,7 +188,7 @@ func newDeployPipelineOpts(vars deployPipelineVars) (*deployPipelineOpts, error) } opts.configureDeployedPipelineLister = func() deployedPipelineLister { // Initialize the client only after the appName is asked. - return deploy.NewPipelineStore(rg.New(v2Config)) + return deploy.NewPipelineStore(rg.New(defaultConfig)) } opts.pipelineVersionGetter = func(appName, name string, isLegacy bool) (versionGetter, error) { return describe.NewPipelineStackDescriber(appName, name, isLegacy) diff --git a/internal/pkg/cli/pipeline_list.go b/internal/pkg/cli/pipeline_list.go index 157915bf4f1..5a78e560143 100644 --- a/internal/pkg/cli/pipeline_list.go +++ b/internal/pkg/cli/pipeline_list.go @@ -61,9 +61,9 @@ func newListPipelinesOpts(vars listPipelineVars) (*listPipelineOpts, error) { return nil, err } - defaultSession, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline ls")).Default() + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline ls")).DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } var wsAppName string @@ -71,15 +71,11 @@ func newListPipelinesOpts(vars listPipelineVars) (*listPipelineOpts, error) { wsAppName = tryReadingAppName() } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } - v2Config := v2ConfigFromSessionRegion(defaultSession) + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &listPipelineOpts{ listPipelineVars: vars, - pipelineLister: deploy.NewPipelineStore(rg.New(v2Config)), + pipelineLister: deploy.NewPipelineStore(rg.New(defaultConfig)), prompt: prompter, sel: selector.NewConfigSelector(prompter, store), store: store, diff --git a/internal/pkg/cli/pipeline_override.go b/internal/pkg/cli/pipeline_override.go index d7f718a23d1..d6d51b08ed0 100644 --- a/internal/pkg/cli/pipeline_override.go +++ b/internal/pkg/cli/pipeline_override.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "slices" @@ -33,16 +34,13 @@ func newOverridePipelineOpts(vars overrideVars) (*overridePipelineOpts, error) { } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline override")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } prompt := prompt.New() - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) cmd := &overridePipelineOpts{ overrideOpts: &overrideOpts{ diff --git a/internal/pkg/cli/pipeline_package.go b/internal/pkg/cli/pipeline_package.go index 9f672accaec..3b56c165591 100644 --- a/internal/pkg/cli/pipeline_package.go +++ b/internal/pkg/cli/pipeline_package.go @@ -5,6 +5,7 @@ package cli import ( "bytes" + "context" "encoding/json" "fmt" "io" @@ -55,15 +56,11 @@ type packagePipelineOpts struct { func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline package")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } - v2Config := v2ConfigFromSessionRegion(defaultSession) + store := newSSMConfigStoreFromConfig(defaultConfig) ws, err := workspace.Use(afero.NewOsFs()) if err != nil { @@ -71,7 +68,7 @@ func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, err } opts := &packagePipelineOpts{ packagePipelineVars: vars, - pipelineDeployer: deploycfn.New(v2ConfigFromSessionRegion(defaultSession), deploycfn.WithProgressTracker(os.Stderr)), + pipelineDeployer: deploycfn.New(defaultConfig, deploycfn.WithProgressTracker(os.Stderr)), tmplWriter: os.Stdout, ws: ws, store: store, @@ -114,7 +111,7 @@ func newPackagePipelineOpts(vars packagePipelineVars) (*packagePipelineOpts, err svcBuffer: &bytes.Buffer{}, jobBuffer: &bytes.Buffer{}, configureDeployedPipelineLister: func() deployedPipelineLister { - return deploy.NewPipelineStore(rg.New(v2Config)) + return deploy.NewPipelineStore(rg.New(defaultConfig)) }, } return opts, nil diff --git a/internal/pkg/cli/pipeline_show.go b/internal/pkg/cli/pipeline_show.go index c09b4be7d2f..3f9bb1b3828 100644 --- a/internal/pkg/cli/pipeline_show.go +++ b/internal/pkg/cli/pipeline_show.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "io" @@ -60,17 +61,13 @@ func newShowPipelineOpts(vars showPipelineVars) (*showPipelineOpts, error) { return nil, err } - defaultSession, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline show")).Default() + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline show")).DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } - v2Config := v2ConfigFromSessionRegion(defaultSession) - codepipeline := codepipeline.New(v2Config, v2Config) - pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) + store := newSSMConfigStoreFromConfig(defaultConfig) + codepipeline := codepipeline.New(defaultConfig, defaultConfig) + pipelineLister := deploy.NewPipelineStore(rg.New(defaultConfig)) prompter := prompt.New() opts := &showPipelineOpts{ showPipelineVars: vars, diff --git a/internal/pkg/cli/pipeline_status.go b/internal/pkg/cli/pipeline_status.go index 304007eafc0..1559031e744 100644 --- a/internal/pkg/cli/pipeline_status.go +++ b/internal/pkg/cli/pipeline_status.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "io" @@ -59,17 +60,13 @@ func newPipelineStatusOpts(vars pipelineStatusVars) (*pipelineStatusOpts, error) return nil, err } - session, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline status")).Default() + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("pipeline status")).DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("session: %w", err) + return nil, fmt.Errorf("default config: %w", err) } - store, err := newSSMConfigStore(session) - if err != nil { - return nil, err - } - v2Config := v2ConfigFromSessionRegion(session) - codepipeline := codepipeline.New(v2Config, v2Config) - pipelineLister := deploy.NewPipelineStore(rg.New(v2Config)) + store := newSSMConfigStoreFromConfig(defaultConfig) + codepipeline := codepipeline.New(defaultConfig, defaultConfig) + pipelineLister := deploy.NewPipelineStore(rg.New(defaultConfig)) prompter := prompt.New() return &pipelineStatusOpts{ w: log.OutputWriter, diff --git a/internal/pkg/cli/secret_init.go b/internal/pkg/cli/secret_init.go index 822b0444e35..f58373b75d1 100644 --- a/internal/pkg/cli/secret_init.go +++ b/internal/pkg/cli/secret_init.go @@ -73,7 +73,7 @@ type secretInitOpts struct { func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("secret init")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } @@ -83,10 +83,7 @@ func newSecretInitOpts(vars secretInitVars) (*secretInitOpts, error) { return nil, err } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() opts := secretInitOpts{ secretInitVars: vars, diff --git a/internal/pkg/cli/storage_init.go b/internal/pkg/cli/storage_init.go index 56946dc182a..cfc6fe62177 100644 --- a/internal/pkg/cli/storage_init.go +++ b/internal/pkg/cli/storage_init.go @@ -4,6 +4,7 @@ package cli import ( + "context" "encoding" "errors" "fmt" @@ -187,7 +188,7 @@ type initStorageOpts struct { func newStorageInitOpts(vars initStorageVars) (*initStorageOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("storage init")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } @@ -198,10 +199,7 @@ func newStorageInitOpts(vars initStorageVars) (*initStorageOpts, error) { return nil, err } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &initStorageOpts{ initStorageVars: vars, diff --git a/internal/pkg/cli/svc_delete.go b/internal/pkg/cli/svc_delete.go index 696908a49f7..911a9fc00e8 100644 --- a/internal/pkg/cli/svc_delete.go +++ b/internal/pkg/cli/svc_delete.go @@ -74,15 +74,12 @@ type deleteSvcOpts struct { func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc delete")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() opts := &deleteSvcOpts{ deleteSvcVars: vars, @@ -92,7 +89,7 @@ func newDeleteSvcOpts(vars deleteSvcVars) (*deleteSvcOpts, error) { prompt: prompter, sess: sessProvider, sel: selector.NewConfigSelector(prompter, store), - appCFN: cloudformation.New(v2ConfigFromSessionRegion(defaultSession), cloudformation.WithProgressTracker(os.Stderr)), + appCFN: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), getSvcCFN: func(cfg aws.Config) wlDeleter { return cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) }, diff --git a/internal/pkg/cli/svc_deploy.go b/internal/pkg/cli/svc_deploy.go index 65399f7ffdd..9af714f216c 100644 --- a/internal/pkg/cli/svc_deploy.go +++ b/internal/pkg/cli/svc_deploy.go @@ -99,15 +99,12 @@ func newSvcDeployOpts(vars deployWkldVars) (*deploySvcOpts, error) { } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc deploy")) - defaultSession, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } - store, err := newSSMConfigStore(defaultSession) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() opts := &deploySvcOpts{ diff --git a/internal/pkg/cli/svc_exec.go b/internal/pkg/cli/svc_exec.go index b3df4f1541b..246b0221f59 100644 --- a/internal/pkg/cli/svc_exec.go +++ b/internal/pkg/cli/svc_exec.go @@ -58,14 +58,11 @@ type svcExecOpts struct { func newSvcExecOpts(vars execVars) (*svcExecOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc exec")) - defaultSession, err := sessProvider.Default() - if err != nil { - return nil, err - } - ssmStore, err := newSSMConfigStore(defaultSession) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + ssmStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, ssmStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/svc_init.go b/internal/pkg/cli/svc_init.go index b9fb0cf2a8d..b2e71b96392 100644 --- a/internal/pkg/cli/svc_init.go +++ b/internal/pkg/cli/svc_init.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "os" @@ -188,14 +189,11 @@ func newInitSvcOpts(vars initSvcVars) (*initSvcOpts, error) { return nil, err } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc init")) - sess, err := sessProvider.Default() - if err != nil { - return nil, err - } - store, err := newSSMConfigStore(sess) + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { return nil, err } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() deployStore, err := deploy.NewStore(sessProvider, store) if err != nil { @@ -207,7 +205,7 @@ func newInitSvcOpts(vars initSvcVars) (*initSvcOpts, error) { Store: store, Ws: ws, Prog: termprogress.NewSpinner(log.DiagnosticWriter), - Deployer: cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)), + Deployer: cloudformation.New(defaultConfig, cloudformation.WithProgressTracker(os.Stderr)), } dfSel, err := selector.NewDockerfileSelector(prompter, fs) if err != nil { diff --git a/internal/pkg/cli/svc_list.go b/internal/pkg/cli/svc_list.go index 8f1cf6e2be5..4904155174e 100644 --- a/internal/pkg/cli/svc_list.go +++ b/internal/pkg/cli/svc_list.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "os" @@ -37,15 +38,12 @@ func newListSvcOpts(vars listWkldVars) (*listSvcOpts, error) { return nil, err } - sess, err := sessions.ImmutableProvider(sessions.UserAgentExtras("svc ls")).Default() + defaultConfig, err := sessions.ImmutableProvider(sessions.UserAgentExtras("svc ls")).DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - store, err := newSSMConfigStore(sess) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) svcLister := &list.SvcListWriter{ Ws: ws, Store: store, diff --git a/internal/pkg/cli/svc_logs.go b/internal/pkg/cli/svc_logs.go index ee2eed39607..d6285048255 100644 --- a/internal/pkg/cli/svc_logs.go +++ b/internal/pkg/cli/svc_logs.go @@ -88,15 +88,12 @@ type wkldLogOpts struct { func newSvcLogOpts(vars svcLogsVars) (*svcLogsOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc logs")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - configStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + configStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/svc_override.go b/internal/pkg/cli/svc_override.go index efb9ecf8eeb..37bb4ef2014 100644 --- a/internal/pkg/cli/svc_override.go +++ b/internal/pkg/cli/svc_override.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "slices" @@ -40,14 +41,11 @@ func newOverrideWorkloadOpts(vars overrideWorkloadVars) (*overrideWorkloadOpts, } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc override")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) - } - cfgStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err + return nil, fmt.Errorf("default config: %v", err) } + cfgStore := newSSMConfigStoreFromConfig(defaultConfig) vars.requiresEnv = true prompt := prompt.New() cmd := &overrideWorkloadOpts{ diff --git a/internal/pkg/cli/svc_package.go b/internal/pkg/cli/svc_package.go index cd8682926d4..79b2c8818b6 100644 --- a/internal/pkg/cli/svc_package.go +++ b/internal/pkg/cli/svc_package.go @@ -90,15 +90,12 @@ func newPackageSvcOpts(vars packageSvcVars) (*packageSvcOpts, error) { } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc package")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() opts := &packageSvcOpts{ packageSvcVars: vars, diff --git a/internal/pkg/cli/svc_pause.go b/internal/pkg/cli/svc_pause.go index aa3981d7f24..5d76ffbdc6e 100644 --- a/internal/pkg/cli/svc_pause.go +++ b/internal/pkg/cli/svc_pause.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" @@ -56,15 +57,12 @@ type svcPauseOpts struct { func newSvcPauseOpts(vars svcPauseVars) (*svcPauseOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc pause")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - configStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + configStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) @@ -89,11 +87,11 @@ func newSvcPauseOpts(vars svcPauseVars) (*svcPauseOpts, error) { if wl.Type != manifestinfo.RequestDrivenWebServiceType { return fmt.Errorf("pausing a service is only supported for services with type: %s", manifestinfo.RequestDrivenWebServiceType) } - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } - opts.client = apprunner.New(v2ConfigFromSessionRegion(sess)) + opts.client = apprunner.New(cfg) d, err := describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ App: opts.appName, Svc: opts.svcName, diff --git a/internal/pkg/cli/svc_resume.go b/internal/pkg/cli/svc_resume.go index ee78f8e94cd..1af64552994 100644 --- a/internal/pkg/cli/svc_resume.go +++ b/internal/pkg/cli/svc_resume.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "github.com/aproint/copilot-cli/internal/pkg/manifest/manifestinfo" @@ -128,15 +129,12 @@ func (o *resumeSvcOpts) validateAndAskSvcEnvName() error { func newResumeSvcOpts(vars resumeSvcVars) (*resumeSvcOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc resume")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - configStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + configStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) @@ -161,11 +159,11 @@ func newResumeSvcOpts(vars resumeSvcVars) (*resumeSvcOpts, error) { } switch svc.Type { case manifestinfo.RequestDrivenWebServiceType: - sess, err := sessProvider.FromRole(env.ManagerRoleARN, env.Region) + cfg, err := sessProvider.ConfigFromRole(context.Background(), env.ManagerRoleARN, env.Region) if err != nil { return err } - a = apprunner.New(v2ConfigFromSessionRegion(sess)) + a = apprunner.New(cfg) d, err = describe.NewRDWebServiceDescriber(describe.NewServiceConfig{ App: opts.appName, Svc: opts.svcName, diff --git a/internal/pkg/cli/svc_show.go b/internal/pkg/cli/svc_show.go index aef8188c16b..396f1927bb7 100644 --- a/internal/pkg/cli/svc_show.go +++ b/internal/pkg/cli/svc_show.go @@ -4,6 +4,7 @@ package cli import ( + "context" "errors" "fmt" "io" @@ -51,15 +52,12 @@ type showSvcOpts struct { func newShowSvcOpts(vars showSvcVars) (*showSvcOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc show")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - ssmStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + ssmStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, ssmStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/svc_status.go b/internal/pkg/cli/svc_status.go index a94fb4bef41..b7868e62595 100644 --- a/internal/pkg/cli/svc_status.go +++ b/internal/pkg/cli/svc_status.go @@ -4,6 +4,7 @@ package cli import ( + "context" "fmt" "io" @@ -42,15 +43,12 @@ type svcStatusOpts struct { func newSvcStatusOpts(vars svcStatusVars) (*svcStatusOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("svc status")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - configStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + configStore := newSSMConfigStoreFromConfig(defaultConfig) deployStore, err := deploy.NewStore(sessProvider, configStore) if err != nil { return nil, fmt.Errorf("connect to deploy store: %w", err) diff --git a/internal/pkg/cli/task_delete.go b/internal/pkg/cli/task_delete.go index 9c312c7872f..30ae0be4c8d 100644 --- a/internal/pkg/cli/task_delete.go +++ b/internal/pkg/cli/task_delete.go @@ -79,15 +79,12 @@ func newDeleteTaskOpts(vars deleteTaskVars) (*deleteTaskOpts, error) { } sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("task delete")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &deleteTaskOpts{ deleteTaskVars: vars, diff --git a/internal/pkg/cli/task_exec.go b/internal/pkg/cli/task_exec.go index cbaddebe545..4fa9cfe1876 100644 --- a/internal/pkg/cli/task_exec.go +++ b/internal/pkg/cli/task_exec.go @@ -55,15 +55,12 @@ type taskExecOpts struct { func newTaskExecOpts(vars taskExecVars) (*taskExecOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("task exec")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } - ssmStore, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + ssmStore := newSSMConfigStoreFromConfig(defaultConfig) prompter := prompt.New() return &taskExecOpts{ taskExecVars: vars, diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index 539e24ed83a..dc35eea62b5 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -188,16 +188,13 @@ type runTaskOpts struct { func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { sessProvider := sessions.ImmutableProvider(sessions.UserAgentExtras("task run")) - defaultSess, err := sessProvider.Default() + defaultConfig, err := sessProvider.DefaultConfig(context.Background()) if err != nil { - return nil, fmt.Errorf("default session: %v", err) + return nil, fmt.Errorf("default config: %v", err) } prompter := prompt.New() - store, err := newSSMConfigStore(defaultSess) - if err != nil { - return nil, err - } + store := newSSMConfigStoreFromConfig(defaultConfig) opts := runTaskOpts{ runTaskVars: vars, diff --git a/internal/pkg/config/store_integration_test.go b/internal/pkg/config/store_integration_test.go index 2e9422cdc66..2984149bd6c 100644 --- a/internal/pkg/config/store_integration_test.go +++ b/internal/pkg/config/store_integration_test.go @@ -6,13 +6,13 @@ package config_test import ( + "context" "math/rand" "testing" "time" "github.com/aproint/copilot-cli/internal/pkg/aws/identity" "github.com/aproint/copilot-cli/internal/pkg/aws/sessions" - "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/ssm" "github.com/aproint/copilot-cli/internal/pkg/config" @@ -24,10 +24,10 @@ func init() { } func Test_SSM_Application_Integration(t *testing.T) { - defaultSess, err := sessions.ImmutableProvider().Default() + defaultConfig, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store := config.NewSSMStore(identity.New(defaultConfig), ssm.NewFromConfig(defaultConfig), defaultConfig.Region) applicationToCreate := config.Application{Name: randStringBytes(10), Version: "1.0"} defer store.DeleteApplication(applicationToCreate.Name) @@ -53,10 +53,10 @@ func Test_SSM_Application_Integration(t *testing.T) { } func Test_SSM_Environment_Integration(t *testing.T) { - defaultSess, err := sessions.ImmutableProvider().Default() + defaultConfig, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store := config.NewSSMStore(identity.New(defaultConfig), ssm.NewFromConfig(defaultConfig), defaultConfig.Region) applicationToCreate := config.Application{Name: randStringBytes(10), Version: "1.0"} testEnvironment := config.Environment{Name: "test", App: applicationToCreate.Name, Region: "us-west-2", AccountID: " 1234"} prodEnvironment := config.Environment{Name: "prod", App: applicationToCreate.Name, Region: "us-west-2", AccountID: " 1234"} @@ -111,10 +111,10 @@ func Test_SSM_Environment_Integration(t *testing.T) { } func Test_SSM_Service_Integration(t *testing.T) { - defaultSess, err := sessions.ImmutableProvider().Default() + defaultConfig, err := sessions.ImmutableProvider().DefaultConfig(context.Background()) require.NoError(t, err) - store := config.NewSSMStore(identity.New(defaultSess), ssm.New(defaultSess), aws.StringValue(defaultSess.Config.Region)) + store := config.NewSSMStore(identity.New(defaultConfig), ssm.NewFromConfig(defaultConfig), defaultConfig.Region) applicationToCreate := config.Application{Name: randStringBytes(10), Version: "1.0"} apiService := config.Workload{Name: "api", App: applicationToCreate.Name, Type: "Load Balanced Web Service"} feService := config.Workload{Name: "front-end", App: applicationToCreate.Name, Type: "Load Balanced Web Service"} diff --git a/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go b/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go index 196c02f67d3..38ea750f180 100644 --- a/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go +++ b/internal/pkg/deploy/cloudformation/cloudformation_integration_test.go @@ -7,6 +7,7 @@ package cloudformation_test import ( "context" + "errors" "fmt" "io" "math/rand" @@ -29,13 +30,10 @@ import ( "github.com/aproint/copilot-cli/internal/pkg/template" "github.com/aproint/copilot-cli/internal/pkg/version" "github.com/aws/aws-sdk-go-v2/aws" + awsCF "github.com/aws/aws-sdk-go-v2/service/cloudformation" "github.com/aws/aws-sdk-go-v2/service/cloudformation/types" - awsv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/aws/session" - awsCF "github.com/aws/aws-sdk-go/service/cloudformation" - "github.com/aws/aws-sdk-go/service/s3" - "github.com/aws/aws-sdk-go/service/s3/s3manager" + "github.com/aws/aws-sdk-go-v2/service/s3" + "github.com/aws/smithy-go" "github.com/stretchr/testify/require" ) @@ -45,19 +43,55 @@ const ( fmtEnvManagerRoleID = "%s-%s-EnvManagerRole" ) +type cfnClient struct { + client *awsCF.Client +} + +func newCFNClient(cfg aws.Config) *cfnClient { + return &cfnClient{client: awsCF.NewFromConfig(cfg)} +} + +func (c *cfnClient) DescribeStacks(input *awsCF.DescribeStacksInput) (*awsCF.DescribeStacksOutput, error) { + return c.client.DescribeStacks(context.Background(), input) +} + +func (c *cfnClient) DeleteStack(input *awsCF.DeleteStackInput) (*awsCF.DeleteStackOutput, error) { + return c.client.DeleteStack(context.Background(), input) +} + +func (c *cfnClient) DeleteStackSet(input *awsCF.DeleteStackSetInput) (*awsCF.DeleteStackSetOutput, error) { + return c.client.DeleteStackSet(context.Background(), input) +} + +func (c *cfnClient) DescribeStackSet(input *awsCF.DescribeStackSetInput) (*awsCF.DescribeStackSetOutput, error) { + return c.client.DescribeStackSet(context.Background(), input) +} + +func (c *cfnClient) ListStackInstances(input *awsCF.ListStackInstancesInput) (*awsCF.ListStackInstancesOutput, error) { + return c.client.ListStackInstances(context.Background(), input) +} + +func (c *cfnClient) DeleteStackInstances(input *awsCF.DeleteStackInstancesInput) (*awsCF.DeleteStackInstancesOutput, error) { + return c.client.DeleteStackInstances(context.Background(), input) +} + +func (c *cfnClient) WaitUntilStackDeleteComplete(input *awsCF.DescribeStacksInput) error { + return awsCF.NewStackDeleteCompleteWaiter(c.client).Wait(context.Background(), input, 10*time.Minute) +} + func init() { rand.Seed(time.Now().UnixNano()) } func Test_App_Infrastructure(t *testing.T) { - sess, err := testSession(nil) + cfg, err := testConfig(nil) require.NoError(t, err) - identity := identity.New(v2ConfigFromSessionRegion(sess)) + identity := identity.New(cfg) callerInfo, err := identity.Get() require.NoError(t, err) require.NoError(t, err) - deployer := cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)) - cfClient := awsCF.New(sess) + deployer := cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) + cfClient := newCFNClient(cfg) require.NoError(t, err) version.Version = "v1.28.0" @@ -114,18 +148,18 @@ func Test_App_Infrastructure(t *testing.T) { require.True(t, len(roleStackOutput.Stacks) == 1, "Stack %s should have been deployed.", appRoleStackName) deployedStack := roleStackOutput.Stacks[0] - expectedResultsForKey := map[string]func(*awsCF.Output){ - "ExecutionRoleARN": func(output *awsCF.Output) { + expectedResultsForKey := map[string]func(types.Output){ + "ExecutionRoleARN": func(output types.Output) { require.True(t, strings.HasSuffix(*output.OutputValue, fmt.Sprintf("role/%s-executionrole", app.Name)), fmt.Sprintf("ExecutionRoleARN should be named {app}-executionrole but was %s", *output.OutputValue)) }, - "AdministrationRoleARN": func(output *awsCF.Output) { + "AdministrationRoleARN": func(output types.Output) { require.True(t, strings.HasSuffix(*output.OutputValue, fmt.Sprintf("role/%s-adminrole", app.Name)), fmt.Sprintf("AdministrationRoleARN should be named {app}-adminrole but was %s", *output.OutputValue)) }, - "TemplateVersion": func(output *awsCF.Output) { + "TemplateVersion": func(output types.Output) { require.Equal(t, *output.OutputValue, version.LatestTemplateVersion(), fmt.Sprintf("TemplateVersion should be %s but was %s", version.LatestTemplateVersion(), *output.OutputValue)) }, @@ -134,7 +168,7 @@ func Test_App_Infrastructure(t *testing.T) { "There should have been %d output values - instead there were %d. The value of the CF stack was %s", len(expectedResultsForKey), len(deployedStack.Outputs), - deployedStack.GoString(), + fmt.Sprintf("%+v", deployedStack), ) for _, output := range deployedStack.Outputs { key := *output.OutputKey @@ -154,11 +188,11 @@ func Test_App_Infrastructure(t *testing.T) { // Clean up any StackInstances we may have created. if stackInstances, err := cfClient.ListStackInstances(&awsCF.ListStackInstancesInput{ StackSetName: aws.String(appStackSetName), - }); err == nil && stackInstances.Summaries != nil && stackInstances.Summaries[0] != nil { + }); err == nil && len(stackInstances.Summaries) > 0 { appStackInstance := stackInstances.Summaries[0] cfClient.DeleteStackInstances(&awsCF.DeleteStackInstancesInput{ - Accounts: []*string{appStackInstance.Account}, - Regions: []*string{appStackInstance.Region}, + Accounts: []string{aws.ToString(appStackInstance.Account)}, + Regions: []string{aws.ToString(appStackInstance.Region)}, RetainStacks: aws.Bool(false), StackSetName: appStackInstance.StackSetId, }) @@ -220,7 +254,7 @@ func Test_App_Infrastructure(t *testing.T) { App: &app, EnvName: "test", EnvAccountID: callerInfo.Account, - EnvRegion: *sess.Config.Region, + EnvRegion: cfg.Region, }, ) require.NoError(t, err) @@ -250,33 +284,33 @@ func Test_App_Infrastructure(t *testing.T) { require.NoError(t, err) deployedStack := appInfraStacks.Stacks[0] - expectedResultsForKey := map[string]func(*awsCF.Output){ - "KMSKeyARN": func(output *awsCF.Output) { + expectedResultsForKey := map[string]func(types.Output){ + "KMSKeyARN": func(output types.Output) { require.NotNil(t, *output.OutputValue, "KMSKeyARN should not be nil") }, - "PipelineBucket": func(output *awsCF.Output) { + "PipelineBucket": func(output types.Output) { require.NotNil(t, *output.OutputValue, "PipelineBucket should not be nil") }, - "TemplateVersion": func(output *awsCF.Output) { + "TemplateVersion": func(output types.Output) { require.Equal(t, *output.OutputValue, version.LatestTemplateVersion(), fmt.Sprintf("TemplateVersion should be %s but was %s", version.LatestTemplateVersion(), *output.OutputValue)) }, - "ECRRepomysvc": func(output *awsCF.Output) { + "ECRRepomysvc": func(output types.Output) { require.True(t, strings.HasSuffix(*output.OutputValue, fmt.Sprintf("repository/%s/mysvc", app.Name)), fmt.Sprintf("ECRRepomysvc should be suffixed with repository/{app}/mysvc but was %s", *output.OutputValue)) }, // We replace dashes with the word DASH for logical IDss - "ECRRepomysvcDASHfrontend": func(output *awsCF.Output) { + "ECRRepomysvcDASHfrontend": func(output types.Output) { require.True(t, strings.HasSuffix(*output.OutputValue, fmt.Sprintf("repository/%s/mysvc-frontend", app.Name)), fmt.Sprintf("ECRRepomysvcDASHfrontend should be suffixed with repository/{app}/mysvc but was %s", *output.OutputValue)) }, - "StackSetOpId": func(output *awsCF.Output) { + "StackSetOpId": func(output types.Output) { opID, err := strconv.Atoi(*output.OutputValue) require.NoError(t, err) require.GreaterOrEqual(t, opID, 1, @@ -287,7 +321,7 @@ func Test_App_Infrastructure(t *testing.T) { "There should have been %d output values - instead there were %d. The value of the CF stack was %s", len(expectedResultsForKey), len(deployedStack.Outputs), - deployedStack.GoString(), + fmt.Sprintf("%+v", deployedStack), ) for _, output := range deployedStack.Outputs { key := *output.OutputKey @@ -307,11 +341,11 @@ func Test_App_Infrastructure(t *testing.T) { // Clean up any StackInstances we may have created. if stackInstances, err := cfClient.ListStackInstances(&awsCF.ListStackInstancesInput{ StackSetName: aws.String(appStackSetName), - }); err == nil && stackInstances.Summaries != nil && stackInstances.Summaries[0] != nil { + }); err == nil && len(stackInstances.Summaries) > 0 { appStackInstance := stackInstances.Summaries[0] cfClient.DeleteStackInstances(&awsCF.DeleteStackInstancesInput{ - Accounts: []*string{appStackInstance.Account}, - Regions: []*string{appStackInstance.Region}, + Accounts: []string{aws.ToString(appStackInstance.Account)}, + Regions: []string{aws.ToString(appStackInstance.Region)}, RetainStacks: aws.Bool(false), StackSetName: appStackInstance.StackSetId, }) @@ -335,10 +369,10 @@ func Test_App_Infrastructure(t *testing.T) { StackName: aws.String(appRoleStackName), }) require.Error(t, err, "DescribeStacks should return an error because the stack does not exist") - awsErr, ok := err.(awserr.Error) - require.True(t, ok, "the returned error should be an awserr") - require.Equal(t, awsErr.Code(), "ValidationError") - require.Contains(t, awsErr.Message(), "does not exist", "the returned error should indicate that the stack does not exist") + var apiErr smithy.APIError + require.True(t, errors.As(err, &apiErr), "the returned error should be an API error") + require.Equal(t, "ValidationError", apiErr.ErrorCode()) + require.Contains(t, apiErr.ErrorMessage(), "does not exist", "the returned error should indicate that the stack does not exist") // create a stackset err = deployer.DeployApp(&deploy.CreateAppInput{ @@ -349,12 +383,12 @@ func Test_App_Infrastructure(t *testing.T) { require.NoError(t, err) // Add resources needed to support a pipeline in a region - err = deployer.AddPipelineResourcesToApp(&app, *sess.Config.Region) + err = deployer.AddPipelineResourcesToApp(&app, cfg.Region) require.NoError(t, err) // Add another pipeline to the same application and region. This should not create // Additional stack instance - err = deployer.AddPipelineResourcesToApp(&app, *sess.Config.Region) + err = deployer.AddPipelineResourcesToApp(&app, cfg.Region) require.NoError(t, err) stackInstances, err := cfClient.ListStackInstances(&awsCF.ListStackInstancesInput{ @@ -368,7 +402,7 @@ func Test_App_Infrastructure(t *testing.T) { App: &app, EnvName: "test", EnvAccountID: callerInfo.Account, - EnvRegion: *sess.Config.Region, + EnvRegion: cfg.Region, }) require.NoError(t, err) @@ -394,16 +428,14 @@ func Test_App_Infrastructure(t *testing.T) { // switching your default region by running aws configure. func Test_Environment_Deployment_Integration(t *testing.T) { version.Version = "v1.28.0" - sess, err := testSession(nil) + cfg, err := testConfig(nil) require.NoError(t, err) - deployer := cloudformation.New(v2ConfigFromSessionRegion(sess), cloudformation.WithProgressTracker(os.Stderr)) - cfClient := awsCF.New(sess) - identity := identity.New(v2ConfigFromSessionRegion(sess)) - s3ManagerClient := s3manager.NewUploader(sess) - s3Config, err := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(sess.Config.Region)) - require.NoError(t, err) - s3Client := awss3.New(s3Config) - iamClient := iam.New(v2ConfigFromSessionRegion(sess)) + deployer := cloudformation.New(cfg, cloudformation.WithProgressTracker(os.Stderr)) + cfClient := newCFNClient(cfg) + identity := identity.New(cfg) + s3APIClient := s3.NewFromConfig(cfg) + s3Client := awss3.New(cfg) + iamClient := iam.New(cfg) id, err := identity.Get() require.NoError(t, err) @@ -428,7 +460,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { require.True(t, len(output.Stacks) == 0, "Stack %s should not exist.", envStackName) // Create a temporary S3 bucket to store custom resource scripts. - _, err = s3ManagerClient.S3.CreateBucket(&s3.CreateBucketInput{ + _, err = s3APIClient.CreateBucket(context.Background(), &s3.CreateBucketInput{ Bucket: aws.String(bucketName), }) require.NoError(t, err) @@ -445,7 +477,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { err = s3Client.EmptyBucket(bucketName) require.NoError(t, err) - _, err = s3ManagerClient.S3.DeleteBucket(&s3.DeleteBucketInput{ + _, err = s3APIClient.DeleteBucket(context.Background(), &s3.DeleteBucketInput{ Bucket: aws.String(bucketName), }) require.NoError(t, err) @@ -467,8 +499,8 @@ func Test_Environment_Deployment_Integration(t *testing.T) { require.True(t, len(output.Stacks) == 1, "Stack %s should have been deployed.", envStackName) deployedStack := output.Stacks[0] - expectedResultsForKey := map[string]func(*awsCF.Output){ - "EnvironmentManagerRoleARN": func(output *awsCF.Output) { + expectedResultsForKey := map[string]func(types.Output){ + "EnvironmentManagerRoleARN": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-EnvironmentManagerRoleARN", envStackName), *output.ExportName, @@ -478,7 +510,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { strings.HasSuffix(*output.OutputValue, fmt.Sprintf("role/%s-EnvManagerRole", envStackName)), "EnvironmentManagerRole ARN value should not be nil.") }, - "CFNExecutionRoleARN": func(output *awsCF.Output) { + "CFNExecutionRoleARN": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-CFNExecutionRoleARN", envStackName), *output.ExportName, @@ -493,7 +525,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { "There should have been %d output values - instead there were %d. The value of the CF stack was %s", len(expectedResultsForKey), len(deployedStack.Outputs), - deployedStack.GoString(), + fmt.Sprintf("%+v", deployedStack), ) for _, output := range deployedStack.Outputs { key := *output.OutputKey @@ -538,11 +570,11 @@ func Test_Environment_Deployment_Integration(t *testing.T) { require.True(t, len(output.Stacks) == 1, "Stack %s should have been deployed.", envStackName) deployedStack := output.Stacks[0] - expectedResultsForKey := map[string]func(*awsCF.Output){ - "EnabledFeatures": func(output *awsCF.Output) { + expectedResultsForKey := map[string]func(types.Output){ + "EnabledFeatures": func(output types.Output) { require.Equal(t, ",,,,,", aws.ToString(output.OutputValue), "no env features enabled by default") }, - "EnvironmentManagerRoleARN": func(output *awsCF.Output) { + "EnvironmentManagerRoleARN": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-EnvironmentManagerRoleARN", envStackName), *output.ExportName, @@ -552,7 +584,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { strings.HasSuffix(*output.OutputValue, fmt.Sprintf("role/%s-EnvManagerRole", envStackName)), "EnvironmentManagerRole ARN value should not be nil.") }, - "CFNExecutionRoleARN": func(output *awsCF.Output) { + "CFNExecutionRoleARN": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-CFNExecutionRoleARN", envStackName), *output.ExportName, @@ -562,7 +594,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { strings.HasSuffix(*output.OutputValue, fmt.Sprintf("role/%s-CFNExecutionRole", envStackName)), "CRNExecutionRole ARN value should not be nil.") }, - "ClusterId": func(output *awsCF.Output) { + "ClusterId": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-ClusterId", envStackName), *output.ExportName, @@ -572,7 +604,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "Cluster value should not be nil") }, - "PrivateSubnets": func(output *awsCF.Output) { + "PrivateSubnets": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-PrivateSubnets", envStackName), *output.ExportName, @@ -582,7 +614,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "Private Subnet values should not be nil") }, - "VpcId": func(output *awsCF.Output) { + "VpcId": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-VpcId", envStackName), *output.ExportName, @@ -592,7 +624,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "VpcId value should not be nil") }, - "PublicSubnets": func(output *awsCF.Output) { + "PublicSubnets": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-PublicSubnets", envStackName), *output.ExportName, @@ -602,7 +634,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "PublicSubnets value should not be nil") }, - "ServiceDiscoveryNamespaceID": func(output *awsCF.Output) { + "ServiceDiscoveryNamespaceID": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-ServiceDiscoveryNamespaceID", envStackName), *output.ExportName, @@ -612,7 +644,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "ServiceDiscoveryNamespaceID value should not be nil") }, - "InternetGatewayID": func(output *awsCF.Output) { + "InternetGatewayID": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-InternetGatewayID", envStackName), *output.ExportName, @@ -622,7 +654,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "InternetGatewayID value should not be nil") }, - "PublicRouteTableID": func(output *awsCF.Output) { + "PublicRouteTableID": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-PublicRouteTableID", envStackName), *output.ExportName, @@ -632,7 +664,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "PublicRouteTableID value should not be nil") }, - "EnvironmentSecurityGroup": func(output *awsCF.Output) { + "EnvironmentSecurityGroup": func(output types.Output) { require.Equal(t, fmt.Sprintf("%s-EnvironmentSecurityGroup", envStackName), *output.ExportName, @@ -642,7 +674,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { output.OutputValue, "EnvironmentSecurityGroup value should not be nil") }, - "LastForceDeployID": func(output *awsCF.Output) { + "LastForceDeployID": func(output types.Output) { require.Equal(t, lastForceUpdateID, aws.ToString(output.OutputValue), "last force update id does not change by default") }, } @@ -650,7 +682,7 @@ func Test_Environment_Deployment_Integration(t *testing.T) { "There should have been %d output values - instead there were %d. The value of the CF stack was %s", len(expectedResultsForKey), len(deployedStack.Outputs), - deployedStack.GoString(), + fmt.Sprintf("%+v", deployedStack), ) for _, output := range deployedStack.Outputs { key := *output.OutputKey @@ -663,26 +695,13 @@ func Test_Environment_Deployment_Integration(t *testing.T) { const letterBytes = "abcdefghijklmnopqrstuvwxyz" -func testSession(region *string) (*session.Session, error) { +func testConfig(region *string) (aws.Config, error) { if region == nil { - return session.NewSessionWithOptions(session.Options{ - SharedConfigState: session.SharedConfigEnable, - }) + return sessions.ImmutableProvider().DefaultConfig(context.Background()) } // override with the provided region - return session.NewSessionWithOptions(session.Options{ - Config: awsv1.Config{ - CredentialsChainVerboseErrors: awsv1.Bool(true), - Region: region, - }, - SharedConfigState: session.SharedConfigEnable, - }) -} - -func v2ConfigFromSessionRegion(sess *session.Session) aws.Config { - cfg, _ := sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(sess.Config.Region)) - return cfg + return sessions.ImmutableProvider().DefaultConfigWithRegion(context.Background(), aws.ToString(region)) } func parameterPtrs(params []types.Parameter) []*types.Parameter { From 8f1ad511ee59bfaf0ece533ed4b4643c6631acfb Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 16:27:01 +0200 Subject: [PATCH 12/17] remove v1 from mod/sum --- go.mod | 1 - go.sum | 2 -- 2 files changed, 3 deletions(-) diff --git a/go.mod b/go.mod index f41385672ce..cec43da4089 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,6 @@ toolchain go1.26.0 require ( github.com/AlecAivazis/survey/v2 v2.3.2 - github.com/aws/aws-sdk-go v1.55.5 github.com/aws/aws-sdk-go-v2 v1.42.1 github.com/aws/aws-sdk-go-v2/config v1.32.27 github.com/aws/aws-sdk-go-v2/credentials v1.19.26 diff --git a/go.sum b/go.sum index b1b4b469d61..3de9c429b7f 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,6 @@ github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZ github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc= github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= -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-v2 v1.42.1 h1:9eOTgu1z/dVtYpNZ3/8/XbbaX0x/BqE3HUzAzs6K0ek= github.com/aws/aws-sdk-go-v2 v1.42.1/go.mod h1:5pKeft2eJj+gElQ38Jqg4ibCqh+/AK33/0X3hip7IjM= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14 h1:3IZY0XAJquT3aHzbkHfPzy4ACPcEjVG0x87KOwtpqGY= From dc00a8f6d32ed76fc4337565af09ee47a66b9e0a Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 16:45:45 +0200 Subject: [PATCH 13/17] address feedback --- internal/pkg/aws/partitions/partition.go | 163 ++++++------------ internal/pkg/aws/partitions/partition_test.go | 37 +++- internal/pkg/cli/task_run.go | 2 +- 3 files changed, 89 insertions(+), 113 deletions(-) diff --git a/internal/pkg/aws/partitions/partition.go b/internal/pkg/aws/partitions/partition.go index e1117bd6940..34899cb66d5 100644 --- a/internal/pkg/aws/partitions/partition.go +++ b/internal/pkg/aws/partitions/partition.go @@ -5,11 +5,19 @@ package partitions import ( "fmt" + "reflect" "regexp" + + copilotapprunner "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" + copilotecs "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" + copilots3 "github.com/aproint/copilot-cli/internal/pkg/aws/s3" + sdkapprunner "github.com/aws/aws-sdk-go-v2/service/apprunner" + sdkecs "github.com/aws/aws-sdk-go-v2/service/ecs" + sdks3 "github.com/aws/aws-sdk-go-v2/service/s3" ) var ( - awsRegionRegex = regexp.MustCompile(`^(us|eu|ap|sa|ca|me|af|il)-\w+-\d+$`) + awsRegionRegex = regexp.MustCompile(`^(us|eu|ap|sa|ca|me|af|il|mx)-\w+-\d+$`) awsChinaRegionRegex = regexp.MustCompile(`^cn-\w+-\d+$`) awsGovRegionRegex = regexp.MustCompile(`^us-gov-\w+-\d+$`) ) @@ -44,122 +52,55 @@ func (r Region) Partition() (Partition, error) { // IsAvailableInRegion returns true if the service ID is available in the given region. func IsAvailableInRegion(sID string, region string) (bool, error) { - partition, err := Region(region).Partition() - if err != nil { + if _, err := Region(region).Partition(); err != nil { return false, err } - regions, ok := serviceRegions[partition.ID()][sID] - if !ok { + + switch sID { + case copilotapprunner.EndpointsID: + return resolverHasRegion(sdkapprunner.NewDefaultEndpointResolver(), region) + case copilotecs.EndpointsID: + return resolverHasRegion(sdkecs.NewDefaultEndpointResolver(), region) + case copilots3.EndpointsID: + return resolverHasRegion(sdks3.NewDefaultEndpointResolver(), region) + default: return false, nil } - _, existInRegion := regions[region] - return existInRegion, nil } -var serviceRegions = map[string]map[string]map[string]struct{}{ - "aws": { - "apprunner": regions( - "ap-northeast-1", - "ap-south-1", - "ap-southeast-1", - "ap-southeast-2", - "eu-central-1", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "us-east-1", - "us-east-2", - "us-west-2", - ), - "ecs": regions( - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-south-2", - "ap-southeast-1", - "ap-southeast-2", - "ap-southeast-3", - "ap-southeast-4", - "ca-central-1", - "ca-west-1", - "eu-central-1", - "eu-central-2", - "eu-north-1", - "eu-south-1", - "eu-south-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "il-central-1", - "me-central-1", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - ), - "s3": regions( - "af-south-1", - "ap-east-1", - "ap-northeast-1", - "ap-northeast-2", - "ap-northeast-3", - "ap-south-1", - "ap-south-2", - "ap-southeast-1", - "ap-southeast-2", - "ap-southeast-3", - "ap-southeast-4", - "ca-central-1", - "ca-west-1", - "eu-central-1", - "eu-central-2", - "eu-north-1", - "eu-south-1", - "eu-south-2", - "eu-west-1", - "eu-west-2", - "eu-west-3", - "il-central-1", - "me-central-1", - "me-south-1", - "sa-east-1", - "us-east-1", - "us-east-2", - "us-west-1", - "us-west-2", - ), - }, - "aws-cn": { - "ecs": regions( - "cn-north-1", - "cn-northwest-1", - ), - "s3": regions( - "cn-north-1", - "cn-northwest-1", - ), - }, - "aws-us-gov": { - "ecs": regions( - "us-gov-east-1", - "us-gov-west-1", - ), - "s3": regions( - "us-gov-east-1", - "us-gov-west-1", - ), - }, -} +func resolverHasRegion(resolver any, region string) (bool, error) { + partitions := reflect.ValueOf(resolver) + if !partitions.IsValid() { + return false, fmt.Errorf("inspect endpoint resolver metadata") + } + if partitions.Kind() == reflect.Pointer { + if partitions.IsNil() { + return false, fmt.Errorf("inspect endpoint resolver metadata") + } + partitions = partitions.Elem() + } + partitions = partitions.FieldByName("partitions") + if !partitions.IsValid() || partitions.Kind() != reflect.Slice { + return false, fmt.Errorf("inspect endpoint resolver metadata") + } -func regions(ids ...string) map[string]struct{} { - out := make(map[string]struct{}, len(ids)) - for _, id := range ids { - out[id] = struct{}{} + for i := 0; i < partitions.Len(); i++ { + endpoints := partitions.Index(i).FieldByName("Endpoints") + if !endpoints.IsValid() || endpoints.Kind() != reflect.Map { + return false, fmt.Errorf("inspect endpoint resolver metadata") + } + for _, key := range endpoints.MapKeys() { + if key.Kind() != reflect.Struct { + return false, fmt.Errorf("inspect endpoint resolver metadata") + } + regionField := key.FieldByName("Region") + if !regionField.IsValid() || regionField.Kind() != reflect.String { + return false, fmt.Errorf("inspect endpoint resolver metadata") + } + if regionField.String() == region { + return true, nil + } + } } - return out + return false, nil } diff --git a/internal/pkg/aws/partitions/partition_test.go b/internal/pkg/aws/partitions/partition_test.go index 549ef6c1471..367196843e3 100644 --- a/internal/pkg/aws/partitions/partition_test.go +++ b/internal/pkg/aws/partitions/partition_test.go @@ -5,9 +5,11 @@ package partitions import ( "errors" + "testing" + "github.com/aproint/copilot-cli/internal/pkg/aws/apprunner" "github.com/aproint/copilot-cli/internal/pkg/aws/ecs" - "testing" + "github.com/aproint/copilot-cli/internal/pkg/aws/s3" "github.com/stretchr/testify/require" ) @@ -24,6 +26,9 @@ func TestRegion_Partition(t *testing.T) { "success": { region: "us-west-2", }, + "success with newer commercial partition region": { + region: "mx-central-1", + }, } for name, tc := range testCases { @@ -50,11 +55,31 @@ func TestRegion_IsAvailableInRegion(t *testing.T) { sID: ecs.EndpointsID, want: true, }, + "ecs service exists in newer SDK endpoint region": { + region: "ap-southeast-5", + sID: ecs.EndpointsID, + want: true, + }, + "ecs service exists in newer commercial partition region": { + region: "mx-central-1", + sID: ecs.EndpointsID, + want: true, + }, "ecs service does not exist in the given region": { region: "us-west-3", sID: ecs.EndpointsID, want: false, }, + "s3 service exists in newer SDK endpoint region": { + region: "ap-southeast-5", + sID: s3.EndpointsID, + want: true, + }, + "s3 service exists in newer commercial partition region": { + region: "mx-central-1", + sID: s3.EndpointsID, + want: true, + }, "apprunner service exist in the given region": { region: "us-west-2", sID: apprunner.EndpointsID, @@ -65,6 +90,16 @@ func TestRegion_IsAvailableInRegion(t *testing.T) { sID: apprunner.EndpointsID, want: false, }, + "unknown service does not exist in the given region": { + region: "us-west-2", + sID: "some-service", + want: false, + }, + "error finding the partition": { + region: "weird region", + sID: ecs.EndpointsID, + wantedErr: errors.New("find the partition for region weird region"), + }, } for name, tc := range testCases { diff --git a/internal/pkg/cli/task_run.go b/internal/pkg/cli/task_run.go index dc35eea62b5..c492a0241d5 100644 --- a/internal/pkg/cli/task_run.go +++ b/internal/pkg/cli/task_run.go @@ -236,7 +236,7 @@ func newTaskRunOpts(vars runTaskVars) (*runTaskOpts, error) { return ecs.New(cfg) } opts.configureJobDescriber = func(cfg aws.Config) ecs.JobDescriber { - return ecs.New(cfg) + return ecs.NewWithStepFunctionsConfig(cfg) } opts.configureUploader = func(cfg aws.Config) uploader { return s3.New(cfg) From e64a215901928bddab69ddc8f5d16a62d38263b5 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 17:01:54 +0200 Subject: [PATCH 14/17] tidy go.mod --- go.mod | 43 +++++++++++++++++++++---------------------- go.sum | 6 ------ 2 files changed, 21 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index cec43da4089..437299df238 100644 --- a/go.mod +++ b/go.mod @@ -9,6 +9,27 @@ require ( github.com/aws/aws-sdk-go-v2 v1.42.1 github.com/aws/aws-sdk-go-v2/config v1.32.27 github.com/aws/aws-sdk-go-v2/credentials v1.19.26 + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.30 + github.com/aws/aws-sdk-go-v2/service/acm v1.41.1 + github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.43.2 + github.com/aws/aws-sdk-go-v2/service/apprunner v1.40.8 + github.com/aws/aws-sdk-go-v2/service/cloudformation v1.73.1 + github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.61.1 + github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.78.2 + github.com/aws/aws-sdk-go-v2/service/codepipeline v1.47.7 + github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.311.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.58.6 + github.com/aws/aws-sdk-go-v2/service/ecs v1.86.2 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.55.6 + github.com/aws/aws-sdk-go-v2/service/iam v1.54.7 + github.com/aws/aws-sdk-go-v2/service/rds v1.119.5 + github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5 + github.com/aws/aws-sdk-go-v2/service/route53 v1.63.5 + github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2 + github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5 + github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2 + github.com/aws/aws-sdk-go-v2/service/ssm v1.69.5 github.com/aws/aws-sdk-go-v2/service/sts v1.43.5 github.com/aws/smithy-go v1.27.3 github.com/briandowns/spinner v1.23.1 @@ -44,35 +65,14 @@ require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.14 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.30 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.30 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.30 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.30 // indirect github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.31 // indirect - github.com/aws/aws-sdk-go-v2/service/acm v1.41.1 // indirect - github.com/aws/aws-sdk-go-v2/service/applicationautoscaling v1.43.2 // indirect - github.com/aws/aws-sdk-go-v2/service/apprunner v1.40.8 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudformation v1.73.1 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.61.1 // indirect - github.com/aws/aws-sdk-go-v2/service/cloudwatchlogs v1.78.2 // indirect - github.com/aws/aws-sdk-go-v2/service/codepipeline v1.47.7 // indirect - github.com/aws/aws-sdk-go-v2/service/codestarconnections v1.36.7 // indirect - github.com/aws/aws-sdk-go-v2/service/ec2 v1.311.0 // indirect - github.com/aws/aws-sdk-go-v2/service/ecr v1.58.6 // indirect - github.com/aws/aws-sdk-go-v2/service/ecs v1.86.2 // indirect - github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.55.6 // indirect - github.com/aws/aws-sdk-go-v2/service/iam v1.54.7 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.13 // indirect github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.23 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.30 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.31 // indirect - github.com/aws/aws-sdk-go-v2/service/rds v1.119.5 // indirect - github.com/aws/aws-sdk-go-v2/service/resourcegroupstaggingapi v1.33.5 // indirect - github.com/aws/aws-sdk-go-v2/service/route53 v1.63.5 // indirect - github.com/aws/aws-sdk-go-v2/service/s3 v1.104.2 // indirect - github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.42.5 // indirect - github.com/aws/aws-sdk-go-v2/service/sfn v1.43.2 // indirect github.com/aws/aws-sdk-go-v2/service/signin v1.2.2 // indirect - github.com/aws/aws-sdk-go-v2/service/ssm v1.69.5 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.31.5 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.36.8 // indirect github.com/containerd/typeurl/v2 v2.1.1 // indirect @@ -87,7 +87,6 @@ require ( github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 // indirect github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect diff --git a/go.sum b/go.sum index 3de9c429b7f..c753414cb56 100644 --- a/go.sum +++ b/go.sum @@ -128,10 +128,6 @@ github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= -github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg= -github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= -github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= -github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -246,8 +242,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 415f65f3c789bf89a3082826d40844e8bb6bc412 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 17:05:44 +0200 Subject: [PATCH 15/17] address feedback pt2 --- internal/pkg/aws/sessions/sessions.go | 1 + internal/pkg/aws/sessions/sessions_v2.go | 44 +++---------- internal/pkg/aws/sessions/sessions_v2_test.go | 66 +++++++++++-------- 3 files changed, 49 insertions(+), 62 deletions(-) diff --git a/internal/pkg/aws/sessions/sessions.go b/internal/pkg/aws/sessions/sessions.go index f5fcae13d0a..62bba4f0b31 100644 --- a/internal/pkg/aws/sessions/sessions.go +++ b/internal/pkg/aws/sessions/sessions.go @@ -22,6 +22,7 @@ const ( // User-Agent settings. const ( userAgentProductName = "aws-copilot" + userAgentCommandKey = "aws-copilot-command" ) // Provider provides methods to create AWS SDK configs. diff --git a/internal/pkg/aws/sessions/sessions_v2.go b/internal/pkg/aws/sessions/sessions_v2.go index 5c84ecb3bb6..b2f466ac6a0 100644 --- a/internal/pkg/aws/sessions/sessions_v2.go +++ b/internal/pkg/aws/sessions/sessions_v2.go @@ -8,18 +8,16 @@ import ( "errors" "fmt" "net/http" - "runtime" - "strings" "github.com/aproint/copilot-cli/internal/pkg/version" awsv2 "github.com/aws/aws-sdk-go-v2/aws" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" "github.com/aws/aws-sdk-go-v2/aws/retry" v2config "github.com/aws/aws-sdk-go-v2/config" v2credentials "github.com/aws/aws-sdk-go-v2/credentials" v2stscreds "github.com/aws/aws-sdk-go-v2/credentials/stscreds" "github.com/aws/aws-sdk-go-v2/service/sts" "github.com/aws/smithy-go/middleware" - smithyhttp "github.com/aws/smithy-go/transport/http" ) type v2ConfigLoader func(context.Context, ...func(*v2config.LoadOptions) error) (awsv2.Config, error) @@ -153,11 +151,6 @@ func (p *Provider) v2APIOptions() []func(*middleware.Stack) error { } } -func (p *Provider) userAgentValue() string { - extras := append([]string{runtime.GOOS}, p.userAgentExtras...) - return fmt.Sprintf("%s/%s (%s)", userAgentProductName, version.Version, strings.Join(extras, "; ")) -} - // AreV2CredsFromEnvVars returns true if the config's credentials provider is environment variables, false otherwise. // An error is returned if the credentials are invalid or the request times out. func AreV2CredsFromEnvVars(ctx context.Context, cfg awsv2.Config) (bool, error) { @@ -189,33 +182,16 @@ func (v *v2Validator) ValidateV2Credentials(ctx context.Context, cfg awsv2.Confi return V2Creds(ctx, cfg) } -type copilotUserAgent struct { - provider *Provider -} - func addCopilotUserAgent(provider *Provider) func(*middleware.Stack) error { return func(stack *middleware.Stack) error { - return stack.Build.Add(&copilotUserAgent{provider: provider}, middleware.After) - } -} - -func (m *copilotUserAgent) ID() string { - return "CopilotUserAgent" -} - -func (m *copilotUserAgent) HandleBuild(ctx context.Context, in middleware.BuildInput, next middleware.BuildHandler) ( - out middleware.BuildOutput, metadata middleware.Metadata, err error, -) { - req, ok := in.Request.(*smithyhttp.Request) - if !ok { - return out, metadata, fmt.Errorf("unknown transport type %T", in.Request) - } - - value := m.provider.userAgentValue() - if existing := req.Header.Get("User-Agent"); existing != "" { - req.Header.Set("User-Agent", fmt.Sprintf("%s %s", existing, value)) - } else { - req.Header.Set("User-Agent", value) + if err := awsmiddleware.AddUserAgentKeyValue(userAgentProductName, version.Version)(stack); err != nil { + return err + } + for _, extra := range provider.userAgentExtras { + if err := awsmiddleware.AddUserAgentKeyValue(userAgentCommandKey, extra)(stack); err != nil { + return err + } + } + return nil } - return next.HandleBuild(ctx, in) } diff --git a/internal/pkg/aws/sessions/sessions_v2_test.go b/internal/pkg/aws/sessions/sessions_v2_test.go index 40cba08cbcd..501e2d9c3fe 100644 --- a/internal/pkg/aws/sessions/sessions_v2_test.go +++ b/internal/pkg/aws/sessions/sessions_v2_test.go @@ -9,6 +9,7 @@ import ( "net/http" "testing" + "github.com/aproint/copilot-cli/internal/pkg/version" awsv2 "github.com/aws/aws-sdk-go-v2/aws" v2config "github.com/aws/aws-sdk-go-v2/config" v2credentials "github.com/aws/aws-sdk-go-v2/credentials" @@ -277,54 +278,63 @@ func TestAreV2CredsFromEnvVars(t *testing.T) { } } -func TestCopilotUserAgent_HandleBuild(t *testing.T) { +func TestAddCopilotUserAgent(t *testing.T) { provider := &Provider{} testCases := map[string]struct { existing string - want string }{ - "sets the header if missing": { - want: provider.userAgentValue(), - }, + "sets the header if missing": {}, "appends to existing user agent": { existing: "aws-sdk-go-v2/1.0.0", - want: "aws-sdk-go-v2/1.0.0 " + provider.userAgentValue(), }, } for name, tc := range testCases { t.Run(name, func(t *testing.T) { - req := &smithyhttp.Request{Request: &http.Request{Header: http.Header{}}} + got := renderCopilotUserAgent(t, provider, tc.existing) + require.Contains(t, got, "aws-sdk-go-v2/") + require.Contains(t, got, userAgentProductName+"/"+version.Version) if tc.existing != "" { - req.Header.Set("User-Agent", tc.existing) + require.Contains(t, got, tc.existing) } - ua := &copilotUserAgent{provider: provider} - - _, _, err := ua.HandleBuild(context.Background(), middleware.BuildInput{Request: req}, middleware.BuildHandlerFunc( - func(_ context.Context, in middleware.BuildInput) (middleware.BuildOutput, middleware.Metadata, error) { - return middleware.BuildOutput{Result: in.Request}, middleware.Metadata{}, nil - }, - )) - - require.NoError(t, err) - require.Equal(t, tc.want, req.Header.Get("User-Agent")) }) } } -func TestCopilotUserAgent_HandleBuildUsesLatestProviderExtras(t *testing.T) { +func TestAddCopilotUserAgentUsesLatestProviderExtras(t *testing.T) { provider := &Provider{userAgentExtras: []string{"svc deploy"}} - req := &smithyhttp.Request{Request: &http.Request{Header: http.Header{}}} - ua := &copilotUserAgent{provider: provider} provider.UserAgentExtras("override cdk") - _, _, err := ua.HandleBuild(context.Background(), middleware.BuildInput{Request: req}, middleware.BuildHandlerFunc( - func(_ context.Context, in middleware.BuildInput) (middleware.BuildOutput, middleware.Metadata, error) { - return middleware.BuildOutput{Result: in.Request}, middleware.Metadata{}, nil - }, - )) + got := renderCopilotUserAgent(t, provider, "") + + require.Contains(t, got, userAgentProductName+"/"+version.Version) + require.Contains(t, got, userAgentCommandKey+"/svc-deploy") + require.Contains(t, got, userAgentCommandKey+"/override-cdk") +} + +func renderCopilotUserAgent(t *testing.T, provider *Provider, existing string) string { + t.Helper() + + stack := middleware.NewStack("testStack", smithyhttp.NewStackRequest) + req := &smithyhttp.Request{Request: &http.Request{Header: http.Header{}}} + if existing != "" { + req.Header.Set("User-Agent", existing) + } + err := stack.Build.Add(middleware.BuildMiddlewareFunc("setRequest", func(ctx context.Context, _ middleware.BuildInput, handler middleware.BuildHandler) ( + out middleware.BuildOutput, metadata middleware.Metadata, err error, + ) { + return handler.HandleBuild(ctx, middleware.BuildInput{Request: req}) + }), middleware.After) + require.NoError(t, err) + err = addCopilotUserAgent(provider)(stack) require.NoError(t, err) - require.Equal(t, provider.userAgentValue(), req.Header.Get("User-Agent")) - require.Contains(t, req.Header.Get("User-Agent"), "svc deploy; override cdk") + _, _, err = middleware.DecorateHandler(middleware.HandlerFunc(func(_ context.Context, input interface{}) ( + output interface{}, metadata middleware.Metadata, err error, + ) { + return input, metadata, nil + }), stack).Handle(context.Background(), nil) + require.NoError(t, err) + + return req.Header.Get("User-Agent") } From 115b02c6c25e4e32e5a17f2e75c0395a27464fb0 Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 17:05:57 +0200 Subject: [PATCH 16/17] fix license --- internal/pkg/cli/config_store.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/pkg/cli/config_store.go b/internal/pkg/cli/config_store.go index 75f4382e164..ef6301a4a38 100644 --- a/internal/pkg/cli/config_store.go +++ b/internal/pkg/cli/config_store.go @@ -1,3 +1,6 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + package cli import ( From 58f91a37cec4683e6d72888d9389c40594e8ddcd Mon Sep 17 00:00:00 2001 From: Zdenek Farana Date: Tue, 7 Jul 2026 17:06:28 +0200 Subject: [PATCH 17/17] make license portable --- scripts/license.sh | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/scripts/license.sh b/scripts/license.sh index fbd41fbbc2c..a3107b6905f 100755 --- a/scripts/license.sh +++ b/scripts/license.sh @@ -22,31 +22,33 @@ if [ $# != 1 ]; then exit 1 fi +rootdir=$1 + fail=0 -for file in $(find $1 -regextype 'posix-extended' -regex '.*\.(go|js)'); do +while IFS= read -r -d '' file; do case $file in - $1/*/mocks/*) + $rootdir/*/mocks/*) # Skip mocks packages. ;; - $1/*/mock_*.go) + $rootdir/*/mock_*.go) # Skip mock files. ;; - $1/*/node_modules/*) + $rootdir/*/node_modules/*) # Skip node modules for js files. ;; - $1/site/*) + $rootdir/site/*) # Skip website content ;; *) header="$(head -10 $file)" if ! check_header "$header"; then fail=1 - echo "${file#$1/} doesn't have the right copyright header:" + echo "${file#$rootdir/} doesn't have the right copyright header:" echo "$header" | sed -e 's/^/ /g' fi ;; esac -done +done < <(find "$rootdir" \( -name '*.go' -o -name '*.js' \) -print0) if [ $fail -ne 0 ]; then exit 1