From 334b2bcfcb673c3cc6077af771a48523a9d32bc8 Mon Sep 17 00:00:00 2001 From: AJ Date: Sat, 2 Nov 2024 01:51:02 +0000 Subject: [PATCH] change port ebs, ecr, ecs cluster, ecs service, efs, eip, eks, elastic beanstalk, elasticache, elb, elbv2, guardduty to awsSDKv2 #770 (#777) --- aws/resources/ebs.go | 59 +++++---- aws/resources/ebs_test.go | 52 +++----- aws/resources/ebs_types.go | 23 ++-- aws/resources/ecr.go | 25 ++-- aws/resources/ecr_test.go | 31 ++--- aws/resources/ecr_types.go | 21 +-- aws/resources/ecs_cluster.go | 71 +++++----- aws/resources/ecs_cluster_test.go | 73 +++++------ aws/resources/ecs_cluster_types.go | 28 ++-- aws/resources/ecs_service.go | 66 +++++----- aws/resources/ecs_service_test.go | 59 ++++----- aws/resources/ecs_service_types.go | 26 ++-- aws/resources/efs.go | 68 +++++----- aws/resources/efs_test.go | 61 ++++----- aws/resources/efs_types.go | 27 ++-- aws/resources/eip.go | 57 ++++---- aws/resources/eip_test.go | 55 ++++---- aws/resources/eip_types.go | 43 ++++--- aws/resources/eks.go | 109 ++++++++-------- aws/resources/eks_test.go | 113 +++++++--------- aws/resources/eks_types.go | 30 +++-- aws/resources/elastic_beanstalk.go | 15 ++- aws/resources/elastic_beanstalk_test.go | 22 ++-- aws/resources/elastic_beanstalk_types.go | 23 ++-- aws/resources/elasticache.go | 157 +++++++++++++---------- aws/resources/elasticache_test.go | 43 ++++--- aws/resources/elasticache_types.go | 57 +++++--- aws/resources/elb.go | 30 ++--- aws/resources/elb_test.go | 32 ++--- aws/resources/elb_types.go | 23 ++-- aws/resources/elbv2.go | 22 ++-- aws/resources/elbv2_test.go | 63 +++++---- aws/resources/elbv2_types.go | 23 ++-- aws/resources/guardduty.go | 43 +++---- aws/resources/guardduty_test.go | 34 ++--- aws/resources/guardduty_types.go | 22 ++-- go.mod | 43 ++++--- go.sum | 50 ++++++++ v2_migration_report/output.md | 30 ++--- 39 files changed, 975 insertions(+), 854 deletions(-) diff --git a/aws/resources/ebs.go b/aws/resources/ebs.go index e543f956..ee2541be 100644 --- a/aws/resources/ebs.go +++ b/aws/resources/ebs.go @@ -2,11 +2,13 @@ package resources import ( "context" + goerr "errors" + "time" - "github.com/aws/aws-sdk-go/aws" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/smithy-go" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -20,9 +22,9 @@ func (ev *EBSVolumes) getAll(c context.Context, configObj config.Config) ([]*str // Since the output of this function is used to delete the returned volumes // We want to only list EBS volumes with a status of "available" or "creating" // Since those are the only statuses that are eligible for deletion - statusFilter := ec2.Filter{Name: aws.String("status"), Values: aws.StringSlice([]string{"available", "creating", "error"})} - result, err := ev.Client.DescribeVolumesWithContext(ev.Context, &ec2.DescribeVolumesInput{ - Filters: []*ec2.Filter{&statusFilter}, + statusFilter := types.Filter{Name: aws.String("status"), Values: []string{"available", "creating", "error"}} + result, err := ev.Client.DescribeVolumes(ev.Context, &ec2.DescribeVolumesInput{ + Filters: []types.Filter{statusFilter}, }) if err != nil { @@ -38,9 +40,9 @@ func (ev *EBSVolumes) getAll(c context.Context, configObj config.Config) ([]*str // checking the nukable permissions ev.VerifyNukablePermissions(volumeIds, func(id *string) error { - _, err := ev.Client.DeleteVolumeWithContext(ev.Context, &ec2.DeleteVolumeInput{ + _, err := ev.Client.DeleteVolume(ev.Context, &ec2.DeleteVolumeInput{ VolumeId: id, - DryRun: awsgo.Bool(true), + DryRun: aws.Bool(true), }) return err }) @@ -48,18 +50,18 @@ func (ev *EBSVolumes) getAll(c context.Context, configObj config.Config) ([]*str return volumeIds, nil } -func shouldIncludeEBSVolume(volume *ec2.Volume, configObj config.Config) bool { +func shouldIncludeEBSVolume(volume types.Volume, configObj config.Config) bool { name := "" for _, tag := range volume.Tags { - if tag != nil && aws.StringValue(tag.Key) == "Name" { - name = aws.StringValue(tag.Value) + if aws.ToString(tag.Key) == "Name" { + name = aws.ToString(tag.Value) } } return configObj.EBSVolume.ShouldInclude(config.ResourceValue{ Name: &name, Time: volume.CreateTime, - Tags: util.ConvertEC2TagsToMap(volume.Tags), + Tags: util.ConvertTypesTagsToMap(volume.Tags), }) } @@ -75,8 +77,8 @@ func (ev *EBSVolumes) nukeAll(volumeIds []*string) error { for _, volumeID := range volumeIds { - if nukable, reason := ev.IsNukable(awsgo.StringValue(volumeID)); !nukable { - logging.Debugf("[Skipping] %s nuke because %v", awsgo.StringValue(volumeID), reason) + if nukable, reason := ev.IsNukable(aws.ToString(volumeID)); !nukable { + logging.Debugf("[Skipping] %s nuke because %v", aws.ToString(volumeID), reason) continue } @@ -84,23 +86,27 @@ func (ev *EBSVolumes) nukeAll(volumeIds []*string) error { VolumeId: volumeID, } - _, err := ev.Client.DeleteVolumeWithContext(ev.Context, params) + _, err := ev.Client.DeleteVolume(ev.Context, params) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(volumeID), + Identifier: aws.ToString(volumeID), ResourceType: "EBS Volume", Error: err, } report.Record(e) if err != nil { - if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "VolumeInUse" { - logging.Debugf("EBS volume %s can't be deleted, it is still attached to an active resource", *volumeID) - } else if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "InvalidVolume.NotFound" { - logging.Debugf("EBS volume %s has already been deleted", *volumeID) - } else { - logging.Debugf("[Failed] %s", err) + var apiErr smithy.APIError + if goerr.As(err, &apiErr) { + switch apiErr.ErrorCode() { + case "VolumeInUse": + logging.Debugf("EBS volume %s can't be deleted, it is still attached to an active resource", *volumeID) + case "InvalidVolume.NotFound": + logging.Debugf("EBS volume %s has already been deleted", *volumeID) + default: + logging.Debugf("[Failed] %s", err) + } } } else { deletedVolumeIDs = append(deletedVolumeIDs, volumeID) @@ -109,9 +115,10 @@ func (ev *EBSVolumes) nukeAll(volumeIds []*string) error { } if len(deletedVolumeIDs) > 0 { - err := ev.Client.WaitUntilVolumeDeletedWithContext(ev.Context, &ec2.DescribeVolumesInput{ - VolumeIds: deletedVolumeIDs, - }) + waiter := ec2.NewVolumeDeletedWaiter(ev.Client) + err := waiter.Wait(ev.Context, &ec2.DescribeVolumesInput{ + VolumeIds: aws.ToStringSlice(deletedVolumeIDs), + }, 5*time.Minute) if err != nil { logging.Debugf("[Failed] %s", err) return errors.WithStackTrace(err) diff --git a/aws/resources/ebs_test.go b/aws/resources/ebs_test.go index e4defc6f..6e8adf30 100644 --- a/aws/resources/ebs_test.go +++ b/aws/resources/ebs_test.go @@ -6,36 +6,28 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" - - "github.com/aws/aws-sdk-go/aws" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedEBS struct { - ec2iface.EC2API - DeleteVolumeOutput ec2.DeleteVolumeOutput + EBSVolumesAPI DescribeVolumesOutput ec2.DescribeVolumesOutput + DeleteVolumeOutput ec2.DeleteVolumeOutput } -func (m mockedEBS) DeleteVolumeWithContext(_ awsgo.Context, input *ec2.DeleteVolumeInput, _ ...request.Option) (*ec2.DeleteVolumeOutput, error) { - return &m.DeleteVolumeOutput, nil -} - -func (m mockedEBS) DescribeVolumesWithContext(_ awsgo.Context, input *ec2.DescribeVolumesInput, _ ...request.Option) (*ec2.DescribeVolumesOutput, error) { +func (m mockedEBS) DescribeVolumes(ctx context.Context, params *ec2.DescribeVolumesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeVolumesOutput, error) { return &m.DescribeVolumesOutput, nil } -func (m mockedEBS) WaitUntilVolumeDeletedWithContext(_ awsgo.Context, input *ec2.DescribeVolumesInput, _ ...request.WaiterOption) error { - return nil +func (m mockedEBS) DeleteVolume(ctx context.Context, params *ec2.DeleteVolumeInput, optFns ...func(*ec2.Options)) (*ec2.DeleteVolumeOutput, error) { + return &m.DeleteVolumeOutput, nil } func TestEBSVolume_GetAll(t *testing.T) { - t.Parallel() testName1 := "test-name1" @@ -46,21 +38,21 @@ func TestEBSVolume_GetAll(t *testing.T) { ev := EBSVolumes{ Client: mockedEBS{ DescribeVolumesOutput: ec2.DescribeVolumesOutput{ - Volumes: []*ec2.Volume{ + Volumes: []types.Volume{ { - VolumeId: awsgo.String(testVolume1), - CreateTime: awsgo.Time(now), - Tags: []*ec2.Tag{{ - Key: awsgo.String("Name"), - Value: awsgo.String(testName1), + VolumeId: aws.String(testVolume1), + CreateTime: aws.Time(now), + Tags: []types.Tag{{ + Key: aws.String("Name"), + Value: aws.String(testName1), }}, }, { - VolumeId: awsgo.String(testVolume2), - CreateTime: awsgo.Time(now.Add(1)), - Tags: []*ec2.Tag{{ - Key: awsgo.String("Name"), - Value: awsgo.String(testName2), + VolumeId: aws.String(testVolume2), + CreateTime: aws.Time(now.Add(1)), + Tags: []types.Tag{{ + Key: aws.String("Name"), + Value: aws.String(testName2), }}, }, }}}} @@ -97,13 +89,12 @@ func TestEBSVolume_GetAll(t *testing.T) { EBSVolume: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } -func TestEBSVolumne_NukeAll(t *testing.T) { - +func TestEBSVolume_NukeAll(t *testing.T) { t.Parallel() ev := EBSVolumes{ @@ -114,5 +105,4 @@ func TestEBSVolumne_NukeAll(t *testing.T) { err := ev.nukeAll([]*string{aws.String("test-volume")}) require.NoError(t, err) - } diff --git a/aws/resources/ebs_types.go b/aws/resources/ebs_types.go index 4eae8a9e..06eca7b7 100644 --- a/aws/resources/ebs_types.go +++ b/aws/resources/ebs_types.go @@ -3,26 +3,31 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type EBSVolumesAPI interface { + DescribeVolumes(ctx context.Context, params *ec2.DescribeVolumesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeVolumesOutput, error) + DeleteVolume(ctx context.Context, params *ec2.DeleteVolumeInput, optFns ...func(*ec2.Options)) (*ec2.DeleteVolumeOutput, error) +} + // EBSVolumes - represents all ebs volumes type EBSVolumes struct { BaseAwsResource - Client ec2iface.EC2API + Client EBSVolumesAPI Region string VolumeIds []string } -func (ev *EBSVolumes) Init(session *session.Session) { - ev.Client = ec2.New(session) +func (ev *EBSVolumes) InitV2(cfg aws.Config) { + ev.Client = ec2.NewFromConfig(cfg) } +func (ev *EBSVolumes) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource func (ev *EBSVolumes) ResourceName() string { return "ebs" @@ -48,13 +53,13 @@ func (ev *EBSVolumes) GetAndSetIdentifiers(c context.Context, configObj config.C return nil, err } - ev.VolumeIds = awsgo.StringValueSlice(identifiers) + ev.VolumeIds = aws.ToStringSlice(identifiers) return ev.VolumeIds, nil } // Nuke - nuke 'em all!!! func (ev *EBSVolumes) Nuke(identifiers []string) error { - if err := ev.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := ev.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/ecr.go b/aws/resources/ecr.go index 87ff25bb..6231434a 100644 --- a/aws/resources/ecr.go +++ b/aws/resources/ecr.go @@ -3,8 +3,8 @@ package resources import ( "context" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecr" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -12,9 +12,15 @@ import ( ) func (registry *ECR) getAll(c context.Context, configObj config.Config) ([]*string, error) { - repositoryNames := []*string{} + var repositoryNames []*string + + paginator := ecr.NewDescribeRepositoriesPaginator(registry.Client, &ecr.DescribeRepositoriesInput{}) + for paginator.HasMorePages() { + output, err := paginator.NextPage(c) + if err != nil { + return nil, errors.WithStackTrace(err) + } - paginator := func(output *ecr.DescribeRepositoriesOutput, lastPage bool) bool { for _, repository := range output.Repositories { if configObj.ECRRepository.ShouldInclude(config.ResourceValue{ Time: repository.CreatedAt, @@ -23,13 +29,6 @@ func (registry *ECR) getAll(c context.Context, configObj config.Config) ([]*stri repositoryNames = append(repositoryNames, repository.RepositoryName) } } - return !lastPage - } - - param := &ecr.DescribeRepositoriesInput{} - err := registry.Client.DescribeRepositoriesPagesWithContext(registry.Context, param, paginator) - if err != nil { - return nil, errors.WithStackTrace(err) } return repositoryNames, nil @@ -45,11 +44,11 @@ func (registry *ECR) nukeAll(repositoryNames []string) error { for _, repositoryName := range repositoryNames { params := &ecr.DeleteRepositoryInput{ - Force: aws.Bool(true), + Force: true, RepositoryName: aws.String(repositoryName), } - _, err := registry.Client.DeleteRepositoryWithContext(registry.Context, params) + _, err := registry.Client.DeleteRepository(registry.Context, params) // Record status of this resource e := report.Entry{ diff --git a/aws/resources/ecr_test.go b/aws/resources/ecr_test.go index 05798924..96227a23 100644 --- a/aws/resources/ecr_test.go +++ b/aws/resources/ecr_test.go @@ -6,40 +6,36 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" + "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/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedECR struct { - ecriface.ECRAPI - DescribeRepositoriesPagesOutput ecr.DescribeRepositoriesOutput - DeleteRepositoryOutput ecr.DeleteRepositoryOutput + ECRAPI + DescribeRepositoriesOutput ecr.DescribeRepositoriesOutput + DeleteRepositoryOutput ecr.DeleteRepositoryOutput } -func (m mockedECR) DescribeRepositoriesPagesWithContext(_ aws.Context, input *ecr.DescribeRepositoriesInput, callback func(*ecr.DescribeRepositoriesOutput, bool) bool, _ ...request.Option) error { - callback(&m.DescribeRepositoriesPagesOutput, true) - return nil +func (m mockedECR) DescribeRepositories(ctx context.Context, params *ecr.DescribeRepositoriesInput, optFns ...func(*ecr.Options)) (*ecr.DescribeRepositoriesOutput, error) { + return &m.DescribeRepositoriesOutput, nil } -func (m mockedECR) DeleteRepositoryWithContext(_ aws.Context, input *ecr.DeleteRepositoryInput, _ ...request.Option) (*ecr.DeleteRepositoryOutput, error) { +func (m mockedECR) DeleteRepository(ctx context.Context, params *ecr.DeleteRepositoryInput, optFns ...func(*ecr.Options)) (*ecr.DeleteRepositoryOutput, error) { return &m.DeleteRepositoryOutput, nil } func TestECR_GetAll(t *testing.T) { - t.Parallel() - testName1 := "test-repo1" testName2 := "test-repo2" now := time.Now() er := ECR{ Client: &mockedECR{ - DescribeRepositoriesPagesOutput: ecr.DescribeRepositoriesOutput{ - Repositories: []*ecr.Repository{ + DescribeRepositoriesOutput: ecr.DescribeRepositoriesOutput{ + Repositories: []types.Repository{ { RepositoryName: aws.String(testName1), CreatedAt: aws.Time(now), @@ -84,16 +80,13 @@ func TestECR_GetAll(t *testing.T) { ECRRepository: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } - func TestECR_NukeAll(t *testing.T) { - t.Parallel() - er := ECR{ Client: &mockedECR{ DeleteRepositoryOutput: ecr.DeleteRepositoryOutput{}, diff --git a/aws/resources/ecr_types.go b/aws/resources/ecr_types.go index c9288920..2a875cb2 100644 --- a/aws/resources/ecr_types.go +++ b/aws/resources/ecr_types.go @@ -3,25 +3,30 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ecr" - "github.com/aws/aws-sdk-go/service/ecr/ecriface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecr" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type ECRAPI interface { + DescribeRepositories(ctx context.Context, params *ecr.DescribeRepositoriesInput, optFns ...func(*ecr.Options)) (*ecr.DescribeRepositoriesOutput, error) + DeleteRepository(ctx context.Context, params *ecr.DeleteRepositoryInput, optFns ...func(*ecr.Options)) (*ecr.DeleteRepositoryOutput, error) +} + type ECR struct { BaseAwsResource - Client ecriface.ECRAPI + Client ECRAPI Region string RepositoryNames []string } -func (registry *ECR) Init(session *session.Session) { - registry.Client = ecr.New(session) +func (registry *ECR) InitV2(cfg aws.Config) { + registry.Client = ecr.NewFromConfig(cfg) } +func (registry *ECR) IsUsingV2() bool { return true } + func (registry *ECR) ResourceName() string { return "ecr" } @@ -44,7 +49,7 @@ func (registry *ECR) GetAndSetIdentifiers(c context.Context, configObj config.Co return nil, err } - registry.RepositoryNames = awsgo.StringValueSlice(identifiers) + registry.RepositoryNames = aws.ToStringSlice(identifiers) return registry.RepositoryNames, nil } diff --git a/aws/resources/ecs_cluster.go b/aws/resources/ecs_cluster.go index c5d02d5b..b80b4e81 100644 --- a/aws/resources/ecs_cluster.go +++ b/aws/resources/ecs_cluster.go @@ -4,14 +4,13 @@ import ( "context" "time" - "github.com/gruntwork-io/cloud-nuke/util" - - "github.com/aws/aws-sdk-go/aws" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" + "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/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" + "github.com/gruntwork-io/cloud-nuke/util" "github.com/gruntwork-io/go-commons/errors" ) @@ -26,23 +25,23 @@ const describeClustersRequestBatchSize = 100 // getAllEcsClusters - Returns a string of ECS Cluster ARNs, which uniquely identifies the cluster. // We need to get all clusters before we can get all services. func (clusters *ECSClusters) getAllEcsClusters() ([]*string, error) { - clusterArns := []*string{} - result, err := clusters.Client.ListClustersWithContext(clusters.Context, &ecs.ListClustersInput{}) + var clusterArns []string + result, err := clusters.Client.ListClusters(clusters.Context, &ecs.ListClustersInput{}) if err != nil { return nil, errors.WithStackTrace(err) } clusterArns = append(clusterArns, result.ClusterArns...) // Handle pagination: continuously pull the next page if nextToken is set - for awsgo.StringValue(result.NextToken) != "" { - result, err = clusters.Client.ListClustersWithContext(clusters.Context, &ecs.ListClustersInput{NextToken: result.NextToken}) + for aws.ToString(result.NextToken) != "" { + result, err = clusters.Client.ListClusters(clusters.Context, &ecs.ListClustersInput{NextToken: result.NextToken}) if err != nil { return nil, errors.WithStackTrace(err) } clusterArns = append(clusterArns, result.ClusterArns...) } - return clusterArns, nil + return aws.StringSlice(clusterArns), nil } // Filter all active ecs clusters @@ -55,20 +54,20 @@ func (clusters *ECSClusters) getAllActiveEcsClusterArns(configObj config.Config) var filteredEcsClusterArns []*string - batches := util.Split(aws.StringValueSlice(allClusters), describeClustersRequestBatchSize) + batches := util.Split(aws.ToStringSlice(allClusters), describeClustersRequestBatchSize) for _, batch := range batches { input := &ecs.DescribeClustersInput{ - Clusters: awsgo.StringSlice(batch), + Clusters: batch, } - describedClusters, describeErr := clusters.Client.DescribeClustersWithContext(clusters.Context, input) + describedClusters, describeErr := clusters.Client.DescribeClusters(clusters.Context, input) if describeErr != nil { logging.Debugf("Error describing ECS clusters from input %s: ", input) return nil, errors.WithStackTrace(describeErr) } for _, cluster := range describedClusters.Clusters { - if shouldIncludeECSCluster(cluster, configObj) { + if shouldIncludeECSCluster(&cluster, configObj) { filteredEcsClusterArns = append(filteredEcsClusterArns, cluster.ClusterArn) } } @@ -77,16 +76,16 @@ func (clusters *ECSClusters) getAllActiveEcsClusterArns(configObj config.Config) return filteredEcsClusterArns, nil } -func shouldIncludeECSCluster(cluster *ecs.Cluster, configObj config.Config) bool { +func shouldIncludeECSCluster(cluster *types.Cluster, configObj config.Config) bool { if cluster == nil { return false } // Filter out invalid state ECS Clusters (will return only `ACTIVE` state clusters) // `cloud-nuke` needs to tag ECS Clusters it sees for the first time. - // Therefore to tag a cluster, that cluster must be in the `ACTIVE` state. - logging.Debugf("Status for ECS Cluster %s is %s", aws.StringValue(cluster.ClusterArn), aws.StringValue(cluster.Status)) - if aws.StringValue(cluster.Status) != activeEcsClusterStatus { + // Therefore, to tag a cluster, that cluster must be in the `ACTIVE` state. + logging.Debugf("Status for ECS Cluster %s is %s", aws.ToString(cluster.ClusterArn), aws.ToString(cluster.Status)) + if aws.ToString(cluster.Status) != activeEcsClusterStatus { return false } @@ -110,14 +109,14 @@ func (clusters *ECSClusters) getAll(c context.Context, configObj config.Config) if !excludeFirstSeenTag { firstSeenTime, err := clusters.getFirstSeenTag(clusterArn) if err != nil { - logging.Debugf("Error getting the `cloud-nuke-first-seen` tag for ECS cluster with ARN %s", aws.StringValue(clusterArn)) + logging.Debugf("Error getting the `cloud-nuke-first-seen` tag for ECS cluster with ARN %s", aws.ToString(clusterArn)) return nil, errors.WithStackTrace(err) } if firstSeenTime == nil { err := clusters.setFirstSeenTag(clusterArn, time.Now().UTC()) if err != nil { - logging.Debugf("Error tagging the ECS cluster with ARN %s", aws.StringValue(clusterArn)) + logging.Debugf("Error tagging the ECS cluster with ARN %s", aws.ToString(clusterArn)) return nil, errors.WithStackTrace(err) } } else if configObj.ECSCluster.ShouldInclude(config.ResourceValue{Time: firstSeenTime}) { @@ -131,9 +130,9 @@ func (clusters *ECSClusters) getAll(c context.Context, configObj config.Config) func (clusters *ECSClusters) stopClusterRunningTasks(clusterArn *string) error { logging.Debugf("[TASK] stopping tasks running on cluster %v", *clusterArn) // before deleting the cluster, remove the active tasks on that cluster - runningTasks, err := clusters.Client.ListTasksWithContext(clusters.Context, &ecs.ListTasksInput{ + runningTasks, err := clusters.Client.ListTasks(clusters.Context, &ecs.ListTasksInput{ Cluster: clusterArn, - DesiredStatus: aws.String("RUNNING"), + DesiredStatus: types.DesiredStatusRunning, }) if err != nil { @@ -142,16 +141,16 @@ func (clusters *ECSClusters) stopClusterRunningTasks(clusterArn *string) error { // stop the listed tasks for _, task := range runningTasks.TaskArns { - _, err := clusters.Client.StopTaskWithContext(clusters.Context, &ecs.StopTaskInput{ + _, err := clusters.Client.StopTask(clusters.Context, &ecs.StopTaskInput{ Cluster: clusterArn, - Task: task, + Task: aws.String(task), Reason: aws.String("Terminating task due to cluster deletion"), }) if err != nil { - logging.Debugf("[TASK] Unable to stop the task %s on cluster %s. Reason: %v", *task, *clusterArn, err) + logging.Debugf("[TASK] Unable to stop the task %s on cluster %s. Reason: %v", task, *clusterArn, err) return errors.WithStackTrace(err) } - logging.Debugf("[TASK] Success, stopped task %v", *task) + logging.Debugf("[TASK] Success, stopped task %v", task) } return nil } @@ -172,29 +171,29 @@ func (clusters *ECSClusters) nukeAll(ecsClusterArns []*string) error { // before nuking the clusters, do check active tasks on the cluster and stop all of them err := clusters.stopClusterRunningTasks(clusterArn) if err != nil { - logging.Debugf("Error, unable to stop the running stasks on the cluster %s %s", aws.StringValue(clusterArn), err) + logging.Debugf("Error, unable to stop the running stasks on the cluster %s %s", aws.ToString(clusterArn), err) return errors.WithStackTrace(err) } params := &ecs.DeleteClusterInput{ Cluster: clusterArn, } - _, err = clusters.Client.DeleteClusterWithContext(clusters.Context, params) + _, err = clusters.Client.DeleteCluster(clusters.Context, params) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(clusterArn), + Identifier: aws.ToString(clusterArn), ResourceType: "ECS Cluster", Error: err, } report.Record(e) if err != nil { - logging.Debugf("Error, failed to delete cluster with ARN %s %s", aws.StringValue(clusterArn), err) + logging.Debugf("Error, failed to delete cluster with ARN %s %s", aws.ToString(clusterArn), err) return errors.WithStackTrace(err) } - logging.Debugf("Success, deleted cluster: %s", aws.StringValue(clusterArn)) + logging.Debugf("Success, deleted cluster: %s", aws.ToString(clusterArn)) nukedEcsClusters = append(nukedEcsClusters, clusterArn) } @@ -210,7 +209,7 @@ func (clusters *ECSClusters) setFirstSeenTag(clusterArn *string, timestamp time. input := &ecs.TagResourceInput{ ResourceArn: clusterArn, - Tags: []*ecs.Tag{ + Tags: []types.Tag{ { Key: aws.String(firstSeenTagKey), Value: aws.String(firstSeenTime), @@ -218,7 +217,7 @@ func (clusters *ECSClusters) setFirstSeenTag(clusterArn *string, timestamp time. }, } - _, err := clusters.Client.TagResource(input) + _, err := clusters.Client.TagResource(clusters.Context, input) if err != nil { return errors.WithStackTrace(err) } @@ -234,9 +233,9 @@ func (clusters *ECSClusters) getFirstSeenTag(clusterArn *string) (*time.Time, er ResourceArn: clusterArn, } - clusterTags, err := clusters.Client.ListTagsForResource(input) + clusterTags, err := clusters.Client.ListTagsForResource(clusters.Context, input) if err != nil { - logging.Debugf("Error getting the tags for ECS cluster with ARN %s", aws.StringValue(clusterArn)) + logging.Debugf("Error getting the tags for ECS cluster with ARN %s", aws.ToString(clusterArn)) return firstSeenTime, errors.WithStackTrace(err) } @@ -245,7 +244,7 @@ func (clusters *ECSClusters) getFirstSeenTag(clusterArn *string) (*time.Time, er firstSeenTime, err := util.ParseTimestamp(tag.Value) if err != nil { - logging.Debugf("Error parsing the `cloud-nuke-first-seen` tag for ECS cluster with ARN %s", aws.StringValue(clusterArn)) + logging.Debugf("Error parsing the `cloud-nuke-first-seen` tag for ECS cluster with ARN %s", aws.ToString(clusterArn)) return firstSeenTime, errors.WithStackTrace(err) } diff --git a/aws/resources/ecs_cluster_test.go b/aws/resources/ecs_cluster_test.go index 0ebc19a3..43a3084a 100644 --- a/aws/resources/ecs_cluster_test.go +++ b/aws/resources/ecs_cluster_test.go @@ -6,57 +6,55 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ecs" - "github.com/aws/aws-sdk-go/service/ecs/ecsiface" + "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/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/util" "github.com/stretchr/testify/require" ) type mockedEC2Cluster struct { - ecsiface.ECSAPI - ListClustersOutput ecs.ListClustersOutput + ECSClustersAPI DescribeClustersOutput ecs.DescribeClustersOutput - TagResourceOutput ecs.TagResourceOutput - ListTagsForResourceOutput ecs.ListTagsForResourceOutput DeleteClusterOutput ecs.DeleteClusterOutput + ListClustersOutput ecs.ListClustersOutput + ListTagsForResourceOutput ecs.ListTagsForResourceOutput ListTasksOutput ecs.ListTasksOutput StopTaskOutput ecs.StopTaskOutput + TagResourceOutput ecs.TagResourceOutput } -func (m mockedEC2Cluster) ListClustersWithContext(_ aws.Context, _ *ecs.ListClustersInput, _ ...request.Option) (*ecs.ListClustersOutput, error) { - return &m.ListClustersOutput, nil -} - -func (m mockedEC2Cluster) DescribeClustersWithContext(_ aws.Context, _ *ecs.DescribeClustersInput, _ ...request.Option) (*ecs.DescribeClustersOutput, error) { +func (m mockedEC2Cluster) DescribeClusters(ctx context.Context, params *ecs.DescribeClustersInput, optFns ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error) { return &m.DescribeClustersOutput, nil } -func (m mockedEC2Cluster) TagResource(*ecs.TagResourceInput) (*ecs.TagResourceOutput, error) { - return &m.TagResourceOutput, nil +func (m mockedEC2Cluster) DeleteCluster(ctx context.Context, params *ecs.DeleteClusterInput, optFns ...func(*ecs.Options)) (*ecs.DeleteClusterOutput, error) { + return &m.DeleteClusterOutput, nil } -func (m mockedEC2Cluster) ListTagsForResource(*ecs.ListTagsForResourceInput) (*ecs.ListTagsForResourceOutput, error) { - return &m.ListTagsForResourceOutput, nil +func (m mockedEC2Cluster) ListClusters(ctx context.Context, params *ecs.ListClustersInput, optFns ...func(*ecs.Options)) (*ecs.ListClustersOutput, error) { + return &m.ListClustersOutput, nil } -func (m mockedEC2Cluster) DeleteClusterWithContext(_ aws.Context, _ *ecs.DeleteClusterInput, _ ...request.Option) (*ecs.DeleteClusterOutput, error) { - return &m.DeleteClusterOutput, nil +func (m mockedEC2Cluster) ListTagsForResource(ctx context.Context, params *ecs.ListTagsForResourceInput, optFns ...func(*ecs.Options)) (*ecs.ListTagsForResourceOutput, error) { + return &m.ListTagsForResourceOutput, nil } -func (m mockedEC2Cluster) ListTasksWithContext(_ aws.Context, _ *ecs.ListTasksInput, _ ...request.Option) (*ecs.ListTasksOutput, error) { +func (m mockedEC2Cluster) ListTasks(ctx context.Context, params *ecs.ListTasksInput, optFns ...func(*ecs.Options)) (*ecs.ListTasksOutput, error) { return &m.ListTasksOutput, nil } -func (m mockedEC2Cluster) StopTaskWithContext(_ aws.Context, _ *ecs.StopTaskInput, _ ...request.Option) (*ecs.StopTaskOutput, error) { + +func (m mockedEC2Cluster) StopTask(ctx context.Context, params *ecs.StopTaskInput, optFns ...func(*ecs.Options)) (*ecs.StopTaskOutput, error) { return &m.StopTaskOutput, nil } -func TestEC2Cluster_GetAll(t *testing.T) { +func (m mockedEC2Cluster) TagResource(ctx context.Context, params *ecs.TagResourceInput, optFns ...func(*ecs.Options)) (*ecs.TagResourceOutput, error) { + return &m.TagResourceOutput, nil +} +func TestEC2Cluster_GetAll(t *testing.T) { t.Parallel() - // Set excludeFirstSeenTag to false for testing ctx := context.WithValue(context.Background(), util.ExcludeFirstSeenTagKey, false) @@ -68,14 +66,14 @@ func TestEC2Cluster_GetAll(t *testing.T) { ec := ECSClusters{ Client: mockedEC2Cluster{ ListClustersOutput: ecs.ListClustersOutput{ - ClusterArns: []*string{ - aws.String(testArn1), - aws.String(testArn2), + ClusterArns: []string{ + testArn1, + testArn2, }, }, DescribeClustersOutput: ecs.DescribeClustersOutput{ - Clusters: []*ecs.Cluster{ + Clusters: []types.Cluster{ { ClusterArn: aws.String(testArn1), Status: aws.String("ACTIVE"), @@ -90,7 +88,7 @@ func TestEC2Cluster_GetAll(t *testing.T) { }, ListTagsForResourceOutput: ecs.ListTagsForResourceOutput{ - Tags: []*ecs.Tag{ + Tags: []types.Tag{ { Key: aws.String(util.FirstSeenTagKey), Value: aws.String(util.FormatTimestamp(now)), @@ -98,9 +96,9 @@ func TestEC2Cluster_GetAll(t *testing.T) { }, }, ListTasksOutput: ecs.ListTasksOutput{ - TaskArns: []*string{ - aws.String("task-arn-001"), - aws.String("task-arn-002"), + TaskArns: []string{ + "task-arn-001", + "task-arn-002", }, }, }, @@ -141,16 +139,13 @@ func TestEC2Cluster_GetAll(t *testing.T) { ECSCluster: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } - } func TestEC2Cluster_NukeAll(t *testing.T) { - t.Parallel() - ec := ECSClusters{ Client: mockedEC2Cluster{ DeleteClusterOutput: ecs.DeleteClusterOutput{}, @@ -162,16 +157,14 @@ func TestEC2Cluster_NukeAll(t *testing.T) { } func TestEC2ClusterWithTasks_NukeAll(t *testing.T) { - t.Parallel() - ec := ECSClusters{ Client: mockedEC2Cluster{ DeleteClusterOutput: ecs.DeleteClusterOutput{}, ListTasksOutput: ecs.ListTasksOutput{ - TaskArns: []*string{ - aws.String("task-arn-001"), - aws.String("task-arn-002"), + TaskArns: []string{ + "task-arn-001", + "task-arn-002", }, }, }, diff --git a/aws/resources/ecs_cluster_types.go b/aws/resources/ecs_cluster_types.go index 0cac8c27..74fb75e2 100644 --- a/aws/resources/ecs_cluster_types.go +++ b/aws/resources/ecs_cluster_types.go @@ -3,26 +3,36 @@ package resources import ( "context" - awsgo "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/service/ecs/ecsiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type ECSClustersAPI interface { + DescribeClusters(ctx context.Context, params *ecs.DescribeClustersInput, optFns ...func(*ecs.Options)) (*ecs.DescribeClustersOutput, error) + DeleteCluster(ctx context.Context, params *ecs.DeleteClusterInput, optFns ...func(*ecs.Options)) (*ecs.DeleteClusterOutput, error) + ListClusters(ctx context.Context, params *ecs.ListClustersInput, optFns ...func(*ecs.Options)) (*ecs.ListClustersOutput, error) + ListTagsForResource(ctx context.Context, params *ecs.ListTagsForResourceInput, optFns ...func(*ecs.Options)) (*ecs.ListTagsForResourceOutput, error) + ListTasks(ctx context.Context, params *ecs.ListTasksInput, optFns ...func(*ecs.Options)) (*ecs.ListTasksOutput, error) + StopTask(ctx context.Context, params *ecs.StopTaskInput, optFns ...func(*ecs.Options)) (*ecs.StopTaskOutput, error) + TagResource(ctx context.Context, params *ecs.TagResourceInput, optFns ...func(*ecs.Options)) (*ecs.TagResourceOutput, error) +} + // ECSClusters - Represents all ECS clusters found in a region type ECSClusters struct { BaseAwsResource - Client ecsiface.ECSAPI + Client ECSClustersAPI Region string ClusterArns []string } -func (clusters *ECSClusters) Init(session *session.Session) { - clusters.Client = ecs.New(session) +func (clusters *ECSClusters) InitV2(cfg aws.Config) { + clusters.Client = ecs.NewFromConfig(cfg) } +func (clusters *ECSClusters) IsUsingV2() bool { return true } + // ResourceName - The simple name of the aws resource func (clusters *ECSClusters) ResourceName() string { return "ecscluster" @@ -47,13 +57,13 @@ func (clusters *ECSClusters) GetAndSetIdentifiers(c context.Context, configObj c return nil, err } - clusters.ClusterArns = awsgo.StringValueSlice(identifiers) + clusters.ClusterArns = aws.ToStringSlice(identifiers) return clusters.ClusterArns, nil } // Nuke - nuke all ECS Cluster resources func (clusters *ECSClusters) Nuke(identifiers []string) error { - if err := clusters.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := clusters.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } return nil diff --git a/aws/resources/ecs_service.go b/aws/resources/ecs_service.go index 7df13b3e..20a46dc3 100644 --- a/aws/resources/ecs_service.go +++ b/aws/resources/ecs_service.go @@ -2,38 +2,38 @@ package resources import ( "context" + "time" - "github.com/gruntwork-io/cloud-nuke/util" - - "github.com/aws/aws-sdk-go/aws" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ecs" + "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/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" + "github.com/gruntwork-io/cloud-nuke/util" "github.com/gruntwork-io/go-commons/errors" ) // getAllEcsClusters - Returns a string of ECS Cluster ARNs, which uniquely identifies the cluster. // We need to get all clusters before we can get all services. func (services *ECSServices) getAllEcsClusters() ([]*string, error) { - clusterArns := []*string{} - result, err := services.Client.ListClustersWithContext(services.Context, &ecs.ListClustersInput{}) + var clusterArns []string + result, err := services.Client.ListClusters(services.Context, &ecs.ListClustersInput{}) if err != nil { return nil, errors.WithStackTrace(err) } clusterArns = append(clusterArns, result.ClusterArns...) // Handle pagination: continuously pull the next page if nextToken is set - for awsgo.StringValue(result.NextToken) != "" { - result, err = services.Client.ListClustersWithContext(services.Context, &ecs.ListClustersInput{NextToken: result.NextToken}) + for aws.ToString(result.NextToken) != "" { + result, err = services.Client.ListClusters(services.Context, &ecs.ListClustersInput{NextToken: result.NextToken}) if err != nil { return nil, errors.WithStackTrace(err) } clusterArns = append(clusterArns, result.ClusterArns...) } - return clusterArns, nil + return aws.StringSlice(clusterArns), nil } // filterOutRecentServices - Given a list of services and an excludeAfter @@ -47,9 +47,9 @@ func (services *ECSServices) filterOutRecentServices(clusterArn *string, ecsServ for _, batch := range batches { params := &ecs.DescribeServicesInput{ Cluster: clusterArn, - Services: awsgo.StringSlice(batch), + Services: batch, } - describeResult, err := services.Client.DescribeServicesWithContext(services.Context, params) + describeResult, err := services.Client.DescribeServices(services.Context, params) if err != nil { return nil, errors.WithStackTrace(err) } @@ -82,11 +82,11 @@ func (services *ECSServices) getAll(c context.Context, configObj config.Config) // ones. var ecsServiceArns []*string for _, clusterArn := range ecsClusterArns { - result, err := services.Client.ListServicesWithContext(services.Context, &ecs.ListServicesInput{Cluster: clusterArn}) + result, err := services.Client.ListServices(services.Context, &ecs.ListServicesInput{Cluster: clusterArn}) if err != nil { return nil, errors.WithStackTrace(err) } - filteredServiceArns, err := services.filterOutRecentServices(clusterArn, awsgo.StringValueSlice(result.ServiceArns), configObj) + filteredServiceArns, err := services.filterOutRecentServices(clusterArn, result.ServiceArns, configObj) if err != nil { return nil, errors.WithStackTrace(err) } @@ -109,24 +109,24 @@ func (services *ECSServices) drainEcsServices(ecsServiceArns []*string) []*strin for _, ecsServiceArn := range ecsServiceArns { describeParams := &ecs.DescribeServicesInput{ - Cluster: awsgo.String(services.ServiceClusterMap[*ecsServiceArn]), - Services: []*string{ecsServiceArn}, + Cluster: aws.String(services.ServiceClusterMap[*ecsServiceArn]), + Services: []string{*ecsServiceArn}, } - describeServicesOutput, err := services.Client.DescribeServicesWithContext(services.Context, describeParams) + describeServicesOutput, err := services.Client.DescribeServices(services.Context, describeParams) if err != nil { logging.Errorf("[Failed] Failed to describe service %s: %s", *ecsServiceArn, err) } else { - schedulingStrategy := *describeServicesOutput.Services[0].SchedulingStrategy - if schedulingStrategy == "DAEMON" { + schedulingStrategy := describeServicesOutput.Services[0].SchedulingStrategy + if schedulingStrategy == types.SchedulingStrategyDaemon { requestedDrains = append(requestedDrains, ecsServiceArn) } else { params := &ecs.UpdateServiceInput{ - Cluster: awsgo.String(services.ServiceClusterMap[*ecsServiceArn]), + Cluster: aws.String(services.ServiceClusterMap[*ecsServiceArn]), Service: ecsServiceArn, - DesiredCount: awsgo.Int64(0), + DesiredCount: aws.Int32(0), } - _, err = services.Client.UpdateServiceWithContext(services.Context, params) + _, err = services.Client.UpdateService(services.Context, params) if err != nil { logging.Errorf("[Failed] Failed to drain service %s: %s", *ecsServiceArn, err) } else { @@ -146,10 +146,12 @@ func (services *ECSServices) waitUntilServicesDrained(ecsServiceArns []*string) var successfullyDrained []*string for _, ecsServiceArn := range ecsServiceArns { params := &ecs.DescribeServicesInput{ - Cluster: awsgo.String(services.ServiceClusterMap[*ecsServiceArn]), - Services: []*string{ecsServiceArn}, + Cluster: aws.String(services.ServiceClusterMap[*ecsServiceArn]), + Services: []string{*ecsServiceArn}, } - err := services.Client.WaitUntilServicesStableWithContext(services.Context, params) + + waiter := ecs.NewServicesStableWaiter(services.Client) + err := waiter.Wait(services.Context, params, 15*time.Minute) if err != nil { logging.Debugf("[Failed] Failed waiting for service to be stable %s: %s", *ecsServiceArn, err) } else { @@ -166,10 +168,10 @@ func (services *ECSServices) deleteEcsServices(ecsServiceArns []*string) []*stri var requestedDeletes []*string for _, ecsServiceArn := range ecsServiceArns { params := &ecs.DeleteServiceInput{ - Cluster: awsgo.String(services.ServiceClusterMap[*ecsServiceArn]), + Cluster: aws.String(services.ServiceClusterMap[*ecsServiceArn]), Service: ecsServiceArn, } - _, err := services.Client.DeleteServiceWithContext(services.Context, params) + _, err := services.Client.DeleteService(services.Context, params) if err != nil { logging.Debugf("[Failed] Failed deleting service %s: %s", *ecsServiceArn, err) } else { @@ -186,14 +188,16 @@ func (services *ECSServices) waitUntilServicesDeleted(ecsServiceArns []*string) var successfullyDeleted []*string for _, ecsServiceArn := range ecsServiceArns { params := &ecs.DescribeServicesInput{ - Cluster: awsgo.String(services.ServiceClusterMap[*ecsServiceArn]), - Services: []*string{ecsServiceArn}, + Cluster: aws.String(services.ServiceClusterMap[*ecsServiceArn]), + Services: []string{*ecsServiceArn}, } - err := services.Client.WaitUntilServicesInactiveWithContext(services.Context, params) + + waiter := ecs.NewServicesInactiveWaiter(services.Client) + err := waiter.Wait(services.Context, params, 15*time.Minute) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(ecsServiceArn), + Identifier: aws.ToString(ecsServiceArn), ResourceType: "ECS Service", Error: err, } diff --git a/aws/resources/ecs_service_test.go b/aws/resources/ecs_service_test.go index 5b06f179..392ea943 100644 --- a/aws/resources/ecs_service_test.go +++ b/aws/resources/ecs_service_test.go @@ -6,55 +6,44 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ecs" - "github.com/aws/aws-sdk-go/service/ecs/ecsiface" + "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/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedEC2Service struct { - ecsiface.ECSAPI + ECSServicesAPI ListClustersOutput ecs.ListClustersOutput - DescribeServicesOutput ecs.DescribeServicesOutput ListServicesOutput ecs.ListServicesOutput - UpdateServiceOutput ecs.UpdateServiceOutput + DescribeServicesOutput ecs.DescribeServicesOutput DeleteServiceOutput ecs.DeleteServiceOutput + UpdateServiceOutput ecs.UpdateServiceOutput } -func (m mockedEC2Service) ListClustersWithContext(_ aws.Context, _ *ecs.ListClustersInput, _ ...request.Option) (*ecs.ListClustersOutput, error) { +func (m mockedEC2Service) ListClusters(ctx context.Context, params *ecs.ListClustersInput, optFns ...func(*ecs.Options)) (*ecs.ListClustersOutput, error) { return &m.ListClustersOutput, nil } -func (m mockedEC2Service) DescribeServicesWithContext(_ aws.Context, _ *ecs.DescribeServicesInput, _ ...request.Option) (*ecs.DescribeServicesOutput, error) { - return &m.DescribeServicesOutput, nil -} - -func (m mockedEC2Service) ListServicesWithContext(_ aws.Context, _ *ecs.ListServicesInput, _ ...request.Option) (*ecs.ListServicesOutput, error) { +func (m mockedEC2Service) ListServices(ctx context.Context, params *ecs.ListServicesInput, optFns ...func(*ecs.Options)) (*ecs.ListServicesOutput, error) { return &m.ListServicesOutput, nil } -func (m mockedEC2Service) UpdateServiceWithContext(_ aws.Context, _ *ecs.UpdateServiceInput, _ ...request.Option) (*ecs.UpdateServiceOutput, error) { - return &m.UpdateServiceOutput, nil -} - -func (m mockedEC2Service) WaitUntilServicesStableWithContext(_ aws.Context, _ *ecs.DescribeServicesInput, _ ...request.WaiterOption) error { - return nil +func (m mockedEC2Service) DescribeServices(ctx context.Context, params *ecs.DescribeServicesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error) { + return &m.DescribeServicesOutput, nil } -func (m mockedEC2Service) DeleteServiceWithContext(_ aws.Context, _ *ecs.DeleteServiceInput, _ ...request.Option) (*ecs.DeleteServiceOutput, error) { +func (m mockedEC2Service) DeleteService(ctx context.Context, params *ecs.DeleteServiceInput, optFns ...func(*ecs.Options)) (*ecs.DeleteServiceOutput, error) { return &m.DeleteServiceOutput, nil } -func (m mockedEC2Service) WaitUntilServicesInactiveWithContext(_ aws.Context, _ *ecs.DescribeServicesInput, _ ...request.WaiterOption) error { - return nil +func (m mockedEC2Service) UpdateService(ctx context.Context, params *ecs.UpdateServiceInput, optFns ...func(*ecs.Options)) (*ecs.UpdateServiceOutput, error) { + return &m.UpdateServiceOutput, nil } func TestEC2Service_GetAll(t *testing.T) { - t.Parallel() - testArn1 := "testArn1" testArn2 := "testArn2" testName1 := "testService1" @@ -63,17 +52,17 @@ func TestEC2Service_GetAll(t *testing.T) { es := ECSServices{ Client: mockedEC2Service{ ListClustersOutput: ecs.ListClustersOutput{ - ClusterArns: []*string{ - aws.String(testArn1), + ClusterArns: []string{ + testArn1, }, }, ListServicesOutput: ecs.ListServicesOutput{ - ServiceArns: []*string{ - aws.String(testArn1), + ServiceArns: []string{ + testArn1, }, }, DescribeServicesOutput: ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { ServiceArn: aws.String(testArn1), ServiceName: aws.String(testName1), @@ -120,23 +109,25 @@ func TestEC2Service_GetAll(t *testing.T) { ECSService: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } func TestEC2Service_NukeAll(t *testing.T) { - t.Parallel() - es := ECSServices{ + BaseAwsResource: BaseAwsResource{ + Context: context.Background(), + }, Client: mockedEC2Service{ DescribeServicesOutput: ecs.DescribeServicesOutput{ - Services: []*ecs.Service{ + Services: []types.Service{ { + SchedulingStrategy: types.SchedulingStrategyDaemon, ServiceArn: aws.String("testArn1"), - SchedulingStrategy: aws.String(ecs.SchedulingStrategyDaemon), + Status: aws.String("DRAINING"), }, }, }, diff --git a/aws/resources/ecs_service_types.go b/aws/resources/ecs_service_types.go index 8f508bed..d6bd3510 100644 --- a/aws/resources/ecs_service_types.go +++ b/aws/resources/ecs_service_types.go @@ -3,27 +3,35 @@ package resources import ( "context" - awsgo "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/service/ecs/ecsiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ecs" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type ECSServicesAPI interface { + ListClusters(ctx context.Context, params *ecs.ListClustersInput, optFns ...func(*ecs.Options)) (*ecs.ListClustersOutput, error) + ListServices(ctx context.Context, params *ecs.ListServicesInput, optFns ...func(*ecs.Options)) (*ecs.ListServicesOutput, error) + DescribeServices(ctx context.Context, params *ecs.DescribeServicesInput, optFns ...func(*ecs.Options)) (*ecs.DescribeServicesOutput, error) + DeleteService(ctx context.Context, params *ecs.DeleteServiceInput, optFns ...func(*ecs.Options)) (*ecs.DeleteServiceOutput, error) + UpdateService(ctx context.Context, params *ecs.UpdateServiceInput, optFns ...func(*ecs.Options)) (*ecs.UpdateServiceOutput, error) +} + // ECSServices - Represents all ECS services found in a region type ECSServices struct { BaseAwsResource - Client ecsiface.ECSAPI + Client ECSServicesAPI Region string Services []string ServiceClusterMap map[string]string } -func (services *ECSServices) Init(session *session.Session) { - services.Client = ecs.New(session) +func (services *ECSServices) InitV2(cfg aws.Config) { + services.Client = ecs.NewFromConfig(cfg) } +func (services *ECSServices) IsUsingV2() bool { return true } + // ResourceName - The simple name of the aws resource func (services *ECSServices) ResourceName() string { return "ecsserv" @@ -48,13 +56,13 @@ func (services *ECSServices) GetAndSetIdentifiers(c context.Context, configObj c return nil, err } - services.Services = awsgo.StringValueSlice(identifiers) + services.Services = aws.ToStringSlice(identifiers) return services.Services, nil } // Nuke - nuke all ECS service resources func (services *ECSServices) Nuke(identifiers []string) error { - if err := services.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := services.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } return nil diff --git a/aws/resources/efs.go b/aws/resources/efs.go index b4a860f0..4502964c 100644 --- a/aws/resources/efs.go +++ b/aws/resources/efs.go @@ -5,8 +5,8 @@ import ( "sync" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/efs" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -15,24 +15,26 @@ import ( ) func (ef *ElasticFileSystem) getAll(c context.Context, configObj config.Config) ([]*string, error) { + var allEfs []*string - allEfs := []*string{} - err := ef.Client.DescribeFileSystemsPagesWithContext( - ef.Context, - &efs.DescribeFileSystemsInput{}, func(page *efs.DescribeFileSystemsOutput, lastPage bool) bool { - for _, system := range page.FileSystems { - if configObj.ElasticFileSystem.ShouldInclude(config.ResourceValue{ - Name: system.Name, - Time: system.CreationTime, - }) { - allEfs = append(allEfs, system.FileSystemId) - } - } + paginator := efs.NewDescribeFileSystemsPaginator(ef.Client, &efs.DescribeFileSystemsInput{}) + for paginator.HasMorePages() { + page, err := paginator.NextPage(c) + if err != nil { + return nil, errors.WithStackTrace(err) + } - return !lastPage - }) + for _, system := range page.FileSystems { + if configObj.ElasticFileSystem.ShouldInclude(config.ResourceValue{ + Name: system.Name, + Time: system.CreationTime, + }) { + allEfs = append(allEfs, system.FileSystemId) + } + } + } - return allEfs, err + return allEfs, nil } func (ef *ElasticFileSystem) nukeAll(identifiers []*string) error { @@ -79,13 +81,13 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, // First, we need to check if the Elastic FileSystem is "in-use", because an in-use file system cannot be deleted // An Elastic FileSystem is considered in-use if it has any access points, or any mount targets // Here, we first look up and delete any and all access points for the given Elastic FileSystem - accessPointIds := []*string{} + var accessPointIds []*string accessPointParam := &efs.DescribeAccessPointsInput{ FileSystemId: efsID, } - out, err := ef.Client.DescribeAccessPointsWithContext(ef.Context, accessPointParam) + out, err := ef.Client.DescribeAccessPoints(ef.Context, accessPointParam) if err != nil { allErrs = multierror.Append(allErrs, err) } @@ -100,13 +102,13 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, AccessPointId: apID, } - logging.Debugf("Deleting access point (id=%s) for Elastic FileSystem (%s) in region: %s", aws.StringValue(apID), aws.StringValue(efsID), ef.Region) + logging.Debugf("Deleting access point (id=%s) for Elastic FileSystem (%s) in region: %s", aws.ToString(apID), aws.ToString(efsID), ef.Region) - _, err := ef.Client.DeleteAccessPointWithContext(ef.Context, deleteParam) + _, err := ef.Client.DeleteAccessPoint(ef.Context, deleteParam) if err != nil { allErrs = multierror.Append(allErrs, err) } else { - logging.Debugf("[OK] Deleted access point (id=%s) for Elastic FileSystem (%s) in region: %s", aws.StringValue(apID), aws.StringValue(efsID), ef.Region) + logging.Debugf("[OK] Deleted access point (id=%s) for Elastic FileSystem (%s) in region: %s", aws.ToString(apID), aws.ToString(efsID), ef.Region) } } @@ -117,7 +119,7 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, done := false var marker *string - mountTargetIds := []*string{} + var mountTargetIds []*string for !done { @@ -126,11 +128,11 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, } // If the last iteration had a marker set, use it - if aws.StringValue(marker) != "" { + if aws.ToString(marker) != "" { mountTargetParam.Marker = marker } - mountTargetsOutput, describeMountsErr := ef.Client.DescribeMountTargetsWithContext(ef.Context, mountTargetParam) + mountTargetsOutput, describeMountsErr := ef.Client.DescribeMountTargets(ef.Context, mountTargetParam) if describeMountsErr != nil { allErrs = multierror.Append(allErrs, err) } @@ -140,7 +142,7 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, } // If the response contained a NextMarker field, set it as the next iteration's marker - if aws.StringValue(mountTargetsOutput.NextMarker) != "" { + if aws.ToString(mountTargetsOutput.NextMarker) != "" { marker = mountTargetsOutput.NextMarker } else { // There's no NextMarker set on the response, so we're done enumerating mount targets @@ -153,13 +155,13 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, MountTargetId: mtID, } - logging.Debugf("Deleting mount target (id=%s) for Elastic FileSystem (%s) in region: %s", aws.StringValue(mtID), aws.StringValue(efsID), ef.Region) + logging.Debugf("Deleting mount target (id=%s) for Elastic FileSystem (%s) in region: %s", aws.ToString(mtID), aws.ToString(efsID), ef.Region) - _, err := ef.Client.DeleteMountTargetWithContext(ef.Context, deleteMtParam) + _, err := ef.Client.DeleteMountTarget(ef.Context, deleteMtParam) if err != nil { allErrs = multierror.Append(allErrs, err) } else { - logging.Debugf("[OK] Deleted mount target (id=%s) for Elastic FileSystem (%s) in region: %s", aws.StringValue(mtID), aws.StringValue(efsID), ef.Region) + logging.Debugf("[OK] Deleted mount target (id=%s) for Elastic FileSystem (%s) in region: %s", aws.ToString(mtID), aws.ToString(efsID), ef.Region) } } @@ -171,10 +173,10 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, FileSystemId: efsID, } - _, deleteErr := ef.Client.DeleteFileSystemWithContext(ef.Context, deleteEfsParam) + _, deleteErr := ef.Client.DeleteFileSystem(ef.Context, deleteEfsParam) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(efsID), + Identifier: aws.ToString(efsID), ResourceType: "Elastic FileSystem (EFS)", Error: err, } @@ -185,8 +187,8 @@ func (ef *ElasticFileSystem) deleteAsync(wg *sync.WaitGroup, errChan chan error, } if err == nil { - logging.Debugf("[OK] Elastic FileSystem (efs) %s deleted in %s", aws.StringValue(efsID), ef.Region) + logging.Debugf("[OK] Elastic FileSystem (efs) %s deleted in %s", aws.ToString(efsID), ef.Region) } else { - logging.Debugf("[Failed] Error deleting Elastic FileSystem (efs) %s in %s", aws.StringValue(efsID), ef.Region) + logging.Debugf("[Failed] Error deleting Elastic FileSystem (efs) %s in %s", aws.ToString(efsID), ef.Region) } } diff --git a/aws/resources/efs_test.go b/aws/resources/efs_test.go index 72d91299..91f95acb 100644 --- a/aws/resources/efs_test.go +++ b/aws/resources/efs_test.go @@ -6,53 +6,48 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/efs" - "github.com/aws/aws-sdk-go/service/efs/efsiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/efs" + "github.com/aws/aws-sdk-go-v2/service/efs/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedElasticFileSystem struct { - efsiface.EFSAPI - DescribeFileSystemsPagesOutput efs.DescribeFileSystemsOutput - DescribeAccessPointsOutput efs.DescribeAccessPointsOutput - DeleteAccessPointOutput efs.DeleteAccessPointOutput - DescribeMountTargetsOutput efs.DescribeMountTargetsOutput - DeleteMountTargetOutput efs.DeleteMountTargetOutput - DeleteFileSystemOutput efs.DeleteFileSystemOutput + DeleteAccessPointOutput efs.DeleteAccessPointOutput + DeleteFileSystemOutput efs.DeleteFileSystemOutput + DeleteMountTargetOutput efs.DeleteMountTargetOutput + DescribeAccessPointsOutput efs.DescribeAccessPointsOutput + DescribeMountTargetsOutput efs.DescribeMountTargetsOutput + DescribeFileSystemsOutput efs.DescribeFileSystemsOutput } -func (m mockedElasticFileSystem) DescribeFileSystemsPagesWithContext(_ aws.Context, input *efs.DescribeFileSystemsInput, callback func(*efs.DescribeFileSystemsOutput, bool) bool, _ ...request.Option) error { - callback(&m.DescribeFileSystemsPagesOutput, true) - return nil +func (m mockedElasticFileSystem) DeleteAccessPoint(ctx context.Context, params *efs.DeleteAccessPointInput, optFns ...func(*efs.Options)) (*efs.DeleteAccessPointOutput, error) { + return &m.DeleteAccessPointOutput, nil } -func (m mockedElasticFileSystem) DescribeAccessPointsWithContext(_ aws.Context, input *efs.DescribeAccessPointsInput, _ ...request.Option) (*efs.DescribeAccessPointsOutput, error) { - return &m.DescribeAccessPointsOutput, nil +func (m mockedElasticFileSystem) DeleteFileSystem(ctx context.Context, params *efs.DeleteFileSystemInput, optFns ...func(*efs.Options)) (*efs.DeleteFileSystemOutput, error) { + return &m.DeleteFileSystemOutput, nil } -func (m mockedElasticFileSystem) DeleteAccessPointWithContext(_ aws.Context, input *efs.DeleteAccessPointInput, _ ...request.Option) (*efs.DeleteAccessPointOutput, error) { - return &m.DeleteAccessPointOutput, nil +func (m mockedElasticFileSystem) DeleteMountTarget(ctx context.Context, params *efs.DeleteMountTargetInput, optFns ...func(*efs.Options)) (*efs.DeleteMountTargetOutput, error) { + return &m.DeleteMountTargetOutput, nil } -func (m mockedElasticFileSystem) DescribeMountTargetsWithContext(_ aws.Context, input *efs.DescribeMountTargetsInput, _ ...request.Option) (*efs.DescribeMountTargetsOutput, error) { - return &m.DescribeMountTargetsOutput, nil +func (m mockedElasticFileSystem) DescribeAccessPoints(ctx context.Context, params *efs.DescribeAccessPointsInput, optFns ...func(*efs.Options)) (*efs.DescribeAccessPointsOutput, error) { + return &m.DescribeAccessPointsOutput, nil } -func (m mockedElasticFileSystem) DeleteMountTargetWithContext(_ aws.Context, input *efs.DeleteMountTargetInput, _ ...request.Option) (*efs.DeleteMountTargetOutput, error) { - return &m.DeleteMountTargetOutput, nil +func (m mockedElasticFileSystem) DescribeMountTargets(ctx context.Context, params *efs.DescribeMountTargetsInput, optFns ...func(*efs.Options)) (*efs.DescribeMountTargetsOutput, error) { + return &m.DescribeMountTargetsOutput, nil } -func (m mockedElasticFileSystem) DeleteFileSystemWithContext(_ aws.Context, input *efs.DeleteFileSystemInput, _ ...request.Option) (*efs.DeleteFileSystemOutput, error) { - return &m.DeleteFileSystemOutput, nil +func (m mockedElasticFileSystem) DescribeFileSystems(ctx context.Context, params *efs.DescribeFileSystemsInput, optFns ...func(*efs.Options)) (*efs.DescribeFileSystemsOutput, error) { + return &m.DescribeFileSystemsOutput, nil } func TestEFS_GetAll(t *testing.T) { - t.Parallel() - testId1 := "testId1" testName1 := "test-efs1" testId2 := "testId2" @@ -60,8 +55,8 @@ func TestEFS_GetAll(t *testing.T) { now := time.Now() ef := ElasticFileSystem{ Client: mockedElasticFileSystem{ - DescribeFileSystemsPagesOutput: efs.DescribeFileSystemsOutput{ - FileSystems: []*efs.FileSystemDescription{ + DescribeFileSystemsOutput: efs.DescribeFileSystemsOutput{ + FileSystems: []types.FileSystemDescription{ { FileSystemId: aws.String(testId1), Name: aws.String(testName1), @@ -108,28 +103,24 @@ func TestEFS_GetAll(t *testing.T) { ElasticFileSystem: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } - } func TestEFS_NukeAll(t *testing.T) { - t.Parallel() - ef := ElasticFileSystem{ Client: mockedElasticFileSystem{ - DescribeAccessPointsOutput: efs.DescribeAccessPointsOutput{ - AccessPoints: []*efs.AccessPointDescription{ + AccessPoints: []types.AccessPointDescription{ { AccessPointId: aws.String("fsap-1234567890abcdef0"), }, }, }, DescribeMountTargetsOutput: efs.DescribeMountTargetsOutput{ - MountTargets: []*efs.MountTargetDescription{ + MountTargets: []types.MountTargetDescription{ { MountTargetId: aws.String("fsmt-1234567890abcdef0"), }, diff --git a/aws/resources/efs_types.go b/aws/resources/efs_types.go index a88fcd6f..50187c38 100644 --- a/aws/resources/efs_types.go +++ b/aws/resources/efs_types.go @@ -3,25 +3,34 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/efs" - "github.com/aws/aws-sdk-go/service/efs/efsiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/efs" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type ElasticFileSystemAPI interface { + DeleteAccessPoint(ctx context.Context, params *efs.DeleteAccessPointInput, optFns ...func(*efs.Options)) (*efs.DeleteAccessPointOutput, error) + DeleteFileSystem(ctx context.Context, params *efs.DeleteFileSystemInput, optFns ...func(*efs.Options)) (*efs.DeleteFileSystemOutput, error) + DeleteMountTarget(ctx context.Context, params *efs.DeleteMountTargetInput, optFns ...func(*efs.Options)) (*efs.DeleteMountTargetOutput, error) + DescribeAccessPoints(ctx context.Context, params *efs.DescribeAccessPointsInput, optFns ...func(*efs.Options)) (*efs.DescribeAccessPointsOutput, error) + DescribeMountTargets(ctx context.Context, params *efs.DescribeMountTargetsInput, optFns ...func(*efs.Options)) (*efs.DescribeMountTargetsOutput, error) + DescribeFileSystems(ctx context.Context, params *efs.DescribeFileSystemsInput, optFns ...func(*efs.Options)) (*efs.DescribeFileSystemsOutput, error) +} + type ElasticFileSystem struct { BaseAwsResource - Client efsiface.EFSAPI + Client ElasticFileSystemAPI Region string Ids []string } -func (ef *ElasticFileSystem) Init(session *session.Session) { - ef.Client = efs.New(session) +func (ef *ElasticFileSystem) InitV2(cfg aws.Config) { + ef.Client = efs.NewFromConfig(cfg) } +func (ef *ElasticFileSystem) IsUsingV2() bool { return true } + func (ef *ElasticFileSystem) ResourceName() string { return "efs" } @@ -44,12 +53,12 @@ func (ef *ElasticFileSystem) GetAndSetIdentifiers(c context.Context, configObj c return nil, err } - ef.Ids = awsgo.StringValueSlice(identifiers) + ef.Ids = aws.ToStringSlice(identifiers) return ef.Ids, nil } func (ef *ElasticFileSystem) Nuke(identifiers []string) error { - if err := ef.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := ef.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/eip.go b/aws/resources/eip.go index 644f75bf..ff0f4577 100644 --- a/aws/resources/eip.go +++ b/aws/resources/eip.go @@ -2,12 +2,13 @@ package resources import ( "context" + goerr "errors" "time" - "github.com/aws/aws-sdk-go/aws" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/ec2" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/aws/smithy-go" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -16,33 +17,33 @@ import ( ) // Returns a formatted string of EIP allocation ids -func (ea *EIPAddresses) getAll(c context.Context, configObj config.Config) ([]*string, error) { +func (eip *EIPAddresses) getAll(c context.Context, configObj config.Config) ([]*string, error) { var firstSeenTime *time.Time var err error - result, err := ea.Client.DescribeAddressesWithContext(ea.Context, &ec2.DescribeAddressesInput{}) + result, err := eip.Client.DescribeAddresses(eip.Context, &ec2.DescribeAddressesInput{}) if err != nil { return nil, errors.WithStackTrace(err) } var allocationIds []*string for _, address := range result.Addresses { - firstSeenTime, err = util.GetOrCreateFirstSeen(c, ea.Client, address.AllocationId, util.ConvertEC2TagsToMap(address.Tags)) + firstSeenTime, err = util.GetOrCreateFirstSeen(c, eip.Client, address.AllocationId, util.ConvertTypesTagsToMap(address.Tags)) if err != nil { logging.Error("unable to retrieve first seen tag") return nil, errors.WithStackTrace(err) } - if ea.shouldInclude(address, firstSeenTime, configObj) { + if eip.shouldInclude(address, firstSeenTime, configObj) { allocationIds = append(allocationIds, address.AllocationId) } } // checking the nukable permissions - ea.VerifyNukablePermissions(allocationIds, func(id *string) error { - _, err := ea.Client.ReleaseAddressWithContext(ea.Context, &ec2.ReleaseAddressInput{ + eip.VerifyNukablePermissions(allocationIds, func(id *string) error { + _, err := eip.Client.ReleaseAddress(eip.Context, &ec2.ReleaseAddressInput{ AllocationId: id, - DryRun: awsgo.Bool(true), + DryRun: aws.Bool(true), }) return err }) @@ -50,52 +51,56 @@ func (ea *EIPAddresses) getAll(c context.Context, configObj config.Config) ([]*s return allocationIds, nil } -func (ea *EIPAddresses) shouldInclude(address *ec2.Address, firstSeenTime *time.Time, configObj config.Config) bool { +func (eip *EIPAddresses) shouldInclude(address types.Address, firstSeenTime *time.Time, configObj config.Config) bool { // If Name is unset, GetEC2ResourceNameTagValue returns error and zero value string // Ignore this error and pass empty string to config.ShouldInclude allocationName := util.GetEC2ResourceNameTagValue(address.Tags) return configObj.ElasticIP.ShouldInclude(config.ResourceValue{ Time: firstSeenTime, Name: allocationName, - Tags: util.ConvertEC2TagsToMap(address.Tags), + Tags: util.ConvertTypesTagsToMap(address.Tags), }) } // Deletes all EIP allocation ids -func (ea *EIPAddresses) nukeAll(allocationIds []*string) error { +func (eip *EIPAddresses) nukeAll(allocationIds []*string) error { if len(allocationIds) == 0 { - logging.Debugf("No Elastic IPs to nuke in region %s", ea.Region) + logging.Debugf("No Elastic IPs to nuke in region %s", eip.Region) return nil } - logging.Debugf("Deleting all Elastic IPs in region %s", ea.Region) + logging.Debugf("Deleting all Elastic IPs in region %s", eip.Region) var deletedAllocationIDs []*string for _, allocationID := range allocationIds { - if nukable, reason := ea.IsNukable(awsgo.StringValue(allocationID)); !nukable { - logging.Debugf("[Skipping] %s nuke because %v", awsgo.StringValue(allocationID), reason) + if nukable, reason := eip.IsNukable(aws.ToString(allocationID)); !nukable { + logging.Debugf("[Skipping] %s nuke because %v", aws.ToString(allocationID), reason) continue } - _, err := ea.Client.ReleaseAddressWithContext(ea.Context, &ec2.ReleaseAddressInput{ + _, err := eip.Client.ReleaseAddress(eip.Context, &ec2.ReleaseAddressInput{ AllocationId: allocationID, }) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(allocationID), + Identifier: aws.ToString(allocationID), ResourceType: "Elastic IP Address (EIP)", Error: err, } report.Record(e) if err != nil { - if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "AuthFailure" { - // TODO: Figure out why we get an AuthFailure - logging.Debugf("EIP %s can't be deleted, it is still attached to an active resource", *allocationID) - } else { - logging.Debugf("[Failed] %s", err) + var apiErr smithy.APIError + if goerr.As(err, &apiErr) { + switch apiErr.ErrorCode() { + case "AuthFailure": + // TODO: Figure out why we get an AuthFailure + logging.Debugf("EIP %s can't be deleted, it is still attached to an active resource", *allocationID) + default: + logging.Debugf("[Failed] %s", err) + } } } else { deletedAllocationIDs = append(deletedAllocationIDs, allocationID) @@ -103,6 +108,6 @@ func (ea *EIPAddresses) nukeAll(allocationIds []*string) error { } } - logging.Debugf("[OK] %d Elastic IP(s) deleted in %s", len(deletedAllocationIDs), ea.Region) + logging.Debugf("[OK] %d Elastic IP(s) deleted in %s", len(deletedAllocationIDs), eip.Region) return nil } diff --git a/aws/resources/eip_test.go b/aws/resources/eip_test.go index f7b5fad7..f60eaf00 100644 --- a/aws/resources/eip_test.go +++ b/aws/resources/eip_test.go @@ -6,31 +6,29 @@ import ( "testing" "time" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/util" "github.com/stretchr/testify/require" ) type mockedEIPAddresses struct { - ec2iface.EC2API - DescribeAddressesOutput ec2.DescribeAddressesOutput + EIPAddressesAPI ReleaseAddressOutput ec2.ReleaseAddressOutput + DescribeAddressesOutput ec2.DescribeAddressesOutput } -func (m mockedEIPAddresses) DescribeAddressesWithContext(_ awsgo.Context, _ *ec2.DescribeAddressesInput, _ ...request.Option) (*ec2.DescribeAddressesOutput, error) { - return &m.DescribeAddressesOutput, nil +func (m mockedEIPAddresses) ReleaseAddress(ctx context.Context, params *ec2.ReleaseAddressInput, optFns ...func(*ec2.Options)) (*ec2.ReleaseAddressOutput, error) { + return &m.ReleaseAddressOutput, nil } -func (m mockedEIPAddresses) ReleaseAddressWithContext(_ awsgo.Context, _ *ec2.ReleaseAddressInput, _ ...request.Option) (*ec2.ReleaseAddressOutput, error) { - return &m.ReleaseAddressOutput, nil +func (m mockedEIPAddresses) DescribeAddresses(ctx context.Context, params *ec2.DescribeAddressesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeAddressesOutput, error) { + return &m.DescribeAddressesOutput, nil } func TestEIPAddress_GetAll(t *testing.T) { - t.Parallel() // Set excludeFirstSeenTag to false for testing @@ -44,30 +42,30 @@ func TestEIPAddress_GetAll(t *testing.T) { ea := EIPAddresses{ Client: &mockedEIPAddresses{ DescribeAddressesOutput: ec2.DescribeAddressesOutput{ - Addresses: []*ec2.Address{ + Addresses: []types.Address{ { - AllocationId: awsgo.String(testAllocId1), - Tags: []*ec2.Tag{ + AllocationId: aws.String(testAllocId1), + Tags: []types.Tag{ { - Key: awsgo.String("Name"), - Value: awsgo.String(testName1), + Key: aws.String("Name"), + Value: aws.String(testName1), }, { - Key: awsgo.String(util.FirstSeenTagKey), - Value: awsgo.String(util.FormatTimestamp(now)), + Key: aws.String(util.FirstSeenTagKey), + Value: aws.String(util.FormatTimestamp(now)), }, }, }, { - AllocationId: awsgo.String(testAllocId2), - Tags: []*ec2.Tag{ + AllocationId: aws.String(testAllocId2), + Tags: []types.Tag{ { - Key: awsgo.String("Name"), - Value: awsgo.String(testName2), + Key: aws.String("Name"), + Value: aws.String(testName2), }, { - Key: awsgo.String(util.FirstSeenTagKey), - Value: awsgo.String(util.FormatTimestamp(now.Add(1))), + Key: aws.String(util.FirstSeenTagKey), + Value: aws.String(util.FormatTimestamp(now.Add(1))), }, }, }, @@ -100,7 +98,7 @@ func TestEIPAddress_GetAll(t *testing.T) { ctx: ctx, configObj: config.ResourceType{ ExcludeRule: config.FilterRule{ - TimeAfter: awsgo.Time(now.Add(-1 * time.Hour)), + TimeAfter: aws.Time(now.Add(-1 * time.Hour)), }}, expected: []string{}, }, @@ -111,22 +109,19 @@ func TestEIPAddress_GetAll(t *testing.T) { ElasticIP: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, awsgo.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } - } func TestEIPAddress_NukeAll(t *testing.T) { - t.Parallel() - ea := EIPAddresses{ Client: &mockedEIPAddresses{ ReleaseAddressOutput: ec2.ReleaseAddressOutput{}, }, } - err := ea.nukeAll([]*string{awsgo.String("alloc1")}) + err := ea.nukeAll([]*string{aws.String("alloc1")}) require.NoError(t, err) } diff --git a/aws/resources/eip_types.go b/aws/resources/eip_types.go index 8a5600d0..121a5922 100644 --- a/aws/resources/eip_types.go +++ b/aws/resources/eip_types.go @@ -3,58 +3,63 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/aws/aws-sdk-go/service/ec2/ec2iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) -// EBSVolumes - represents all ebs volumes +type EIPAddressesAPI interface { + ReleaseAddress(ctx context.Context, params *ec2.ReleaseAddressInput, optFns ...func(*ec2.Options)) (*ec2.ReleaseAddressOutput, error) + DescribeAddresses(ctx context.Context, params *ec2.DescribeAddressesInput, optFns ...func(*ec2.Options)) (*ec2.DescribeAddressesOutput, error) +} + +// EIPAddresses - represents all ebs volumes type EIPAddresses struct { BaseAwsResource - Client ec2iface.EC2API + Client EIPAddressesAPI Region string AllocationIds []string } -func (address *EIPAddresses) Init(session *session.Session) { - address.Client = ec2.New(session) +func (eip *EIPAddresses) InitV2(cfg aws.Config) { + eip.Client = ec2.NewFromConfig(cfg) } +func (eip *EIPAddresses) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource -func (address *EIPAddresses) ResourceName() string { +func (eip *EIPAddresses) ResourceName() string { return "eip" } // ResourceIdentifiers - The instance ids of the eip addresses -func (address *EIPAddresses) ResourceIdentifiers() []string { - return address.AllocationIds +func (eip *EIPAddresses) ResourceIdentifiers() []string { + return eip.AllocationIds } -func (address *EIPAddresses) MaxBatchSize() int { +func (eip *EIPAddresses) MaxBatchSize() int { // Tentative batch size to ensure AWS doesn't throttle return 49 } -func (address *EIPAddresses) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { +func (eip *EIPAddresses) GetAndSetResourceConfig(configObj config.Config) config.ResourceType { return configObj.ElasticIP } -func (address *EIPAddresses) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { - identifiers, err := address.getAll(c, configObj) +func (eip *EIPAddresses) GetAndSetIdentifiers(c context.Context, configObj config.Config) ([]string, error) { + identifiers, err := eip.getAll(c, configObj) if err != nil { return nil, err } - address.AllocationIds = awsgo.StringValueSlice(identifiers) - return address.AllocationIds, nil + eip.AllocationIds = aws.ToStringSlice(identifiers) + return eip.AllocationIds, nil } // Nuke - nuke 'em all!!! -func (address *EIPAddresses) Nuke(identifiers []string) error { - if err := address.nukeAll(awsgo.StringSlice(identifiers)); err != nil { +func (eip *EIPAddresses) Nuke(identifiers []string) error { + if err := eip.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/eks.go b/aws/resources/eks.go index 5bf2d862..539f7d17 100644 --- a/aws/resources/eks.go +++ b/aws/resources/eks.go @@ -3,9 +3,10 @@ package resources import ( "context" "sync" + "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/eks" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -16,12 +17,12 @@ import ( // getAll returns a list of strings of EKS Cluster Names that uniquely identify each cluster. func (clusters *EKSClusters) getAll(c context.Context, configObj config.Config) ([]*string, error) { - result, err := clusters.Client.ListClustersWithContext(clusters.Context, &eks.ListClustersInput{}) + result, err := clusters.Client.ListClusters(clusters.Context, &eks.ListClustersInput{}) if err != nil { return nil, errors.WithStackTrace(err) } - filteredClusters, err := clusters.filter(result.Clusters, configObj) + filteredClusters, err := clusters.filter(aws.StringSlice(result.Clusters), configObj) if err != nil { return nil, errors.WithStackTrace(err) } @@ -39,7 +40,7 @@ func (clusters *EKSClusters) filter(clusterNames []*string, configObj config.Con continue } - describeResult, err := clusters.Client.DescribeClusterWithContext( + describeResult, err := clusters.Client.DescribeCluster( clusters.Context, &eks.DescribeClusterInput{Name: clusterName}) if err != nil { @@ -48,7 +49,7 @@ func (clusters *EKSClusters) filter(clusterNames []*string, configObj config.Con if !configObj.EKSCluster.ShouldInclude(config.ResourceValue{ Time: describeResult.Cluster.CreatedAt, - Tags: util.ConvertStringPtrTagsToMap(describeResult.Cluster.Tags), + Tags: util.ConvertStringPtrTagsToMap(aws.StringMap(describeResult.Cluster.Tags)), }) { continue } @@ -82,15 +83,17 @@ func (clusters *EKSClusters) deleteAsync(wg *sync.WaitGroup, errChan chan error, // Make sure the node groups are actually deleted before returning. for _, nodeGroup := range deletedNodeGroups { - err := clusters.Client.WaitUntilNodegroupDeletedWithContext(clusters.Context, &eks.DescribeNodegroupInput{ + + waiter := eks.NewNodegroupDeletedWaiter(clusters.Client) + err := waiter.Wait(clusters.Context, &eks.DescribeNodegroupInput{ ClusterName: aws.String(eksClusterName), NodegroupName: nodeGroup, - }) + }, 15*time.Minute) if err != nil { - logging.Debugf("[Failed] Failed waiting for Node Group %s associated with cluster %s to be deleted: %s", aws.StringValue(nodeGroup), eksClusterName, err) + logging.Debugf("[Failed] Failed waiting for Node Group %s associated with cluster %s to be deleted: %s", aws.ToString(nodeGroup), eksClusterName, err) allSubResourceErrs = multierror.Append(allSubResourceErrs, err) } else { - logging.Debugf("Deleted Node Group %s associated with cluster %s", aws.StringValue(nodeGroup), eksClusterName) + logging.Debugf("Deleted Node Group %s associated with cluster %s", aws.ToString(nodeGroup), eksClusterName) } } if allSubResourceErrs != nil { @@ -100,7 +103,7 @@ func (clusters *EKSClusters) deleteAsync(wg *sync.WaitGroup, errChan chan error, // At this point, all the sub resources of the EKS cluster has been confirmed to be deleted, so we can go ahead to // request to delete the EKS cluster. - _, deleteErr := clusters.Client.DeleteClusterWithContext(clusters.Context, &eks.DeleteClusterInput{Name: aws.String(eksClusterName)}) + _, deleteErr := clusters.Client.DeleteCluster(clusters.Context, &eks.DeleteClusterInput{Name: aws.String(eksClusterName)}) if deleteErr != nil { logging.Debugf("[Failed] Failed deleting EKS cluster %s: %s", eksClusterName, deleteErr) } @@ -111,17 +114,18 @@ func (clusters *EKSClusters) deleteAsync(wg *sync.WaitGroup, errChan chan error, // and requests each one to be deleted. Note that this function will not wait for the Node Groups to be deleted. This // will return the list of Node Groups that were successfully scheduled for deletion. func (clusters *EKSClusters) scheduleDeleteEKSClusterManagedNodeGroup(eksClusterName string) ([]*string, error) { - allNodeGroups := []*string{} - err := clusters.Client.ListNodegroupsPagesWithContext( - clusters.Context, - &eks.ListNodegroupsInput{ClusterName: aws.String(eksClusterName)}, - func(page *eks.ListNodegroupsOutput, lastPage bool) bool { - allNodeGroups = append(allNodeGroups, page.Nodegroups...) - return !lastPage - }, - ) - if err != nil { - return nil, err + var allNodeGroups []*string + + paginator := eks.NewListNodegroupsPaginator(clusters.Client, &eks.ListNodegroupsInput{ + ClusterName: aws.String(eksClusterName), + }) + for paginator.HasMorePages() { + page, err := paginator.NextPage(context.Background()) + if err != nil { + return nil, errors.WithStackTrace(err) + } + + allNodeGroups = append(allNodeGroups, aws.StringSlice(page.Nodegroups)...) } // Since there isn't a bulk node group delete, we make the requests to delete node groups in a tight loop. This @@ -129,16 +133,16 @@ func (clusters *EKSClusters) scheduleDeleteEKSClusterManagedNodeGroup(eksCluster // cloud-nuke should be fairly small due to its use case. We can improve this if anyone runs into scalability // issues with this implementation. var allDeleteErrs error - deletedNodeGroups := []*string{} + var deletedNodeGroups []*string for _, nodeGroup := range allNodeGroups { - _, err := clusters.Client.DeleteNodegroupWithContext( + _, err := clusters.Client.DeleteNodegroup( clusters.Context, &eks.DeleteNodegroupInput{ ClusterName: aws.String(eksClusterName), NodegroupName: nodeGroup, }) if err != nil { - logging.Debugf("[Failed] Failed deleting Node Group %s associated with cluster %s: %s", aws.StringValue(nodeGroup), eksClusterName, err) + logging.Debugf("[Failed] Failed deleting Node Group %s associated with cluster %s: %s", aws.ToString(nodeGroup), eksClusterName, err) allDeleteErrs = multierror.Append(allDeleteErrs, err) } else { deletedNodeGroups = append(deletedNodeGroups, nodeGroup) @@ -151,17 +155,16 @@ func (clusters *EKSClusters) scheduleDeleteEKSClusterManagedNodeGroup(eksCluster // each one to be deleted. Since only one Fargate Profile can be deleted at a time, this function will wait until the // Fargate Profile is actually deleted for each one before moving on to the next one. func (clusters *EKSClusters) deleteEKSClusterFargateProfiles(eksClusterName string) error { - allFargateProfiles := []*string{} - err := clusters.Client.ListFargateProfilesPagesWithContext( - clusters.Context, - &eks.ListFargateProfilesInput{ClusterName: aws.String(eksClusterName)}, - func(page *eks.ListFargateProfilesOutput, lastPage bool) bool { - allFargateProfiles = append(allFargateProfiles, page.FargateProfileNames...) - return !lastPage - }, - ) - if err != nil { - return err + var allFargateProfiles []*string + + paginator := eks.NewListFargateProfilesPaginator(clusters.Client, &eks.ListFargateProfilesInput{ClusterName: aws.String(eksClusterName)}) + for paginator.HasMorePages() { + page, err := paginator.NextPage(context.Background()) + if err != nil { + return errors.WithStackTrace(err) + } + + allFargateProfiles = append(allFargateProfiles, aws.StringSlice(page.FargateProfileNames)...) } // We can't delete Fargate profiles in parallel, so we delete them sequentially, waiting until the profile has been @@ -172,31 +175,31 @@ func (clusters *EKSClusters) deleteEKSClusterFargateProfiles(eksClusterName stri // Note that we aggregate deletion errors so that we at least attempt to delete all of them once. var allDeleteErrs error for _, fargateProfile := range allFargateProfiles { - _, err := clusters.Client.DeleteFargateProfileWithContext( + _, err := clusters.Client.DeleteFargateProfile( clusters.Context, &eks.DeleteFargateProfileInput{ ClusterName: aws.String(eksClusterName), FargateProfileName: fargateProfile, }) if err != nil { - logging.Debugf("[Failed] Failed deleting Fargate Profile %s associated with cluster %s: %s", aws.StringValue(fargateProfile), eksClusterName, err) + logging.Debugf("[Failed] Failed deleting Fargate Profile %s associated with cluster %s: %s", aws.ToString(fargateProfile), eksClusterName, err) allDeleteErrs = multierror.Append(allDeleteErrs, err) continue } - waitErr := clusters.Client.WaitUntilFargateProfileDeletedWithContext( - clusters.Context, - &eks.DescribeFargateProfileInput{ - ClusterName: aws.String(eksClusterName), - FargateProfileName: fargateProfile, - }) + waiter := eks.NewFargateProfileDeletedWaiter(clusters.Client) + waitErr := waiter.Wait(clusters.Context, &eks.DescribeFargateProfileInput{ + ClusterName: aws.String(eksClusterName), + FargateProfileName: fargateProfile, + }, 15*time.Minute) if waitErr != nil { - logging.Debugf("[Failed] Failed waiting for Fargate Profile %s associated with cluster %s to be deleted: %s", aws.StringValue(fargateProfile), eksClusterName, waitErr) + logging.Debugf("[Failed] Failed waiting for Fargate Profile %s associated with cluster %s to be deleted: %s", aws.ToString(fargateProfile), eksClusterName, waitErr) allDeleteErrs = multierror.Append(allDeleteErrs, waitErr) } else { - logging.Debugf("Deleted Fargate Profile %s associated with cluster %s", aws.StringValue(fargateProfile), eksClusterName) + logging.Debugf("Deleted Fargate Profile %s associated with cluster %s", aws.ToString(fargateProfile), eksClusterName) } } + return allDeleteErrs } @@ -205,11 +208,15 @@ func (clusters *EKSClusters) deleteEKSClusterFargateProfiles(eksClusterName stri func (clusters *EKSClusters) waitUntilEksClustersDeleted(eksClusterNames []*string) []*string { var successfullyDeleted []*string for _, eksClusterName := range eksClusterNames { - err := clusters.Client.WaitUntilClusterDeletedWithContext(clusters.Context, &eks.DescribeClusterInput{Name: eksClusterName}) + + waiter := eks.NewClusterDeletedWaiter(clusters.Client) + err := waiter.Wait(clusters.Context, &eks.DescribeClusterInput{ + Name: eksClusterName, + }, 15*time.Minute) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(eksClusterName), + Identifier: aws.ToString(eksClusterName), ResourceType: "EKS Cluster", Error: err, } @@ -218,7 +225,7 @@ func (clusters *EKSClusters) waitUntilEksClustersDeleted(eksClusterNames []*stri if err != nil { logging.Debugf("[Failed] Failed waiting for EKS cluster to be deleted %s: %s", *eksClusterName, err) } else { - logging.Debugf("Deleted EKS cluster: %s", aws.StringValue(eksClusterName)) + logging.Debugf("Deleted EKS cluster: %s", aws.ToString(eksClusterName)) successfullyDeleted = append(successfullyDeleted, eksClusterName) } } @@ -242,7 +249,7 @@ func (clusters *EKSClusters) nukeAll(eksClusterNames []*string) error { return TooManyEKSClustersErr{} } - // We need to delete subresources associated with the EKS Cluster before being able to delete the cluster, so we + // We need to delete sub-resources associated with the EKS Cluster before being able to delete the cluster, so we // spawn goroutines to drive the deletion of each EKS cluster. logging.Debugf("Deleting %d EKS clusters in region %s", numNuking, clusters.Region) wg := new(sync.WaitGroup) @@ -250,7 +257,7 @@ func (clusters *EKSClusters) nukeAll(eksClusterNames []*string) error { errChans := make([]chan error, numNuking) for i, eksClusterName := range eksClusterNames { errChans[i] = make(chan error, 1) - go clusters.deleteAsync(wg, errChans[i], aws.StringValue(eksClusterName)) + go clusters.deleteAsync(wg, errChans[i], aws.ToString(eksClusterName)) } wg.Wait() diff --git a/aws/resources/eks_test.go b/aws/resources/eks_test.go index f19a7579..9b0b5f57 100644 --- a/aws/resources/eks_test.go +++ b/aws/resources/eks_test.go @@ -5,86 +5,62 @@ import ( "testing" "time" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/eks" + "github.com/aws/aws-sdk-go-v2/service/eks/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedEKSCluster struct { - eksiface.EKSAPI - - ListClustersOutput eks.ListClustersOutput - DescribeClusterOutput eks.DescribeClusterOutput - DeleteClusterOutput eks.DeleteClusterOutput - - ListFargateProfilesOutput eks.ListFargateProfilesOutput - DeleteFargateProfileOutput eks.DeleteFargateProfileOutput - - DescribeNodegroupOutput eks.DescribeNodegroupOutput - ListNodegroupsOutput eks.ListNodegroupsOutput - DeleteNodegroupOutput eks.DeleteNodegroupOutput + EKSClustersAPI + DeleteClusterOutput eks.DeleteClusterOutput + DeleteFargateProfileOutput eks.DeleteFargateProfileOutput + DeleteNodegroupOutput eks.DeleteNodegroupOutput + DescribeClusterOutput eks.DescribeClusterOutput + DescribeFargateProfileOutput eks.DescribeFargateProfileOutput + DescribeNodegroupOutput eks.DescribeNodegroupOutput + ListClustersOutput eks.ListClustersOutput + ListFargateProfilesOutput eks.ListFargateProfilesOutput + ListNodegroupsOutput eks.ListNodegroupsOutput } -func (m mockedEKSCluster) ListClustersWithContext(_ awsgo.Context, _ *eks.ListClustersInput, _ ...request.Option) (*eks.ListClustersOutput, error) { - // Only need to return mocked response output - return &m.ListClustersOutput, nil -} - -func (m mockedEKSCluster) DescribeClusterWithContext(_ awsgo.Context, _ *eks.DescribeClusterInput, _ ...request.Option) (*eks.DescribeClusterOutput, error) { - // Only need to return mocked response output - return &m.DescribeClusterOutput, nil +func (m mockedEKSCluster) DeleteCluster(ctx context.Context, params *eks.DeleteClusterInput, optFns ...func(*eks.Options)) (*eks.DeleteClusterOutput, error) { + return &m.DeleteClusterOutput, nil } -func (m mockedEKSCluster) ListNodegroupsPagesWithContext( - _ awsgo.Context, - input *eks.ListNodegroupsInput, fn func(*eks.ListNodegroupsOutput, bool) bool, - _ ...request.Option) error { - // Only need to return mocked response output - fn(&m.ListNodegroupsOutput, true) - return nil +func (m mockedEKSCluster) DeleteFargateProfile(ctx context.Context, params *eks.DeleteFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DeleteFargateProfileOutput, error) { + return &m.DeleteFargateProfileOutput, nil } -func (m mockedEKSCluster) DeleteNodegroupWithContext(_ awsgo.Context, _ *eks.DeleteNodegroupInput, _ ...request.Option) (*eks.DeleteNodegroupOutput, error) { - // Only need to return mocked response output +func (m mockedEKSCluster) DeleteNodegroup(ctx context.Context, params *eks.DeleteNodegroupInput, optFns ...func(*eks.Options)) (*eks.DeleteNodegroupOutput, error) { return &m.DeleteNodegroupOutput, nil } -func (m mockedEKSCluster) WaitUntilNodegroupDeletedWithContext(_ awsgo.Context, input *eks.DescribeNodegroupInput, _ ...request.WaiterOption) error { - return nil +func (m mockedEKSCluster) DescribeCluster(ctx context.Context, params *eks.DescribeClusterInput, optFns ...func(*eks.Options)) (*eks.DescribeClusterOutput, error) { + return &m.DescribeClusterOutput, nil } -func (m mockedEKSCluster) ListFargateProfilesPagesWithContext( - _ awsgo.Context, - input *eks.ListFargateProfilesInput, fn func(*eks.ListFargateProfilesOutput, bool) bool, - _ ...request.Option) error { - // Only need to return mocked response output - fn(&m.ListFargateProfilesOutput, true) - return nil +func (m mockedEKSCluster) DescribeFargateProfile(ctx context.Context, params *eks.DescribeFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DescribeFargateProfileOutput, error) { + return &m.DescribeFargateProfileOutput, nil } -func (m mockedEKSCluster) DeleteFargateProfileWithContext(_ awsgo.Context, input *eks.DeleteFargateProfileInput, _ ...request.Option) (*eks.DeleteFargateProfileOutput, error) { - // Only need to return mocked response output - return &m.DeleteFargateProfileOutput, nil +func (m mockedEKSCluster) DescribeNodegroup(ctx context.Context, params *eks.DescribeNodegroupInput, optFns ...func(*eks.Options)) (*eks.DescribeNodegroupOutput, error) { + return &m.DescribeNodegroupOutput, nil } -func (m mockedEKSCluster) WaitUntilFargateProfileDeletedWithContext(_ awsgo.Context, input *eks.DescribeFargateProfileInput, _ ...request.WaiterOption) error { - return nil +func (m mockedEKSCluster) ListClusters(ctx context.Context, params *eks.ListClustersInput, optFns ...func(*eks.Options)) (*eks.ListClustersOutput, error) { + return &m.ListClustersOutput, nil } -func (m mockedEKSCluster) WaitUntilClusterDeletedWithContext(_ awsgo.Context, input *eks.DescribeClusterInput, _ ...request.WaiterOption) error { - return nil +func (m mockedEKSCluster) ListFargateProfiles(ctx context.Context, params *eks.ListFargateProfilesInput, optFns ...func(*eks.Options)) (*eks.ListFargateProfilesOutput, error) { + return &m.ListFargateProfilesOutput, nil } -func (m mockedEKSCluster) DeleteClusterWithContext(_ awsgo.Context, input *eks.DeleteClusterInput, _ ...request.Option) (*eks.DeleteClusterOutput, error) { - return &m.DeleteClusterOutput, nil +func (m mockedEKSCluster) ListNodegroups(ctx context.Context, params *eks.ListNodegroupsInput, optFns ...func(*eks.Options)) (*eks.ListNodegroupsOutput, error) { + return &m.ListNodegroupsOutput, nil } - func TestEKSClusterGetAll(t *testing.T) { - t.Parallel() testClusterName := "test_cluster1" @@ -92,37 +68,34 @@ func TestEKSClusterGetAll(t *testing.T) { eksCluster := EKSClusters{ Client: mockedEKSCluster{ ListClustersOutput: eks.ListClustersOutput{ - Clusters: []*string{awsgo.String(testClusterName)}, + Clusters: []string{testClusterName}, }, DescribeClusterOutput: eks.DescribeClusterOutput{ - Cluster: &eks.Cluster{CreatedAt: &now}, + Cluster: &types.Cluster{CreatedAt: &now}, }, }, } clusters, err := eksCluster.getAll(context.Background(), config.Config{}) require.NoError(t, err) - require.Contains(t, awsgo.StringValueSlice(clusters), testClusterName) + require.Contains(t, aws.ToStringSlice(clusters), testClusterName) } func TestEKSClusterNukeAll(t *testing.T) { - t.Parallel() - testClusterName := "test_cluster1" - testFargateProfileName := "test_fargate_profile1" - testNodeGroupName := "test_nodegroup1" eksCluster := EKSClusters{ + BaseAwsResource: BaseAwsResource{ + Context: context.Background(), + }, Client: mockedEKSCluster{ - ListNodegroupsOutput: eks.ListNodegroupsOutput{ - Nodegroups: []*string{&testNodeGroupName}, - }, - DescribeClusterOutput: eks.DescribeClusterOutput{}, - ListFargateProfilesOutput: eks.ListFargateProfilesOutput{ - FargateProfileNames: []*string{&testFargateProfileName}, - }, - DeleteFargateProfileOutput: eks.DeleteFargateProfileOutput{}, - DeleteClusterOutput: eks.DeleteClusterOutput{}, + ListNodegroupsOutput: eks.ListNodegroupsOutput{}, + DescribeClusterOutput: eks.DescribeClusterOutput{}, + ListFargateProfilesOutput: eks.ListFargateProfilesOutput{}, + DescribeNodegroupOutput: eks.DescribeNodegroupOutput{}, + DeleteFargateProfileOutput: eks.DeleteFargateProfileOutput{}, + DeleteClusterOutput: eks.DeleteClusterOutput{}, + DescribeFargateProfileOutput: eks.DescribeFargateProfileOutput{}, }, } diff --git a/aws/resources/eks_types.go b/aws/resources/eks_types.go index 732694da..78655bae 100644 --- a/aws/resources/eks_types.go +++ b/aws/resources/eks_types.go @@ -3,26 +3,38 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/eks" - "github.com/aws/aws-sdk-go/service/eks/eksiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/eks" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type EKSClustersAPI interface { + DeleteCluster(ctx context.Context, params *eks.DeleteClusterInput, optFns ...func(*eks.Options)) (*eks.DeleteClusterOutput, error) + DeleteFargateProfile(ctx context.Context, params *eks.DeleteFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DeleteFargateProfileOutput, error) + DeleteNodegroup(ctx context.Context, params *eks.DeleteNodegroupInput, optFns ...func(*eks.Options)) (*eks.DeleteNodegroupOutput, error) + DescribeCluster(ctx context.Context, params *eks.DescribeClusterInput, optFns ...func(*eks.Options)) (*eks.DescribeClusterOutput, error) + DescribeFargateProfile(ctx context.Context, params *eks.DescribeFargateProfileInput, optFns ...func(*eks.Options)) (*eks.DescribeFargateProfileOutput, error) + DescribeNodegroup(ctx context.Context, params *eks.DescribeNodegroupInput, optFns ...func(*eks.Options)) (*eks.DescribeNodegroupOutput, error) + ListClusters(ctx context.Context, params *eks.ListClustersInput, optFns ...func(*eks.Options)) (*eks.ListClustersOutput, error) + ListFargateProfiles(ctx context.Context, params *eks.ListFargateProfilesInput, optFns ...func(*eks.Options)) (*eks.ListFargateProfilesOutput, error) + ListNodegroups(ctx context.Context, params *eks.ListNodegroupsInput, optFns ...func(*eks.Options)) (*eks.ListNodegroupsOutput, error) +} + // EKSClusters - Represents all EKS clusters found in a region type EKSClusters struct { BaseAwsResource - Client eksiface.EKSAPI + Client EKSClustersAPI Region string Clusters []string } -func (clusters *EKSClusters) Init(session *session.Session) { - clusters.Client = eks.New(session) +func (clusters *EKSClusters) InitV2(cfg aws.Config) { + clusters.Client = eks.NewFromConfig(cfg) } +func (clusters *EKSClusters) IsUsingV2() bool { return true } + // ResourceName - The simple name of the aws resource func (clusters *EKSClusters) ResourceName() string { return "ekscluster" @@ -50,13 +62,13 @@ func (clusters *EKSClusters) GetAndSetIdentifiers(c context.Context, configObj c return nil, err } - clusters.Clusters = awsgo.StringValueSlice(identifiers) + clusters.Clusters = aws.ToStringSlice(identifiers) return clusters.Clusters, nil } // Nuke - nuke all EKS Cluster resources func (clusters *EKSClusters) Nuke(identifiers []string) error { - if err := clusters.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := clusters.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } return nil diff --git a/aws/resources/elastic_beanstalk.go b/aws/resources/elastic_beanstalk.go index 63c67a6b..b86ea181 100644 --- a/aws/resources/elastic_beanstalk.go +++ b/aws/resources/elastic_beanstalk.go @@ -3,15 +3,16 @@ package resources import ( "context" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elasticbeanstalk" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk" + "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" "github.com/gruntwork-io/go-commons/errors" ) -func shouldIncludeEBApplication(app *elasticbeanstalk.ApplicationDescription, configObj config.Config) bool { +func shouldIncludeEBApplication(app *types.ApplicationDescription, configObj config.Config) bool { return configObj.ElasticBeanstalk.ShouldInclude(config.ResourceValue{ Name: app.ApplicationName, Time: app.DateCreated, @@ -20,13 +21,13 @@ func shouldIncludeEBApplication(app *elasticbeanstalk.ApplicationDescription, co // Returns a formatted string of EB application ids func (eb *EBApplications) getAll(c context.Context, configObj config.Config) ([]*string, error) { - output, err := eb.Client.DescribeApplicationsWithContext(eb.Context, &elasticbeanstalk.DescribeApplicationsInput{}) + output, err := eb.Client.DescribeApplications(eb.Context, &elasticbeanstalk.DescribeApplicationsInput{}) if err != nil { return nil, errors.WithStackTrace(err) } var appIds []*string for _, app := range output.Applications { - if shouldIncludeEBApplication(app, configObj) { + if shouldIncludeEBApplication(&app, configObj) { appIds = append(appIds, app.ApplicationName) } } @@ -44,13 +45,13 @@ func (eb *EBApplications) nukeAll(appIds []*string) error { var deletedApps []*string for _, id := range appIds { - _, err := eb.Client.DeleteApplicationWithContext(eb.Context, &elasticbeanstalk.DeleteApplicationInput{ + _, err := eb.Client.DeleteApplication(eb.Context, &elasticbeanstalk.DeleteApplicationInput{ ApplicationName: id, TerminateEnvByForce: aws.Bool(true), }) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(id), + Identifier: aws.ToString(id), ResourceType: "Elastic Beanstalk Application", Error: err, } diff --git a/aws/resources/elastic_beanstalk_test.go b/aws/resources/elastic_beanstalk_test.go index 4d733950..1abaafaf 100644 --- a/aws/resources/elastic_beanstalk_test.go +++ b/aws/resources/elastic_beanstalk_test.go @@ -6,25 +6,25 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/elasticbeanstalk" - "github.com/aws/aws-sdk-go/service/elasticbeanstalk/elasticbeanstalkiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk" + "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedEBApplication struct { - elasticbeanstalkiface.ElasticBeanstalkAPI + EBApplicationsAPI DescribeApplicationsOutput elasticbeanstalk.DescribeApplicationsOutput + DeleteApplicationOutput elasticbeanstalk.DeleteApplicationOutput } -func (mock *mockedEBApplication) DescribeApplicationsWithContext(_ aws.Context, req *elasticbeanstalk.DescribeApplicationsInput, _ ...request.Option) (*elasticbeanstalk.DescribeApplicationsOutput, error) { - return &mock.DescribeApplicationsOutput, nil +func (m *mockedEBApplication) DescribeApplications(ctx context.Context, params *elasticbeanstalk.DescribeApplicationsInput, optFns ...func(*elasticbeanstalk.Options)) (*elasticbeanstalk.DescribeApplicationsOutput, error) { + return &m.DescribeApplicationsOutput, nil } -func (mock *mockedEBApplication) DeleteApplicationWithContext(_ aws.Context, _ *elasticbeanstalk.DeleteApplicationInput, _ ...request.Option) (*elasticbeanstalk.DeleteApplicationOutput, error) { - return nil, nil +func (m *mockedEBApplication) DeleteApplication(ctx context.Context, params *elasticbeanstalk.DeleteApplicationInput, optFns ...func(*elasticbeanstalk.Options)) (*elasticbeanstalk.DeleteApplicationOutput, error) { + return &m.DeleteApplicationOutput, nil } func TestEBApplication_GetAll(t *testing.T) { @@ -37,7 +37,7 @@ func TestEBApplication_GetAll(t *testing.T) { eb := EBApplications{ Client: &mockedEBApplication{ DescribeApplicationsOutput: elasticbeanstalk.DescribeApplicationsOutput{ - Applications: []*elasticbeanstalk.ApplicationDescription{ + Applications: []types.ApplicationDescription{ { ApplicationArn: aws.String("app-arn-01"), ApplicationName: &app1, @@ -94,7 +94,7 @@ func TestEBApplication_GetAll(t *testing.T) { ElasticBeanstalk: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } diff --git a/aws/resources/elastic_beanstalk_types.go b/aws/resources/elastic_beanstalk_types.go index 9473552a..9596cd94 100644 --- a/aws/resources/elastic_beanstalk_types.go +++ b/aws/resources/elastic_beanstalk_types.go @@ -3,26 +3,31 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/elasticbeanstalk" - "github.com/aws/aws-sdk-go/service/elasticbeanstalk/elasticbeanstalkiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type EBApplicationsAPI interface { + DescribeApplications(ctx context.Context, params *elasticbeanstalk.DescribeApplicationsInput, optFns ...func(*elasticbeanstalk.Options)) (*elasticbeanstalk.DescribeApplicationsOutput, error) + DeleteApplication(ctx context.Context, params *elasticbeanstalk.DeleteApplicationInput, optFns ...func(*elasticbeanstalk.Options)) (*elasticbeanstalk.DeleteApplicationOutput, error) +} + // EBApplications - represents all elastic beanstalk applications type EBApplications struct { BaseAwsResource - Client elasticbeanstalkiface.ElasticBeanstalkAPI + Client EBApplicationsAPI Region string appIds []string } -func (eb *EBApplications) Init(session *session.Session) { - eb.Client = elasticbeanstalk.New(session) +func (eb *EBApplications) InitV2(cfg aws.Config) { + eb.Client = elasticbeanstalk.NewFromConfig(cfg) } +func (eb *EBApplications) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource func (eb *EBApplications) ResourceName() string { return "elastic-beanstalk" @@ -48,13 +53,13 @@ func (eb *EBApplications) GetAndSetIdentifiers(c context.Context, configObj conf return nil, err } - eb.appIds = awsgo.StringValueSlice(identifiers) + eb.appIds = aws.ToStringSlice(identifiers) return eb.appIds, nil } // Nuke - nuke 'em all!!! func (eb *EBApplications) Nuke(identifiers []string) error { - if err := eb.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := eb.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/elasticache.go b/aws/resources/elasticache.go index 7d0152b6..e9b1def7 100644 --- a/aws/resources/elasticache.go +++ b/aws/resources/elasticache.go @@ -2,36 +2,38 @@ package resources import ( "context" + "errors" "fmt" "strings" + "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/elasticache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticache" + "github.com/aws/aws-sdk-go-v2/service/elasticache/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" - "github.com/gruntwork-io/go-commons/errors" + goerrors "github.com/gruntwork-io/go-commons/errors" ) // Returns a formatted string of Elasticache cluster Ids func (cache *Elasticaches) getAll(c context.Context, configObj config.Config) ([]*string, error) { // First, get any cache clusters that are replication groups, which will be the case for all multi-node Redis clusters - replicationGroupsResult, replicationGroupsErr := cache.Client.DescribeReplicationGroupsWithContext(cache.Context, &elasticache.DescribeReplicationGroupsInput{}) + replicationGroupsResult, replicationGroupsErr := cache.Client.DescribeReplicationGroups(cache.Context, &elasticache.DescribeReplicationGroupsInput{}) if replicationGroupsErr != nil { - return nil, errors.WithStackTrace(replicationGroupsErr) + return nil, goerrors.WithStackTrace(replicationGroupsErr) } // Next, get any cache clusters that are not members of a replication group: meaning: - // 1. any cache clusters with a Engine of "memcached" + // 1. any cache clusters with an Engine of "memcached" // 2. any single node Redis clusters - cacheClustersResult, cacheClustersErr := cache.Client.DescribeCacheClustersWithContext( + cacheClustersResult, cacheClustersErr := cache.Client.DescribeCacheClusters( cache.Context, &elasticache.DescribeCacheClustersInput{ ShowCacheClustersNotInReplicationGroups: aws.Bool(true), }) if cacheClustersErr != nil { - return nil, errors.WithStackTrace(cacheClustersErr) + return nil, goerrors.WithStackTrace(cacheClustersErr) } var clusterIds []*string @@ -68,14 +70,14 @@ func (cache *Elasticaches) determineCacheClusterType(clusterId *string) (*string ReplicationGroupId: clusterId, } - replicationGroupOutput, describeReplicationGroupsErr := cache.Client.DescribeReplicationGroupsWithContext(cache.Context, replicationGroupDescribeParams) + replicationGroupOutput, describeReplicationGroupsErr := cache.Client.DescribeReplicationGroups(cache.Context, replicationGroupDescribeParams) if describeReplicationGroupsErr != nil { - if awsErr, ok := describeReplicationGroupsErr.(awserr.Error); ok { - if awsErr.Code() == elasticache.ErrCodeReplicationGroupNotFoundFault { - // It's possible that we're looking at a cache cluster, in which case we can safely ignore this error - } else { - return nil, Single, describeReplicationGroupsErr - } + // GlobalReplicationGroupNotFoundFault + var eRG404 *types.ReplicationGroupNotFoundFault + if errors.As(describeReplicationGroupsErr, &eRG404) { + // It's possible that we're looking at a cache cluster, in which case we can safely ignore this error + } else { + return nil, Single, describeReplicationGroupsErr } } @@ -90,14 +92,13 @@ func (cache *Elasticaches) determineCacheClusterType(clusterId *string) (*string CacheClusterId: clusterId, } - cacheClustersOutput, describeErr := cache.Client.DescribeCacheClustersWithContext(cache.Context, describeParams) + cacheClustersOutput, describeErr := cache.Client.DescribeCacheClusters(cache.Context, describeParams) if describeErr != nil { - if awsErr, ok := describeErr.(awserr.Error); ok { - if awsErr.Code() == elasticache.ErrCodeCacheClusterNotFoundFault { - // It's possible that we're looking at a replication group, in which case we can safely ignore this error - } else { - return nil, Single, describeErr - } + var eC404 *types.CacheClusterNotFoundFault + if errors.As(describeErr, &eC404) { + // It's possible that we're looking at a replication group, in which case we can safely ignore this error + } else { + return nil, Single, describeErr } } @@ -109,40 +110,49 @@ func (cache *Elasticaches) determineCacheClusterType(clusterId *string) (*string } func (cache *Elasticaches) nukeNonReplicationGroupElasticacheCluster(clusterId *string) error { - logging.Debugf("Deleting Elasticache cluster Id: %s which is not a member of a replication group", aws.StringValue(clusterId)) + logging.Debugf("Deleting Elasticache cluster Id: %s which is not a member of a replication group", aws.ToString(clusterId)) params := elasticache.DeleteCacheClusterInput{ CacheClusterId: clusterId, } - _, err := cache.Client.DeleteCacheClusterWithContext(cache.Context, ¶ms) + _, err := cache.Client.DeleteCacheCluster(cache.Context, ¶ms) if err != nil { return err } - return cache.Client.WaitUntilCacheClusterDeletedWithContext(cache.Context, &elasticache.DescribeCacheClustersInput{ - CacheClusterId: clusterId, - }) + waiter := elasticache.NewCacheClusterDeletedWaiter(cache.Client) + + return waiter.Wait( + cache.Context, + &elasticache.DescribeCacheClustersInput{ + CacheClusterId: clusterId, + }, + 15*time.Minute, + ) } func (cache *Elasticaches) nukeReplicationGroupMemberElasticacheCluster(clusterId *string) error { - logging.Debugf("Elasticache cluster Id: %s is a member of a replication group. Therefore, deleting its replication group", aws.StringValue(clusterId)) + logging.Debugf("Elasticache cluster Id: %s is a member of a replication group. Therefore, deleting its replication group", aws.ToString(clusterId)) params := &elasticache.DeleteReplicationGroupInput{ ReplicationGroupId: clusterId, } - _, err := cache.Client.DeleteReplicationGroupWithContext(cache.Context, params) + _, err := cache.Client.DeleteReplicationGroup(cache.Context, params) if err != nil { return err } - waitErr := cache.Client.WaitUntilReplicationGroupDeletedWithContext(cache.Context, &elasticache.DescribeReplicationGroupsInput{ - ReplicationGroupId: clusterId, - }) + waiter := elasticache.NewReplicationGroupDeletedWaiter(cache.Client) + waitErr := waiter.Wait( + cache.Context, + &elasticache.DescribeReplicationGroupsInput{ReplicationGroupId: clusterId}, + 15*time.Minute, + ) if waitErr != nil { return waitErr } - logging.Debugf("Successfully deleted replication group Id: %s", aws.StringValue(clusterId)) + logging.Debugf("Successfully deleted replication group Id: %s", aws.ToString(clusterId)) return nil } @@ -175,7 +185,7 @@ func (cache *Elasticaches) nukeAll(clusterIds []*string) error { // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(clusterId), + Identifier: aws.ToString(clusterId), ResourceType: "Elasticache", Error: err, } @@ -200,7 +210,7 @@ type CouldNotLookupCacheClusterErr struct { } func (err CouldNotLookupCacheClusterErr) Error() string { - return fmt.Sprintf("Failed to lookup clusterId: %s", aws.StringValue(err.ClusterId)) + return fmt.Sprintf("Failed to lookup clusterId: %s", aws.ToString(err.ClusterId)) } /* @@ -209,27 +219,30 @@ Elasticache Parameter Groups func (pg *ElasticacheParameterGroups) getAll(c context.Context, configObj config.Config) ([]*string, error) { var paramGroupNames []*string - err := pg.Client.DescribeCacheParameterGroupsPages( - &elasticache.DescribeCacheParameterGroupsInput{}, - func(page *elasticache.DescribeCacheParameterGroupsOutput, lastPage bool) bool { - for _, paramGroup := range page.CacheParameterGroups { - if pg.shouldInclude(paramGroup, configObj) { - paramGroupNames = append(paramGroupNames, paramGroup.CacheParameterGroupName) - } + + paginator := elasticache.NewDescribeCacheParameterGroupsPaginator(pg.Client, &elasticache.DescribeCacheParameterGroupsInput{}) + for paginator.HasMorePages() { + page, err := paginator.NextPage(c) + if err != nil { + return nil, goerrors.WithStackTrace(err) + } + + for _, paramGroup := range page.CacheParameterGroups { + if pg.shouldInclude(¶mGroup, configObj) { + paramGroupNames = append(paramGroupNames, paramGroup.CacheParameterGroupName) } - return !lastPage - }, - ) + } + } - return paramGroupNames, errors.WithStackTrace(err) + return paramGroupNames, nil } -func (pg *ElasticacheParameterGroups) shouldInclude(paramGroup *elasticache.CacheParameterGroup, configObj config.Config) bool { +func (pg *ElasticacheParameterGroups) shouldInclude(paramGroup *types.CacheParameterGroup, configObj config.Config) bool { if paramGroup == nil { return false } - //Exclude AWS managed resources. user defined resources are unable to begin with "default." - if strings.HasPrefix(aws.StringValue(paramGroup.CacheParameterGroupName), "default.") { + // Exclude AWS managed resources. user defined resources are unable to begin with "default." + if strings.HasPrefix(aws.ToString(paramGroup.CacheParameterGroupName), "default.") { return false } @@ -245,11 +258,11 @@ func (pg *ElasticacheParameterGroups) nukeAll(paramGroupNames []*string) error { } var deletedGroupNames []*string for _, pgName := range paramGroupNames { - _, err := pg.Client.DeleteCacheParameterGroup(&elasticache.DeleteCacheParameterGroupInput{CacheParameterGroupName: pgName}) + _, err := pg.Client.DeleteCacheParameterGroup(pg.Context, &elasticache.DeleteCacheParameterGroupInput{CacheParameterGroupName: pgName}) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(pgName), + Identifier: aws.ToString(pgName), ResourceType: "Elasticache Parameter Group", Error: err, } @@ -258,7 +271,7 @@ func (pg *ElasticacheParameterGroups) nukeAll(paramGroupNames []*string) error { logging.Debugf("[Failed] %s", err) } else { deletedGroupNames = append(deletedGroupNames, pgName) - logging.Debugf("Deleted Elasticache parameter group: %s", aws.StringValue(pgName)) + logging.Debugf("Deleted Elasticache parameter group: %s", aws.ToString(pgName)) } } logging.Debugf("[OK] %d Elasticache parameter groups deleted in %s", len(deletedGroupNames), pg.Region) @@ -270,23 +283,25 @@ Elasticache Subnet Groups */ func (sg *ElasticacheSubnetGroups) getAll(c context.Context, configObj config.Config) ([]*string, error) { var subnetGroupNames []*string - err := sg.Client.DescribeCacheSubnetGroupsPages( - &elasticache.DescribeCacheSubnetGroupsInput{}, - func(page *elasticache.DescribeCacheSubnetGroupsOutput, lastPage bool) bool { - for _, subnetGroup := range page.CacheSubnetGroups { - if !strings.Contains(*subnetGroup.CacheSubnetGroupName, "default") && - configObj.ElasticacheSubnetGroups.ShouldInclude(config.ResourceValue{ - Name: subnetGroup.CacheSubnetGroupName, - }) { - subnetGroupNames = append(subnetGroupNames, subnetGroup.CacheSubnetGroupName) - } - } - return !lastPage - }, - ) + paginator := elasticache.NewDescribeCacheSubnetGroupsPaginator(sg.Client, &elasticache.DescribeCacheSubnetGroupsInput{}) + for paginator.HasMorePages() { + page, err := paginator.NextPage(c) + if err != nil { + return nil, goerrors.WithStackTrace(err) + } + + for _, subnetGroup := range page.CacheSubnetGroups { + if !strings.Contains(*subnetGroup.CacheSubnetGroupName, "default") && + configObj.ElasticacheSubnetGroups.ShouldInclude(config.ResourceValue{ + Name: subnetGroup.CacheSubnetGroupName, + }) { + subnetGroupNames = append(subnetGroupNames, subnetGroup.CacheSubnetGroupName) + } + } + } - return subnetGroupNames, errors.WithStackTrace(err) + return subnetGroupNames, nil } func (sg *ElasticacheSubnetGroups) nukeAll(subnetGroupNames []*string) error { @@ -296,11 +311,11 @@ func (sg *ElasticacheSubnetGroups) nukeAll(subnetGroupNames []*string) error { } var deletedGroupNames []*string for _, sgName := range subnetGroupNames { - _, err := sg.Client.DeleteCacheSubnetGroup(&elasticache.DeleteCacheSubnetGroupInput{CacheSubnetGroupName: sgName}) + _, err := sg.Client.DeleteCacheSubnetGroup(sg.Context, &elasticache.DeleteCacheSubnetGroupInput{CacheSubnetGroupName: sgName}) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(sgName), + Identifier: aws.ToString(sgName), ResourceType: "Elasticache Subnet Group", Error: err, } @@ -309,7 +324,7 @@ func (sg *ElasticacheSubnetGroups) nukeAll(subnetGroupNames []*string) error { logging.Debugf("[Failed] %s", err) } else { deletedGroupNames = append(deletedGroupNames, sgName) - logging.Debugf("Deleted Elasticache subnet group: %s", aws.StringValue(sgName)) + logging.Debugf("Deleted Elasticache subnet group: %s", aws.ToString(sgName)) } } logging.Debugf("[OK] %d Elasticache subnet groups deleted in %s", len(deletedGroupNames), sg.Region) diff --git a/aws/resources/elasticache_test.go b/aws/resources/elasticache_test.go index 59c04eec..9618972c 100644 --- a/aws/resources/elasticache_test.go +++ b/aws/resources/elasticache_test.go @@ -6,39 +6,38 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/elasticache" - "github.com/aws/aws-sdk-go/service/elasticache/elasticacheiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticache" + "github.com/aws/aws-sdk-go-v2/service/elasticache/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedElasticache struct { - elasticacheiface.ElastiCacheAPI + ElasticachesAPI DescribeReplicationGroupsOutput elasticache.DescribeReplicationGroupsOutput DescribeCacheClustersOutput elasticache.DescribeCacheClustersOutput + DeleteCacheClusterOutput elasticache.DeleteCacheClusterOutput DeleteReplicationGroupOutput elasticache.DeleteReplicationGroupOutput } -func (m mockedElasticache) DescribeCacheClustersWithContext(_ aws.Context, input *elasticache.DescribeCacheClustersInput, _ ...request.Option) (*elasticache.DescribeCacheClustersOutput, error) { - return &m.DescribeCacheClustersOutput, nil +func (m mockedElasticache) DescribeReplicationGroups(ctx context.Context, params *elasticache.DescribeReplicationGroupsInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeReplicationGroupsOutput, error) { + return &m.DescribeReplicationGroupsOutput, nil } -func (m mockedElasticache) DescribeReplicationGroupsWithContext(_ aws.Context, input *elasticache.DescribeReplicationGroupsInput, _ ...request.Option) (*elasticache.DescribeReplicationGroupsOutput, error) { - return &m.DescribeReplicationGroupsOutput, nil +func (m mockedElasticache) DescribeCacheClusters(ctx context.Context, params *elasticache.DescribeCacheClustersInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeCacheClustersOutput, error) { + return &m.DescribeCacheClustersOutput, nil } -func (m mockedElasticache) DeleteReplicationGroupWithContext(_ aws.Context, input *elasticache.DeleteReplicationGroupInput, _ ...request.Option) (*elasticache.DeleteReplicationGroupOutput, error) { - return &m.DeleteReplicationGroupOutput, nil +func (m mockedElasticache) DeleteCacheCluster(ctx context.Context, params *elasticache.DeleteCacheClusterInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteCacheClusterOutput, error) { + return &m.DeleteCacheClusterOutput, nil } -func (m mockedElasticache) WaitUntilReplicationGroupDeletedWithContext(_ aws.Context, input *elasticache.DescribeReplicationGroupsInput, _ ...request.WaiterOption) error { - return nil +func (m mockedElasticache) DeleteReplicationGroup(ctx context.Context, params *elasticache.DeleteReplicationGroupInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteReplicationGroupOutput, error) { + return &m.DeleteReplicationGroupOutput, nil } func TestElasticache_GetAll(t *testing.T) { - t.Parallel() now := time.Now() @@ -47,7 +46,7 @@ func TestElasticache_GetAll(t *testing.T) { ec := Elasticaches{ Client: mockedElasticache{ DescribeReplicationGroupsOutput: elasticache.DescribeReplicationGroupsOutput{ - ReplicationGroups: []*elasticache.ReplicationGroup{ + ReplicationGroups: []types.ReplicationGroup{ { ReplicationGroupId: aws.String(testName1), ReplicationGroupCreateTime: aws.Time(now), @@ -59,7 +58,7 @@ func TestElasticache_GetAll(t *testing.T) { }, }, DescribeCacheClustersOutput: elasticache.DescribeCacheClustersOutput{ - CacheClusters: []*elasticache.CacheCluster{}, + CacheClusters: []types.CacheCluster{}, }, }, } @@ -95,23 +94,25 @@ func TestElasticache_GetAll(t *testing.T) { Elasticache: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } func TestElasticache_NukeAll(t *testing.T) { - t.Parallel() - now := time.Now() ec := Elasticaches{ + BaseAwsResource: BaseAwsResource{ + Context: context.Background(), + }, Client: mockedElasticache{ DescribeReplicationGroupsOutput: elasticache.DescribeReplicationGroupsOutput{ - ReplicationGroups: []*elasticache.ReplicationGroup{ + ReplicationGroups: []types.ReplicationGroup{ { ReplicationGroupId: aws.String("test-name-1"), - ReplicationGroupCreateTime: aws.Time(now), + ReplicationGroupCreateTime: aws.Time(time.Now()), + Status: aws.String("deleted"), }, }, }, diff --git a/aws/resources/elasticache_types.go b/aws/resources/elasticache_types.go index 5790312d..9d14b621 100644 --- a/aws/resources/elasticache_types.go +++ b/aws/resources/elasticache_types.go @@ -3,26 +3,33 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/elasticache" - "github.com/aws/aws-sdk-go/service/elasticache/elasticacheiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticache" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type ElasticachesAPI interface { + DescribeReplicationGroups(ctx context.Context, params *elasticache.DescribeReplicationGroupsInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeReplicationGroupsOutput, error) + DescribeCacheClusters(ctx context.Context, params *elasticache.DescribeCacheClustersInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeCacheClustersOutput, error) + DeleteCacheCluster(ctx context.Context, params *elasticache.DeleteCacheClusterInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteCacheClusterOutput, error) + DeleteReplicationGroup(ctx context.Context, params *elasticache.DeleteReplicationGroupInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteReplicationGroupOutput, error) +} + // Elasticaches - represents all Elasticache clusters type Elasticaches struct { BaseAwsResource - Client elasticacheiface.ElastiCacheAPI + Client ElasticachesAPI Region string ClusterIds []string } -func (cache *Elasticaches) Init(session *session.Session) { - cache.Client = elasticache.New(session) +func (cache *Elasticaches) InitV2(cfg aws.Config) { + cache.Client = elasticache.NewFromConfig(cfg) } +func (cache *Elasticaches) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource func (cache *Elasticaches) ResourceName() string { return "elasticache" @@ -48,13 +55,13 @@ func (cache *Elasticaches) GetAndSetIdentifiers(c context.Context, configObj con return nil, err } - cache.ClusterIds = awsgo.StringValueSlice(identifiers) + cache.ClusterIds = aws.ToStringSlice(identifiers) return cache.ClusterIds, nil } // Nuke - nuke 'em all!!! func (cache *Elasticaches) Nuke(identifiers []string) error { - if err := cache.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := cache.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } @@ -64,18 +71,24 @@ func (cache *Elasticaches) Nuke(identifiers []string) error { /* Elasticache Parameter Groups */ +type ElasticacheParameterGroupsAPI interface { + DescribeCacheParameterGroups(ctx context.Context, params *elasticache.DescribeCacheParameterGroupsInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeCacheParameterGroupsOutput, error) + DeleteCacheParameterGroup(ctx context.Context, params *elasticache.DeleteCacheParameterGroupInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteCacheParameterGroupOutput, error) +} type ElasticacheParameterGroups struct { BaseAwsResource - Client elasticacheiface.ElastiCacheAPI + Client ElasticacheParameterGroupsAPI Region string GroupNames []string } -func (pg *ElasticacheParameterGroups) Init(session *session.Session) { - pg.Client = elasticache.New(session) +func (pg *ElasticacheParameterGroups) InitV2(cfg aws.Config) { + pg.Client = elasticache.NewFromConfig(cfg) } +func (pg *ElasticacheParameterGroups) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource func (pg *ElasticacheParameterGroups) ResourceName() string { return "elasticacheParameterGroups" @@ -97,13 +110,13 @@ func (pg *ElasticacheParameterGroups) GetAndSetIdentifiers(c context.Context, co return nil, err } - pg.GroupNames = awsgo.StringValueSlice(identifiers) + pg.GroupNames = aws.ToStringSlice(identifiers) return pg.GroupNames, nil } // Nuke - nuke 'em all!!! func (pg *ElasticacheParameterGroups) Nuke(identifiers []string) error { - if err := pg.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := pg.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } @@ -113,18 +126,24 @@ func (pg *ElasticacheParameterGroups) Nuke(identifiers []string) error { /* Elasticache Subnet Groups */ +type ElasticacheSubnetGroupsAPI interface { + DescribeCacheSubnetGroups(ctx context.Context, params *elasticache.DescribeCacheSubnetGroupsInput, optFns ...func(*elasticache.Options)) (*elasticache.DescribeCacheSubnetGroupsOutput, error) + DeleteCacheSubnetGroup(ctx context.Context, params *elasticache.DeleteCacheSubnetGroupInput, optFns ...func(*elasticache.Options)) (*elasticache.DeleteCacheSubnetGroupOutput, error) +} type ElasticacheSubnetGroups struct { BaseAwsResource - Client elasticacheiface.ElastiCacheAPI + Client ElasticacheSubnetGroupsAPI Region string GroupNames []string } -func (sg *ElasticacheSubnetGroups) Init(session *session.Session) { - sg.Client = elasticache.New(session) +func (sg *ElasticacheSubnetGroups) InitV2(cfg aws.Config) { + sg.Client = elasticache.NewFromConfig(cfg) } +func (sg *ElasticacheSubnetGroups) IsUsingV2() bool { return true } + func (sg *ElasticacheSubnetGroups) ResourceName() string { return "elasticacheSubnetGroups" } @@ -145,13 +164,13 @@ func (sg *ElasticacheSubnetGroups) GetAndSetIdentifiers(c context.Context, confi return nil, err } - sg.GroupNames = awsgo.StringValueSlice(identifiers) + sg.GroupNames = aws.ToStringSlice(identifiers) return sg.GroupNames, nil } // Nuke - nuke 'em all!!! func (sg *ElasticacheSubnetGroups) Nuke(identifiers []string) error { - if err := sg.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := sg.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/elb.go b/aws/resources/elb.go index be15253d..52262b49 100644 --- a/aws/resources/elb.go +++ b/aws/resources/elb.go @@ -4,27 +4,25 @@ import ( "context" "time" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/gruntwork-io/cloud-nuke/config" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" - "github.com/aws/aws-sdk-go/service/elb" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" "github.com/gruntwork-io/go-commons/errors" ) -func (balancer *LoadBalancers) waitUntilElbDeleted(input *elb.DescribeLoadBalancersInput) error { +func (balancer *LoadBalancers) waitUntilElbDeleted(input *elasticloadbalancing.DescribeLoadBalancersInput) error { for i := 0; i < 30; i++ { - _, err := balancer.Client.DescribeLoadBalancersWithContext(balancer.Context, input) + output, err := balancer.Client.DescribeLoadBalancers(balancer.Context, input) if err != nil { - if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "LoadBalancerNotFound" { - return nil - } - return err } + if len(output.LoadBalancerDescriptions) == 0 { + return nil + } + time.Sleep(1 * time.Second) logging.Debug("Waiting for ELB to be deleted") } @@ -34,7 +32,7 @@ func (balancer *LoadBalancers) waitUntilElbDeleted(input *elb.DescribeLoadBalanc // Returns a formatted string of ELB names func (balancer *LoadBalancers) getAll(c context.Context, configObj config.Config) ([]*string, error) { - result, err := balancer.Client.DescribeLoadBalancersWithContext(balancer.Context, &elb.DescribeLoadBalancersInput{}) + result, err := balancer.Client.DescribeLoadBalancers(balancer.Context, &elasticloadbalancing.DescribeLoadBalancersInput{}) if err != nil { return nil, errors.WithStackTrace(err) } @@ -63,15 +61,15 @@ func (balancer *LoadBalancers) nukeAll(names []*string) error { var deletedNames []*string for _, name := range names { - params := &elb.DeleteLoadBalancerInput{ + params := &elasticloadbalancing.DeleteLoadBalancerInput{ LoadBalancerName: name, } - _, err := balancer.Client.DeleteLoadBalancerWithContext(balancer.Context, params) + _, err := balancer.Client.DeleteLoadBalancer(balancer.Context, params) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(name), + Identifier: aws.ToString(name), ResourceType: "Load Balancer (v1)", Error: err, } @@ -86,8 +84,8 @@ func (balancer *LoadBalancers) nukeAll(names []*string) error { } if len(deletedNames) > 0 { - err := balancer.waitUntilElbDeleted(&elb.DescribeLoadBalancersInput{ - LoadBalancerNames: deletedNames, + err := balancer.waitUntilElbDeleted(&elasticloadbalancing.DescribeLoadBalancersInput{ + LoadBalancerNames: aws.ToStringSlice(deletedNames), }) if err != nil { logging.Debugf("[Failed] %s", err) diff --git a/aws/resources/elb_test.go b/aws/resources/elb_test.go index b594b9ac..b96757e0 100644 --- a/aws/resources/elb_test.go +++ b/aws/resources/elb_test.go @@ -6,32 +6,28 @@ import ( "testing" "time" - "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/elb" - "github.com/aws/aws-sdk-go/service/elb/elbiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing/types" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedLoadBalancers struct { - elbiface.ELBAPI - DescribeLoadBalancersOutput elb.DescribeLoadBalancersOutput - DeleteLoadBalancerOutput elb.DeleteLoadBalancerOutput - DescribeLoadBalancersError error + LoadBalancersAPI + DescribeLoadBalancersOutput elasticloadbalancing.DescribeLoadBalancersOutput + DeleteLoadBalancerOutput elasticloadbalancing.DeleteLoadBalancerOutput } -func (m mockedLoadBalancers) DescribeLoadBalancersWithContext(_ aws.Context, input *elb.DescribeLoadBalancersInput, _ ...request.Option) (*elb.DescribeLoadBalancersOutput, error) { +func (m mockedLoadBalancers) DescribeLoadBalancers(ctx context.Context, params *elasticloadbalancing.DescribeLoadBalancersInput, optFns ...func(*elasticloadbalancing.Options)) (*elasticloadbalancing.DescribeLoadBalancersOutput, error) { return &m.DescribeLoadBalancersOutput, nil } -func (m mockedLoadBalancers) DeleteLoadBalancerWithContext(_ aws.Context, input *elb.DeleteLoadBalancerInput, _ ...request.Option) (*elb.DeleteLoadBalancerOutput, error) { - return &m.DeleteLoadBalancerOutput, m.DescribeLoadBalancersError +func (m mockedLoadBalancers) DeleteLoadBalancer(ctx context.Context, params *elasticloadbalancing.DeleteLoadBalancerInput, optFns ...func(*elasticloadbalancing.Options)) (*elasticloadbalancing.DeleteLoadBalancerOutput, error) { + return &m.DeleteLoadBalancerOutput, nil } func TestElb_GetAll(t *testing.T) { - t.Parallel() testName1 := "test-name-1" @@ -39,8 +35,8 @@ func TestElb_GetAll(t *testing.T) { now := time.Now() balancer := LoadBalancers{ Client: mockedLoadBalancers{ - DescribeLoadBalancersOutput: elb.DescribeLoadBalancersOutput{ - LoadBalancerDescriptions: []*elb.LoadBalancerDescription{ + DescribeLoadBalancersOutput: elasticloadbalancing.DescribeLoadBalancersOutput{ + LoadBalancerDescriptions: []types.LoadBalancerDescription{ { LoadBalancerName: aws.String(testName1), CreatedTime: aws.Time(now), @@ -85,19 +81,17 @@ func TestElb_GetAll(t *testing.T) { ELBv1: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } func TestElb_NukeAll(t *testing.T) { - t.Parallel() balancer := LoadBalancers{ Client: mockedLoadBalancers{ - DeleteLoadBalancerOutput: elb.DeleteLoadBalancerOutput{}, - DescribeLoadBalancersError: awserr.New("LoadBalancerNotFound", "", nil), + DeleteLoadBalancerOutput: elasticloadbalancing.DeleteLoadBalancerOutput{}, }, } diff --git a/aws/resources/elb_types.go b/aws/resources/elb_types.go index 3360ce85..34ec2782 100644 --- a/aws/resources/elb_types.go +++ b/aws/resources/elb_types.go @@ -3,26 +3,31 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/elb" - "github.com/aws/aws-sdk-go/service/elb/elbiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type LoadBalancersAPI interface { + DescribeLoadBalancers(ctx context.Context, params *elasticloadbalancing.DescribeLoadBalancersInput, optFns ...func(*elasticloadbalancing.Options)) (*elasticloadbalancing.DescribeLoadBalancersOutput, error) + DeleteLoadBalancer(ctx context.Context, params *elasticloadbalancing.DeleteLoadBalancerInput, optFns ...func(*elasticloadbalancing.Options)) (*elasticloadbalancing.DeleteLoadBalancerOutput, error) +} + // LoadBalancers - represents all load balancers type LoadBalancers struct { BaseAwsResource - Client elbiface.ELBAPI + Client LoadBalancersAPI Region string Names []string } -func (balancer *LoadBalancers) Init(session *session.Session) { - balancer.Client = elb.New(session) +func (balancer *LoadBalancers) InitV2(cfg aws.Config) { + balancer.Client = elasticloadbalancing.NewFromConfig(cfg) } +func (balancer *LoadBalancers) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource func (balancer *LoadBalancers) ResourceName() string { return "elb" @@ -48,13 +53,13 @@ func (balancer *LoadBalancers) GetAndSetIdentifiers(c context.Context, configObj return nil, err } - balancer.Names = awsgo.StringValueSlice(identifiers) + balancer.Names = aws.ToStringSlice(identifiers) return balancer.Names, nil } // Nuke - nuke 'em all!!! func (balancer *LoadBalancers) Nuke(identifiers []string) error { - if err := balancer.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := balancer.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/elbv2.go b/aws/resources/elbv2.go index eb24a67d..b4b3406e 100644 --- a/aws/resources/elbv2.go +++ b/aws/resources/elbv2.go @@ -2,18 +2,19 @@ package resources import ( "context" + "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/elbv2" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" "github.com/gruntwork-io/go-commons/errors" ) -// Returns a formatted string of ELBv2 Arns +// Returns a formatted string of ELBv2 ARNs func (balancer *LoadBalancersV2) getAll(c context.Context, configObj config.Config) ([]*string, error) { - result, err := balancer.Client.DescribeLoadBalancersWithContext(balancer.Context, &elbv2.DescribeLoadBalancersInput{}) + result, err := balancer.Client.DescribeLoadBalancers(balancer.Context, &elasticloadbalancingv2.DescribeLoadBalancersInput{}) if err != nil { return nil, errors.WithStackTrace(err) } @@ -42,15 +43,15 @@ func (balancer *LoadBalancersV2) nukeAll(arns []*string) error { var deletedArns []*string for _, arn := range arns { - params := &elbv2.DeleteLoadBalancerInput{ + params := &elasticloadbalancingv2.DeleteLoadBalancerInput{ LoadBalancerArn: arn, } - _, err := balancer.Client.DeleteLoadBalancerWithContext(balancer.Context, params) + _, err := balancer.Client.DeleteLoadBalancer(balancer.Context, params) // Record status of this resource e := report.Entry{ - Identifier: aws.StringValue(arn), + Identifier: aws.ToString(arn), ResourceType: "Load Balancer (v2)", Error: err, } @@ -65,9 +66,10 @@ func (balancer *LoadBalancersV2) nukeAll(arns []*string) error { } if len(deletedArns) > 0 { - err := balancer.Client.WaitUntilLoadBalancersDeletedWithContext(balancer.Context, &elbv2.DescribeLoadBalancersInput{ - LoadBalancerArns: deletedArns, - }) + waiter := elasticloadbalancingv2.NewLoadBalancersDeletedWaiter(balancer.Client) + err := waiter.Wait(balancer.Context, &elasticloadbalancingv2.DescribeLoadBalancersInput{ + LoadBalancerArns: aws.ToStringSlice(deletedArns), + }, 15*time.Minute) if err != nil { logging.Debugf("[Failed] %s", err) return errors.WithStackTrace(err) diff --git a/aws/resources/elbv2_test.go b/aws/resources/elbv2_test.go index 34c0ae33..16d7dad4 100644 --- a/aws/resources/elbv2_test.go +++ b/aws/resources/elbv2_test.go @@ -2,40 +2,36 @@ package resources import ( "context" + "fmt" "regexp" "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types" + "github.com/aws/smithy-go" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedElbV2 struct { - elbv2iface.ELBV2API - DescribeLoadBalancersOutput elbv2.DescribeLoadBalancersOutput - DeleteLoadBalancerOutput elbv2.DeleteLoadBalancerOutput + LoadBalancersV2API + DescribeLoadBalancersOutput elasticloadbalancingv2.DescribeLoadBalancersOutput + ErrDescribeLoadBalancersOutput error + DeleteLoadBalancerOutput elasticloadbalancingv2.DeleteLoadBalancerOutput } -func (m mockedElbV2) DescribeLoadBalancersWithContext(_ aws.Context, input *elbv2.DescribeLoadBalancersInput, _ ...request.Option) (*elbv2.DescribeLoadBalancersOutput, error) { - return &m.DescribeLoadBalancersOutput, nil +func (m mockedElbV2) DescribeLoadBalancers(ctx context.Context, params *elasticloadbalancingv2.DescribeLoadBalancersInput, optFns ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeLoadBalancersOutput, error) { + return &m.DescribeLoadBalancersOutput, m.ErrDescribeLoadBalancersOutput } -func (m mockedElbV2) DeleteLoadBalancerWithContext(_ aws.Context, input *elbv2.DeleteLoadBalancerInput, _ ...request.Option) (*elbv2.DeleteLoadBalancerOutput, error) { +func (m mockedElbV2) DeleteLoadBalancer(ctx context.Context, params *elasticloadbalancingv2.DeleteLoadBalancerInput, optFns ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DeleteLoadBalancerOutput, error) { return &m.DeleteLoadBalancerOutput, nil } -func (m mockedElbV2) WaitUntilLoadBalancersDeletedWithContext(_ aws.Context, input *elbv2.DescribeLoadBalancersInput, _ ...request.WaiterOption) error { - return nil -} - func TestElbV2_GetAll(t *testing.T) { - t.Parallel() - testName1 := "test-name-1" testArn1 := "test-arn-1" testName2 := "test-name-2" @@ -43,8 +39,8 @@ func TestElbV2_GetAll(t *testing.T) { now := time.Now() balancer := LoadBalancersV2{ Client: mockedElbV2{ - DescribeLoadBalancersOutput: elbv2.DescribeLoadBalancersOutput{ - LoadBalancers: []*elbv2.LoadBalancer{ + DescribeLoadBalancersOutput: elasticloadbalancingv2.DescribeLoadBalancersOutput{ + LoadBalancers: []types.LoadBalancer{ { LoadBalancerArn: aws.String(testArn1), LoadBalancerName: aws.String(testName1), @@ -91,22 +87,43 @@ func TestElbV2_GetAll(t *testing.T) { ELBv2: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } +} + +type errMockLoadBalancerNotFound struct{} +func (e errMockLoadBalancerNotFound) Error() string { + return fmt.Sprintf("%s: %s", e.ErrorCode(), e.ErrorMessage()) } -func TestElbV2_NukeAll(t *testing.T) { +func (e errMockLoadBalancerNotFound) ErrorCode() string { + return "LoadBalancerNotFound" +} - t.Parallel() +func (e errMockLoadBalancerNotFound) ErrorMessage() string { + return "The specified load balancer does not exist." +} + +func (e errMockLoadBalancerNotFound) ErrorFault() smithy.ErrorFault { + return smithy.FaultServer +} +func TestElbV2_NukeAll(t *testing.T) { + t.Parallel() + var eLBNotFound errMockLoadBalancerNotFound balancer := LoadBalancersV2{ + BaseAwsResource: BaseAwsResource{ + Context: context.Background(), + }, Client: mockedElbV2{ - DeleteLoadBalancerOutput: elbv2.DeleteLoadBalancerOutput{}, + DescribeLoadBalancersOutput: elasticloadbalancingv2.DescribeLoadBalancersOutput{}, + ErrDescribeLoadBalancersOutput: eLBNotFound, + DeleteLoadBalancerOutput: elasticloadbalancingv2.DeleteLoadBalancerOutput{}, }, } - err := balancer.nukeAll([]*string{aws.String("test-arn-1"), aws.String("test-arn-2")}) + err := balancer.nukeAll([]*string{aws.String("test-arn-1")}) require.NoError(t, err) } diff --git a/aws/resources/elbv2_types.go b/aws/resources/elbv2_types.go index 55290fd8..171a977f 100644 --- a/aws/resources/elbv2_types.go +++ b/aws/resources/elbv2_types.go @@ -3,26 +3,31 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/elbv2" - "github.com/aws/aws-sdk-go/service/elbv2/elbv2iface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/go-commons/errors" ) +type LoadBalancersV2API interface { + DescribeLoadBalancers(ctx context.Context, params *elasticloadbalancingv2.DescribeLoadBalancersInput, optFns ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DescribeLoadBalancersOutput, error) + DeleteLoadBalancer(ctx context.Context, params *elasticloadbalancingv2.DeleteLoadBalancerInput, optFns ...func(*elasticloadbalancingv2.Options)) (*elasticloadbalancingv2.DeleteLoadBalancerOutput, error) +} + // LoadBalancersV2 - represents all load balancers type LoadBalancersV2 struct { BaseAwsResource - Client elbv2iface.ELBV2API + Client LoadBalancersV2API Region string Arns []string } -func (balancer *LoadBalancersV2) Init(session *session.Session) { - balancer.Client = elbv2.New(session) +func (balancer *LoadBalancersV2) InitV2(cfg aws.Config) { + balancer.Client = elasticloadbalancingv2.NewFromConfig(cfg) } +func (balancer *LoadBalancersV2) IsUsingV2() bool { return true } + // ResourceName - the simple name of the aws resource func (balancer *LoadBalancersV2) ResourceName() string { return "elbv2" @@ -48,13 +53,13 @@ func (balancer *LoadBalancersV2) GetAndSetIdentifiers(c context.Context, configO return nil, err } - balancer.Arns = awsgo.StringValueSlice(identifiers) + balancer.Arns = aws.ToStringSlice(identifiers) return balancer.Arns, nil } // Nuke - nuke 'em all!!! func (balancer *LoadBalancersV2) Nuke(identifiers []string) error { - if err := balancer.nukeAll(awsgo.StringSlice(identifiers)); err != nil { + if err := balancer.nukeAll(aws.StringSlice(identifiers)); err != nil { return errors.WithStackTrace(err) } diff --git a/aws/resources/guardduty.go b/aws/resources/guardduty.go index 2b57b85e..e131c395 100644 --- a/aws/resources/guardduty.go +++ b/aws/resources/guardduty.go @@ -3,8 +3,8 @@ package resources import ( "context" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/guardduty" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/guardduty" "github.com/gruntwork-io/cloud-nuke/config" "github.com/gruntwork-io/cloud-nuke/logging" "github.com/gruntwork-io/cloud-nuke/report" @@ -19,28 +19,27 @@ type DetectorOutputWithID struct { func (gd *GuardDuty) getAll(c context.Context, configObj config.Config) ([]*string, error) { var detectorIdsToInclude []*string - var detectorIds []*string - err := gd.Client.ListDetectorsPagesWithContext(gd.Context, &guardduty.ListDetectorsInput{}, func(page *guardduty.ListDetectorsOutput, lastPage bool) bool { - detectorIds = append(detectorIds, page.DetectorIds...) - return !lastPage - }) - if err != nil { - return nil, errors.WithStackTrace(err) - } - - // Due to the ListDetectors method only returning the Ids of found detectors, we need to further enrich our data about - // each detector with a separate call to GetDetector for metadata including when it was created, which we need to make the - // determination about whether or not the given detector should be included - for _, detectorId := range detectorIds { - detector, err := gd.Client.GetDetectorWithContext(gd.Context, &guardduty.GetDetectorInput{ - DetectorId: detectorId, - }) + paginator := guardduty.NewListDetectorsPaginator(gd.Client, &guardduty.ListDetectorsInput{}) + for paginator.HasMorePages() { + page, err := paginator.NextPage(c) if err != nil { return nil, errors.WithStackTrace(err) } - if gd.shouldInclude(detector, detectorId, configObj) { - detectorIdsToInclude = append(detectorIdsToInclude, detectorId) + // Due to the ListDetectors method only returning the Ids of found detectors, we need to further enrich our data about + // each detector with a separate call to GetDetector for metadata including when it was created, which we need to make the + // determination about whether or not the given detector should be included + for _, detectorId := range page.DetectorIds { + detector, err := gd.Client.GetDetector(gd.Context, &guardduty.GetDetectorInput{ + DetectorId: aws.String(detectorId), + }) + if err != nil { + return nil, errors.WithStackTrace(err) + } + + if gd.shouldInclude(detector, aws.String(detectorId), configObj) { + detectorIdsToInclude = append(detectorIdsToInclude, aws.String(detectorId)) + } } } @@ -65,14 +64,14 @@ func (gd *GuardDuty) nukeAll(detectorIds []string) error { logging.Debugf("Deleting all GuardDuty detectors in region %s", gd.Region) - deletedIds := []string{} + var deletedIds []string for _, detectorId := range detectorIds { params := &guardduty.DeleteDetectorInput{ DetectorId: aws.String(detectorId), } - _, err := gd.Client.DeleteDetectorWithContext(gd.Context, params) + _, err := gd.Client.DeleteDetector(gd.Context, params) // Record status of this resource e := report.Entry{ diff --git a/aws/resources/guardduty_test.go b/aws/resources/guardduty_test.go index 6aa6ec14..286d6cf6 100644 --- a/aws/resources/guardduty_test.go +++ b/aws/resources/guardduty_test.go @@ -5,47 +5,42 @@ import ( "testing" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/request" - "github.com/aws/aws-sdk-go/service/guardduty" - "github.com/aws/aws-sdk-go/service/guardduty/guarddutyiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/guardduty" "github.com/gruntwork-io/cloud-nuke/config" "github.com/stretchr/testify/require" ) type mockedGuardDuty struct { - guarddutyiface.GuardDutyAPI + GuardDutyAPI ListDetectorsPagesOutput guardduty.ListDetectorsOutput GetDetectorOutput guardduty.GetDetectorOutput DeleteDetectorOutput guardduty.DeleteDetectorOutput } -func (m mockedGuardDuty) ListDetectorsPagesWithContext(_ aws.Context, input *guardduty.ListDetectorsInput, callback func(*guardduty.ListDetectorsOutput, bool) bool, _ ...request.Option) error { - callback(&m.ListDetectorsPagesOutput, true) - return nil -} - -func (m mockedGuardDuty) GetDetectorWithContext(_ aws.Context, input *guardduty.GetDetectorInput, _ ...request.Option) (*guardduty.GetDetectorOutput, error) { +func (m mockedGuardDuty) GetDetector(ctx context.Context, params *guardduty.GetDetectorInput, optFns ...func(*guardduty.Options)) (*guardduty.GetDetectorOutput, error) { return &m.GetDetectorOutput, nil } -func (m mockedGuardDuty) DeleteDetectorWithContext(_ aws.Context, input *guardduty.DeleteDetectorInput, _ ...request.Option) (*guardduty.DeleteDetectorOutput, error) { +func (m mockedGuardDuty) DeleteDetector(ctx context.Context, params *guardduty.DeleteDetectorInput, optFns ...func(*guardduty.Options)) (*guardduty.DeleteDetectorOutput, error) { return &m.DeleteDetectorOutput, nil } -func TestGuardDuty_GetAll(t *testing.T) { +func (m mockedGuardDuty) ListDetectors(ctx context.Context, params *guardduty.ListDetectorsInput, optFns ...func(*guardduty.Options)) (*guardduty.ListDetectorsOutput, error) { + return &m.ListDetectorsPagesOutput, nil +} +func TestGuardDuty_GetAll(t *testing.T) { t.Parallel() - testId1 := "test-detector-id-1" testId2 := "test-detector-id-2" now := time.Now() gd := GuardDuty{ Client: mockedGuardDuty{ ListDetectorsPagesOutput: guardduty.ListDetectorsOutput{ - DetectorIds: []*string{ - aws.String(testId1), - aws.String(testId2), + DetectorIds: []string{ + testId1, + testId2, }, }, GetDetectorOutput: guardduty.GetDetectorOutput{ @@ -76,15 +71,13 @@ func TestGuardDuty_GetAll(t *testing.T) { GuardDuty: tc.configObj, }) require.NoError(t, err) - require.Equal(t, tc.expected, aws.StringValueSlice(names)) + require.Equal(t, tc.expected, aws.ToStringSlice(names)) }) } } func TestGuardDuty_NukeAll(t *testing.T) { - t.Parallel() - gd := GuardDuty{ Client: mockedGuardDuty{ DeleteDetectorOutput: guardduty.DeleteDetectorOutput{}, @@ -93,5 +86,4 @@ func TestGuardDuty_NukeAll(t *testing.T) { err := gd.nukeAll([]string{"test"}) require.NoError(t, err) - } diff --git a/aws/resources/guardduty_types.go b/aws/resources/guardduty_types.go index 9fe20b20..c3a41f95 100644 --- a/aws/resources/guardduty_types.go +++ b/aws/resources/guardduty_types.go @@ -3,24 +3,30 @@ package resources import ( "context" - awsgo "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/session" - "github.com/aws/aws-sdk-go/service/guardduty" - "github.com/aws/aws-sdk-go/service/guardduty/guarddutyiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/guardduty" "github.com/gruntwork-io/cloud-nuke/config" ) +type GuardDutyAPI interface { + GetDetector(ctx context.Context, params *guardduty.GetDetectorInput, optFns ...func(*guardduty.Options)) (*guardduty.GetDetectorOutput, error) + DeleteDetector(ctx context.Context, params *guardduty.DeleteDetectorInput, optFns ...func(*guardduty.Options)) (*guardduty.DeleteDetectorOutput, error) + ListDetectors(ctx context.Context, params *guardduty.ListDetectorsInput, optFns ...func(*guardduty.Options)) (*guardduty.ListDetectorsOutput, error) +} + type GuardDuty struct { BaseAwsResource - Client guarddutyiface.GuardDutyAPI + Client GuardDutyAPI Region string detectorIds []string } -func (gd *GuardDuty) Init(session *session.Session) { - gd.Client = guardduty.New(session) +func (gd *GuardDuty) InitV2(cfg aws.Config) { + gd.Client = guardduty.NewFromConfig(cfg) } +func (gd *GuardDuty) IsUsingV2() bool { return true } + func (gd *GuardDuty) ResourceName() string { return "guardduty" } @@ -43,7 +49,7 @@ func (gd *GuardDuty) GetAndSetIdentifiers(c context.Context, configObj config.Co return nil, err } - gd.detectorIds = awsgo.StringValueSlice(identifiers) + gd.detectorIds = aws.ToStringSlice(identifiers) return gd.detectorIds, nil } diff --git a/go.mod b/go.mod index 870544ab..98f3e046 100644 --- a/go.mod +++ b/go.mod @@ -5,16 +5,16 @@ go 1.21 require ( github.com/aws/aws-sdk-go v1.49.13 github.com/aws/aws-sdk-go-v2 v1.32.3 - github.com/aws/aws-sdk-go-v2/config v1.27.24 - github.com/aws/aws-sdk-go-v2/credentials v1.17.24 + github.com/aws/aws-sdk-go-v2/config v1.28.1 + github.com/aws/aws-sdk-go-v2/credentials v1.17.42 github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.34.3 github.com/aws/aws-sdk-go-v2/service/acm v1.30.3 github.com/aws/aws-sdk-go-v2/service/acmpca v1.37.4 - github.com/aws/aws-sdk-go-v2/service/amp v1.27.1 + github.com/aws/aws-sdk-go-v2/service/amp v1.30.0 github.com/aws/aws-sdk-go-v2/service/apigateway v1.27.3 github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.24.3 github.com/aws/aws-sdk-go-v2/service/apprunner v1.32.3 - github.com/aws/aws-sdk-go-v2/service/autoscaling v1.23.16 + github.com/aws/aws-sdk-go-v2/service/autoscaling v1.47.0 github.com/aws/aws-sdk-go-v2/service/backup v1.39.4 github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.44.3 github.com/aws/aws-sdk-go-v2/service/cloudwatch v1.42.3 @@ -23,12 +23,22 @@ require ( github.com/aws/aws-sdk-go-v2/service/configservice v1.50.3 github.com/aws/aws-sdk-go-v2/service/datasync v1.43.0 github.com/aws/aws-sdk-go-v2/service/dynamodb v1.36.3 - github.com/aws/aws-sdk-go-v2/service/ec2 v1.185.0 - github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.7 - github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.7 - github.com/aws/aws-sdk-go-v2/service/sns v1.32.3 - github.com/aws/aws-sdk-go-v2/service/sqs v1.35.3 + github.com/aws/aws-sdk-go-v2/service/ec2 v1.187.0 + github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 + github.com/aws/aws-sdk-go-v2/service/ecs v1.49.0 + github.com/aws/aws-sdk-go-v2/service/efs v1.33.3 + github.com/aws/aws-sdk-go-v2/service/eks v1.51.1 + github.com/aws/aws-sdk-go-v2/service/elasticache v1.43.1 + github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.28.3 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.28.3 + github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.41.0 + github.com/aws/aws-sdk-go-v2/service/eventbridge v1.35.3 + github.com/aws/aws-sdk-go-v2/service/guardduty v1.50.1 + github.com/aws/aws-sdk-go-v2/service/scheduler v1.12.3 + github.com/aws/aws-sdk-go-v2/service/sns v1.33.3 + github.com/aws/aws-sdk-go-v2/service/sqs v1.36.3 github.com/aws/aws-sdk-go-v2/service/vpclattice v1.12.3 + github.com/aws/smithy-go v1.22.0 github.com/charmbracelet/lipgloss v0.6.0 github.com/go-errors/errors v1.4.2 github.com/gruntwork-io/go-commons v0.17.0 @@ -45,18 +55,17 @@ require ( atomicgo.dev/cursor v0.1.1 // indirect atomicgo.dev/keyboard v0.2.8 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 // indirect github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.3 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 // indirect - github.com/aws/smithy-go v1.22.0 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 // indirect github.com/containerd/console v1.0.3 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 38ea0dc9..7e6777f7 100644 --- a/go.sum +++ b/go.sum @@ -22,10 +22,16 @@ github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6 h1:pT3hpW0cOHRJx8Y0 github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.6/go.mod h1:j/I2++U0xX+cr44QjHay4Cvxj6FUbnxrgmqN3H1jTZA= github.com/aws/aws-sdk-go-v2/config v1.27.24 h1:NM9XicZ5o1CBU/MZaHwFtimRpWx9ohAUAqkG6AqSqPo= github.com/aws/aws-sdk-go-v2/config v1.27.24/go.mod h1:aXzi6QJTuQRVVusAO8/NxpdTeTyr/wRcybdDtfUwJSs= +github.com/aws/aws-sdk-go-v2/config v1.28.1 h1:oxIvOUXy8x0U3fR//0eq+RdCKimWI900+SV+10xsCBw= +github.com/aws/aws-sdk-go-v2/config v1.28.1/go.mod h1:bRQcttQJiARbd5JZxw6wG0yIK3eLeSCPdg6uqmmlIiI= github.com/aws/aws-sdk-go-v2/credentials v1.17.24 h1:YclAsrnb1/GTQNt2nzv+756Iw4mF8AOzcDfweWwwm/M= github.com/aws/aws-sdk-go-v2/credentials v1.17.24/go.mod h1:Hld7tmnAkoBQdTMNYZGzztzKRdA4fCdn9L83LOoigac= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42 h1:sBP0RPjBU4neGpIYyx8mkU2QqLPl5u9cmdTWVzIpHkM= +github.com/aws/aws-sdk-go-v2/credentials v1.17.42/go.mod h1:FwZBfU530dJ26rv9saAbxa9Ej3eF/AK0OAY86k13n4M= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/lQRMaIpJkLLaJ1ZI76no= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18 h1:68jFVtt3NulEzojFesM/WVarlFpCaXLKaBxDpzkQ9OQ= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.18/go.mod h1:Fjnn5jQVIo6VyedMc0/EhPpfNlPl7dHV916O6B+49aE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.23/go.mod h1:2DFxAQ9pfIRy0imBCJv+vZ2X6RKxves6fbnEuSry6b4= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22 h1:Jw50LwEkVjuVzE1NzkhNKkBf9cRN7MtE1F/b2cOKTUM= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.22/go.mod h1:Y/SmAyPcOTmpeVaWSzSKiILfXTVJwrGmYZhcRbhWuEY= @@ -34,8 +40,12 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22 h1:981MHwBaRZM7+9QSR6 github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.22/go.mod h1:1RA1+aBEfn+CAB/Mh0MB6LsdCYCnjZm7tKXtnk499ZQ= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 h1:hT8rVHwugYE2lEfdFE0QWVo81lF7jMrYJVDWI+f+VxU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 h1:VaRN3TlFdd6KxX1x3ILT5ynH6HvKgqdiXoTxAF4HQcQ= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17 h1:Roo69qTpfu8OlJ2Tb7pAYVuF0CpuUMB0IYWwYP/4DZM= github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.17/go.mod h1:NcWPxQzGM1USQggaTVwz6VpqMZPX1CvDJLDh6jnOCa4= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22 h1:yV+hCAHZZYJQcwAaszoBNwLbPItHvApxT0kVIw6jRgs= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.3.22/go.mod h1:kbR1TL8llqB1eGnVbybcA4/wgScxdylOdyAd51yxPdw= github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.34.3 h1:ScJw+8v6RPTJbuWxowSiUw8xdPL0aQOAbakC6mF1uZU= github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.34.3/go.mod h1:PTv5/X1+6atCKR/vK3kbm9Ra/zzX/T/92Y/4MuL6ArU= github.com/aws/aws-sdk-go-v2/service/acm v1.30.3 h1:/7wq5haORYzJUkAbD9Hh4/SGiwupLhPdGqIzf+taLOA= @@ -44,6 +54,8 @@ github.com/aws/aws-sdk-go-v2/service/acmpca v1.37.4 h1:uWqTNc//8pMepB0qUzu+r13Qy github.com/aws/aws-sdk-go-v2/service/acmpca v1.37.4/go.mod h1:WVF7A3ipjS/vpzOY09xJDeH8ja+rDbnl5u2mL26rt60= github.com/aws/aws-sdk-go-v2/service/amp v1.27.1 h1:va9j7MGA8jBlQs9KujMlkSdnC26TuEJXv7ywnFjmTZ8= github.com/aws/aws-sdk-go-v2/service/amp v1.27.1/go.mod h1:QhmX7qjomjuHJjCJbW+QRdaCBM42v1eAbWvBVFrT1Vw= +github.com/aws/aws-sdk-go-v2/service/amp v1.30.0 h1:1AQM/Lo024FKGTW/iwIDQHV8+5j8/h0iabYm+4jB5Bo= +github.com/aws/aws-sdk-go-v2/service/amp v1.30.0/go.mod h1:4OQEJHTg0Z2Q32qQUDWquPZKmLagi5/BVzTCYtcnpJo= github.com/aws/aws-sdk-go-v2/service/apigateway v1.27.3 h1:81BvgDQ0bYSim7mFZWSwsX0DRkMkxsYGCpgGfEagnks= github.com/aws/aws-sdk-go-v2/service/apigateway v1.27.3/go.mod h1:EN7f1IzcWoBfc2wwp8aftbof+ib5uk9b5OO1sQvPwB0= github.com/aws/aws-sdk-go-v2/service/apigatewayv2 v1.24.3 h1:LNnp0zMnX20sO+lUZ9e7tMRmIk311vgPgH3f6K1XbqU= @@ -52,6 +64,8 @@ github.com/aws/aws-sdk-go-v2/service/apprunner v1.32.3 h1:wkQpocpYy3/SqFf8iUO1uB github.com/aws/aws-sdk-go-v2/service/apprunner v1.32.3/go.mod h1:lOQv8hfiAZCHdi+wNKBKdSqf1yCKzWiOEQNVKoK/Jko= github.com/aws/aws-sdk-go-v2/service/autoscaling v1.23.16 h1:cp30gVVAbZfeDod6UJGppMH2+p+/cRCG2AZ1TbT+LqA= github.com/aws/aws-sdk-go-v2/service/autoscaling v1.23.16/go.mod h1:hHTMeJt6CQwFdmS19RK1LsDscus8c25Ve8KiYRhsISg= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.47.0 h1:3yvZKeDa/slOTk8Gym4ym9u7AKhYAvy0Y00oRE+HRvE= +github.com/aws/aws-sdk-go-v2/service/autoscaling v1.47.0/go.mod h1:SDmFD5Xuoa8dHPOLakoiURaUXei4zcqrkZ0/myZch/A= github.com/aws/aws-sdk-go-v2/service/backup v1.39.4 h1:4JLXjQf1vEDFmGjr2Z+jLFkMvAEb3aHmq4ChiL+npdA= github.com/aws/aws-sdk-go-v2/service/backup v1.39.4/go.mod h1:bXVDvryQpYdWh2pqCk0L/RtKSAwucmAqiyByKLPF1W8= github.com/aws/aws-sdk-go-v2/service/cloudtrail v1.44.3 h1:wVATQoy9BnfUTPlcfliv8IVboUxfbFl36tIxjQ6LR3c= @@ -70,26 +84,62 @@ github.com/aws/aws-sdk-go-v2/service/dynamodb v1.36.3 h1:pS5ka5Z026eG29K3cce+yxG github.com/aws/aws-sdk-go-v2/service/dynamodb v1.36.3/go.mod h1:MBT8rSGSZjJiV6X7rlrVGoIt+mCoaw0VbpdVtsrsJfk= github.com/aws/aws-sdk-go-v2/service/ec2 v1.185.0 h1:WPhQgVHZUEsIRGEFh5B7VmwFzTkYgk7CxjWxZOgjQco= github.com/aws/aws-sdk-go-v2/service/ec2 v1.185.0/go.mod h1:kYXaB4FzyhEJjvrJ84oPnMElLiEAjGxxUunVW2tBSng= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.187.0 h1:cA4hWo269CN5RY7Arqt8BfzXF0KIN8DSNo/KcqHKkWk= +github.com/aws/aws-sdk-go-v2/service/ec2 v1.187.0/go.mod h1:ossaD9Z1ugYb6sq9QIqQLEOorCGcqUoxlhud9M9yE70= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3 h1:bqmoQEKpWFRDRxOv4lC5yZLc+N1cogZHPLeQACfVUJo= +github.com/aws/aws-sdk-go-v2/service/ecr v1.36.3/go.mod h1:KwOqlt4MOBK9EpOGkj8RU9fqfTEae5AOUHi1pDEZ3OQ= +github.com/aws/aws-sdk-go-v2/service/ecs v1.49.0 h1:xhCV6zY5ZFzfyAUOiBXK6wh0HVQTBkvNwA/eiz89ZWY= +github.com/aws/aws-sdk-go-v2/service/ecs v1.49.0/go.mod h1:RXYd/Ts+sFnjDrVdAZsAfHVkYxQUxhC+l2zrSpSgCGc= +github.com/aws/aws-sdk-go-v2/service/efs v1.33.3 h1:PvOnbQfS7gR6x9e3THv9k441t0Pyk2Se8TvVWedz6EM= +github.com/aws/aws-sdk-go-v2/service/efs v1.33.3/go.mod h1:lgRqCGG4HGimYuAkEjtzekYr7xPjq8+BM51wGarbk1c= +github.com/aws/aws-sdk-go-v2/service/eks v1.51.1 h1:OQjVHkANBbwE055NK49M/kelQbapsQOsSfUUWP1mi3w= +github.com/aws/aws-sdk-go-v2/service/eks v1.51.1/go.mod h1:9wMtzHTjYbK5MLzYBWSznUPsys/n9LapMwb6UhKOVPQ= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.43.1 h1:mNdBr6JqVYp0DSjSiO7snzUo5xoczBBfhuUIHIqutgA= +github.com/aws/aws-sdk-go-v2/service/elasticache v1.43.1/go.mod h1:rPN8bNqTMCKtKxkyVdPra/0J7ecOmRQlBv3BZTq9Fq0= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.28.3 h1:cUhmI37/S8kYMfQrd5JB7zxfbLuXIAJcFJvo//cZLgs= +github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.28.3/go.mod h1:ERGQhQc/0neux01Q60KOG4/3oRgdBNtOJ7/mYPUpjTY= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.28.3 h1:cRDiIyPNUf71QjW6dFbHApMieS4svBvfTKBiEtzQZrs= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancing v1.28.3/go.mod h1:G86bITIZX9wcacVyMHzLz9nEQaQLSBKDHym0spIEr+M= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.41.0 h1:W+xNfPS8dQ8YoszdkHqTDYIgCrWJvyUU/ZgdJ0frCRE= +github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.41.0/go.mod h1:6WuvTcPjB9gff93p/2LNBg09d8xK99jpVO6+fRSCKEU= github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.7 h1:q+xiPu+Dk5MFC20ZjdGGhbihD39Xsih98epvVjnOjyE= github.com/aws/aws-sdk-go-v2/service/eventbridge v1.33.7/go.mod h1:iQCsmx9LyBMyMEkLCBVqnIAz+rfo6/ss3oLcYn26+no= +github.com/aws/aws-sdk-go-v2/service/eventbridge v1.35.3 h1:e/jGXEQi+lyTIhc3s+jbJrq2IWgLXsNbdYxDauWTyPU= +github.com/aws/aws-sdk-go-v2/service/eventbridge v1.35.3/go.mod h1:607CryyDS58whuaVno9CCg3L/nnWOqorxiyAS2f9leY= +github.com/aws/aws-sdk-go-v2/service/guardduty v1.50.1 h1:0A05jzCVA6W/UFqdtpKm8KXE8QhcEn/Fn01Zxsq2Owg= +github.com/aws/aws-sdk-go-v2/service/guardduty v1.50.1/go.mod h1:tfpIzAIeMtSUucGN87ZUA2u5Lqnc04ManYSk3smJpGc= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0 h1:TToQNkvGguu209puTojY/ozlqy2d/SFNcoLIqTFi42g= github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.0/go.mod h1:0jp+ltwkf+SwG2fm/PKo8t4y8pJSgOCO4D8Lz3k0aHQ= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.3 h1:wudRPcZMKytcywXERkR6PLqD8gPx754ZyIOo0iVg488= github.com/aws/aws-sdk-go-v2/service/internal/endpoint-discovery v1.10.3/go.mod h1:yRo5Kj5+m/ScVIZpQOquQvDtSrDM1JLRCnvglBcdNmw= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2 h1:s7NA1SOw8q/5c0wr8477yOPp0z+uBaXBnLE0XYb0POA= github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.2/go.mod h1:fnjjWyAW/Pj5HYOxl9LJqWtEwS7W2qgcRLWP+uWbss0= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3 h1:qcxX0JYlgWH3hpPUnd6U0ikcl6LLA9sLkXE2w1fpMvY= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.3/go.mod h1:cLSNEmI45soc+Ef8K/L+8sEA3A3pYFEYf5B5UI+6bH4= github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.7 h1:EcPyKUUo3neD2tDFKnq3TR3B9s2uZe9eWgxVQgixdzc= github.com/aws/aws-sdk-go-v2/service/scheduler v1.10.7/go.mod h1:MlNx35QVGG8TB2x1kOC0TKd9e93+RmFUE8HzYDLDLso= +github.com/aws/aws-sdk-go-v2/service/scheduler v1.12.3 h1:VrfgbM8+DuUaTRx1Lllajic28bHaaUrYx9tN9JCGXVI= +github.com/aws/aws-sdk-go-v2/service/scheduler v1.12.3/go.mod h1:0ujC4ruQHlBlToSoHj3s/OL9wr7dp7wPrcACMDc87ME= github.com/aws/aws-sdk-go-v2/service/sns v1.32.3 h1:LC5JBrEAdJ0SSRLfNcLzOLsfoc3xO/BAsHiUNcQfDI4= github.com/aws/aws-sdk-go-v2/service/sns v1.32.3/go.mod h1:ZO606Jfatw51c8q29gHVVCnufg2dq3MnmkNLlTZFrkE= +github.com/aws/aws-sdk-go-v2/service/sns v1.33.3 h1:coZW/SqpINT0VWG8vRWWY9TWUof8TDdxublw2Xur0Zc= +github.com/aws/aws-sdk-go-v2/service/sns v1.33.3/go.mod h1:J/G2xuhwNBlDvEi0WR/bnBbac4KSgpkERna/IXEF52w= github.com/aws/aws-sdk-go-v2/service/sqs v1.35.3 h1:Lcs658WFW235QuUfpAdxd8RCy8Va2VUA7/U9iIrcjcY= github.com/aws/aws-sdk-go-v2/service/sqs v1.35.3/go.mod h1:WuGxWQhu2LXoPGA2HBIbotpwhM6T4hAz0Ip/HjdxfJg= +github.com/aws/aws-sdk-go-v2/service/sqs v1.36.3 h1:H1bCg79Q4PDtxQH8Fn5kASQlbVv2WGP5o5IEFEBNOAs= +github.com/aws/aws-sdk-go-v2/service/sqs v1.36.3/go.mod h1:W6Uy6OWgxF9RZuHoikthB6f+A0oYXqnfWmFl5m7E2G4= github.com/aws/aws-sdk-go-v2/service/sso v1.22.1 h1:p1GahKIjyMDZtiKoIn0/jAj/TkMzfzndDv5+zi2Mhgc= github.com/aws/aws-sdk-go-v2/service/sso v1.22.1/go.mod h1:/vWdhoIoYA5hYoPZ6fm7Sv4d8701PiG5VKe8/pPJL60= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3 h1:UTpsIf0loCIWEbrqdLb+0RxnTXfWh2vhw4nQmFi4nPc= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.3/go.mod h1:FZ9j3PFHHAR+w0BSEjK955w5YD2UwB/l/H0yAK3MJvI= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2 h1:ORnrOK0C4WmYV/uYt3koHEWBLYsRDwk2Np+eEoyV4Z0= github.com/aws/aws-sdk-go-v2/service/ssooidc v1.26.2/go.mod h1:xyFHA4zGxgYkdD73VeezHt3vSKEG9EmFnGwoKlP00u4= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3 h1:2YCmIXv3tmiItw0LlYf6v7gEHebLY45kBEnPezbUKyU= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.3/go.mod h1:u19stRyNPxGhj6dRm+Cdgu6N75qnbW7+QN0q0dsAk58= github.com/aws/aws-sdk-go-v2/service/sts v1.30.1 h1:+woJ607dllHJQtsnJLi52ycuqHMwlW+Wqm2Ppsfp4nQ= github.com/aws/aws-sdk-go-v2/service/sts v1.30.1/go.mod h1:jiNR3JqT15Dm+QWq2SRgh0x0bCNSRP2L25+CqPNpJlQ= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3 h1:wVnQ6tigGsRqSWDEEyH6lSAJ9OyFUsSnbaUWChuSGzs= +github.com/aws/aws-sdk-go-v2/service/sts v1.32.3/go.mod h1:VZa9yTFyj4o10YGsmDO4gbQJUvvhY72fhumT8W4LqsE= github.com/aws/aws-sdk-go-v2/service/vpclattice v1.12.3 h1:YwFhhnQNn2bvnJ9HNy7DEhyIf5Ze/9Qn6ad6gtByLko= github.com/aws/aws-sdk-go-v2/service/vpclattice v1.12.3/go.mod h1:wjm69e87s+O7nq0zC54dEJ7M9gLHMfr9ZJ+j5u9IV0Q= github.com/aws/smithy-go v1.13.3/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA= diff --git a/v2_migration_report/output.md b/v2_migration_report/output.md index 76e7d6b1..64fac786 100644 --- a/v2_migration_report/output.md +++ b/v2_migration_report/output.md @@ -25,7 +25,7 @@ run `go generate ./...` to refresh this report. | data-sync-location | :white_check_mark: | | data-sync-task | :white_check_mark: | | dynamodb | :white_check_mark: | -| ebs | | +| ebs | :white_check_mark: | | ec2 | | | ec2-dedicated-hosts | | | ec2-endpoint | | @@ -33,25 +33,25 @@ run `go generate ./...` to refresh this report. | ec2-placement-groups | | | ec2-subnet | | | ec2_dhcp_option | | -| ecr | | -| ecscluster | | -| ecsserv | | -| efs | | +| ecr | :white_check_mark: | +| ecscluster | :white_check_mark: | +| ecsserv | :white_check_mark: | +| efs | :white_check_mark: | | egress-only-internet-gateway | | -| eip | | -| ekscluster | | -| elastic-beanstalk | | -| elasticache | | -| elasticacheParameterGroups | | -| elasticacheSubnetGroups | | -| elb | | -| elbv2 | | +| eip | :white_check_mark: | +| ekscluster | :white_check_mark: | +| elastic-beanstalk | :white_check_mark: | +| elasticache | :white_check_mark: | +| elasticacheParameterGroups | :white_check_mark: | +| elasticacheSubnetGroups | :white_check_mark: | +| elb | :white_check_mark: | +| elbv2 | :white_check_mark: | | event-bridge | :white_check_mark: | | event-bridge-archive | :white_check_mark: | | event-bridge-rule | :white_check_mark: | | event-bridge-schedule | :white_check_mark: | | event-bridge-schedule-group | :white_check_mark: | -| guardduty | | +| guardduty | :white_check_mark: | | iam | | | iam-group | | | iam-policy | | @@ -112,7 +112,7 @@ run `go generate ./...` to refresh this report. | snap | | | snstopic | :white_check_mark: | | sqs | :white_check_mark: | -| transit-gateway | | +| transit-gateway | :white_check_mark: | | transit-gateway-attachment | :white_check_mark: | | transit-gateway-route-table | | | vpc | |