Skip to content

Commit

Permalink
change port EC2 to awsSDKv2 #770 (#808)
Browse files Browse the repository at this point in the history
  • Loading branch information
wakeful authored Dec 17, 2024
1 parent 562dc1f commit d434a9c
Show file tree
Hide file tree
Showing 7 changed files with 296 additions and 275 deletions.
62 changes: 31 additions & 31 deletions aws/resources/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ package resources

import (
"context"
"github.com/gruntwork-io/cloud-nuke/util"
"time"

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/gruntwork-io/cloud-nuke/logging"
"github.com/gruntwork-io/cloud-nuke/util"
"github.com/gruntwork-io/go-commons/errors"
)

Expand All @@ -18,9 +20,9 @@ func (ei *EC2Instances) filterOutProtectedInstances(output *ec2.DescribeInstance
for _, instance := range reservation.Instances {
instanceID := *instance.InstanceId

attr, err := ei.Client.DescribeInstanceAttributeWithContext(ei.Context, &ec2.DescribeInstanceAttributeInput{
Attribute: awsgo.String("disableApiTermination"),
InstanceId: awsgo.String(instanceID),
attr, err := ei.Client.DescribeInstanceAttribute(ei.Context, &ec2.DescribeInstanceAttributeInput{
Attribute: types.InstanceAttributeNameDisableApiTermination,
InstanceId: aws.String(instanceID),
})
if err != nil {
return nil, errors.WithStackTrace(err)
Expand All @@ -36,20 +38,20 @@ func (ei *EC2Instances) filterOutProtectedInstances(output *ec2.DescribeInstance
}

// Returns a formatted string of EC2 instance ids
func (ei *EC2Instances) getAll(c context.Context, configObj config.Config) ([]*string, error) {
func (ei *EC2Instances) getAll(ctx context.Context, configObj config.Config) ([]*string, error) {
params := &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{
Filters: []types.Filter{
{
Name: awsgo.String("instance-state-name"),
Values: []*string{
awsgo.String("running"), awsgo.String("pending"),
awsgo.String("stopped"), awsgo.String("stopping"),
Name: aws.String("instance-state-name"),
Values: []string{
"running", "pending",
"stopped", "stopping",
},
},
},
}

output, err := ei.Client.DescribeInstancesWithContext(ei.Context, params)
output, err := ei.Client.DescribeInstances(ctx, params)
if err != nil {
return nil, errors.WithStackTrace(err)
}
Expand All @@ -62,7 +64,7 @@ func (ei *EC2Instances) getAll(c context.Context, configObj config.Config) ([]*s
return instanceIds, nil
}

func shouldIncludeInstanceId(instance *ec2.Instance, protected bool, configObj config.Config) bool {
func shouldIncludeInstanceId(instance types.Instance, protected bool, configObj config.Config) bool {
if protected {
return false
}
Expand All @@ -73,7 +75,7 @@ func shouldIncludeInstanceId(instance *ec2.Instance, protected bool, configObj c
return configObj.EC2.ShouldInclude(config.ResourceValue{
Name: instanceName,
Time: instance.LaunchTime,
Tags: util.ConvertEC2TagsToMap(instance.Tags),
Tags: util.ConvertTypesTagsToMap(instance.Tags),
})
}

Expand All @@ -82,12 +84,12 @@ func (ei *EC2Instances) releaseEIPs(instanceIds []*string) error {

for _, instanceID := range instanceIds {
// Get the Elastic IPs associated with the EC2 instances
output, err := ei.Client.DescribeAddressesWithContext(ei.Context, &ec2.DescribeAddressesInput{
Filters: []*ec2.Filter{
output, err := ei.Client.DescribeAddresses(ei.Context, &ec2.DescribeAddressesInput{
Filters: []types.Filter{
{
Name: awsgo.String("instance-id"),
Values: []*string{
instanceID,
Name: aws.String("instance-id"),
Values: []string{
aws.ToString(instanceID),
},
},
},
Expand All @@ -108,7 +110,7 @@ func (ei *EC2Instances) releaseEIPs(instanceIds []*string) error {
continue
}

_, err := ei.Client.ReleaseAddressWithContext(ei.Context, &ec2.ReleaseAddressInput{
_, err := ei.Client.ReleaseAddress(ei.Context, &ec2.ReleaseAddressInput{
AllocationId: address.AllocationId,
})

Expand Down Expand Up @@ -142,26 +144,24 @@ func (ei *EC2Instances) nukeAll(instanceIds []*string) error {
logging.Debugf("Terminating all EC2 instances in region %s", ei.Region)

params := &ec2.TerminateInstancesInput{
InstanceIds: instanceIds,
InstanceIds: aws.ToStringSlice(instanceIds),
}

_, err = ei.Client.TerminateInstancesWithContext(ei.Context, params)
_, err = ei.Client.TerminateInstances(ei.Context, params)
if err != nil {
logging.Debugf("[Failed] %s", err)
return errors.WithStackTrace(err)
}

err = ei.Client.WaitUntilInstanceTerminatedWithContext(ei.Context, &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{
waiter := ec2.NewInstanceTerminatedWaiter(ei.Client)
err = waiter.Wait(ei.Context, &ec2.DescribeInstancesInput{
Filters: []types.Filter{
{
Name: awsgo.String("instance-id"),
Values: instanceIds,
Name: aws.String("instance-id"),
Values: aws.ToStringSlice(instanceIds),
},
},
})
for _, instanceID := range instanceIds {
logging.Debugf("Terminated EC2 Instance: %s", *instanceID)
}
}, 15*time.Minute)

if err != nil {
logging.Debugf("[Failed] %s", err)
Expand Down
114 changes: 66 additions & 48 deletions aws/resources/ec2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,46 @@ import (
"time"

"github.com/aws/aws-sdk-go-v2/aws"
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/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/logging"
"github.com/stretchr/testify/require"
)

type mockedEC2Instances struct {
ec2iface.EC2API
EC2InstancesAPI
DescribeInstancesOutput ec2.DescribeInstancesOutput
DescribeInstanceAttributeOutput map[string]ec2.DescribeInstanceAttributeOutput
TerminateInstancesOutput ec2.TerminateInstancesOutput
DescribeAddressesOutput ec2.DescribeAddressesOutput
ReleaseAddressOutput ec2.ReleaseAddressOutput
}

func (m mockedEC2Instances) DescribeInstancesWithContext(
_ awsgo.Context, _ *ec2.DescribeInstancesInput, _ ...request.Option) (*ec2.DescribeInstancesOutput, error) {
func (m mockedEC2Instances) DescribeInstances(_ context.Context, _ *ec2.DescribeInstancesInput, _ ...func(*ec2.Options)) (*ec2.DescribeInstancesOutput, error) {
return &m.DescribeInstancesOutput, nil
}

func (m mockedEC2Instances) DescribeInstanceAttributeWithContext(
_ awsgo.Context, input *ec2.DescribeInstanceAttributeInput, _ ...request.Option) (*ec2.DescribeInstanceAttributeOutput, error) {
id := input.InstanceId
func (m mockedEC2Instances) DescribeInstanceAttribute(_ context.Context, params *ec2.DescribeInstanceAttributeInput, _ ...func(*ec2.Options)) (*ec2.DescribeInstanceAttributeOutput, error) {
id := params.InstanceId
output := m.DescribeInstanceAttributeOutput[*id]

return &output, nil
}

func (m mockedEC2Instances) TerminateInstancesWithContext(
_ awsgo.Context, _ *ec2.TerminateInstancesInput, _ ...request.Option) (*ec2.TerminateInstancesOutput, error) {
func (m mockedEC2Instances) TerminateInstances(_ context.Context, _ *ec2.TerminateInstancesInput, _ ...func(*ec2.Options)) (*ec2.TerminateInstancesOutput, error) {
return &m.TerminateInstancesOutput, nil
}

func (m mockedEC2Instances) WaitUntilInstanceTerminatedWithContext(
_ awsgo.Context, _ *ec2.DescribeInstancesInput, _ ...request.WaiterOption) error {
return nil
}
func (m mockedEC2Instances) DescribeAddressesWithContext(_ awsgo.Context, _ *ec2.DescribeAddressesInput, _ ...request.Option) (*ec2.DescribeAddressesOutput, error) {
func (m mockedEC2Instances) DescribeAddresses(_ context.Context, _ *ec2.DescribeAddressesInput, _ ...func(*ec2.Options)) (*ec2.DescribeAddressesOutput, error) {
return &m.DescribeAddressesOutput, nil
}
func (m mockedEC2Instances) ReleaseAddressWithContext(_ awsgo.Context, _ *ec2.ReleaseAddressInput, _ ...request.Option) (*ec2.ReleaseAddressOutput, error) {

func (m mockedEC2Instances) ReleaseAddress(ctx context.Context, params *ec2.ReleaseAddressInput, optFns ...func(*ec2.Options)) (*ec2.ReleaseAddressOutput, error) {
return &m.ReleaseAddressOutput, nil
}

func TestEc2Instances_GetAll(t *testing.T) {

t.Parallel()

testId1 := "testId1"
testId2 := "testId2"
testName1 := "testName1"
Expand All @@ -66,42 +55,42 @@ func TestEc2Instances_GetAll(t *testing.T) {
ei := EC2Instances{
Client: mockedEC2Instances{
DescribeInstancesOutput: ec2.DescribeInstancesOutput{
Reservations: []*ec2.Reservation{
Reservations: []types.Reservation{
{
Instances: []*ec2.Instance{
Instances: []types.Instance{
{
InstanceId: awsgo.String(testId1),
Tags: []*ec2.Tag{
InstanceId: aws.String(testId1),
Tags: []types.Tag{
{
Key: awsgo.String("Name"),
Value: awsgo.String(testName1),
Key: aws.String("Name"),
Value: aws.String(testName1),
},
},
LaunchTime: awsgo.Time(now),
LaunchTime: aws.Time(now),
},
{
InstanceId: awsgo.String(testId2),
Tags: []*ec2.Tag{
InstanceId: aws.String(testId2),
Tags: []types.Tag{
{
Key: awsgo.String("Name"),
Value: awsgo.String(testName2),
Key: aws.String("Name"),
Value: aws.String(testName2),
},
},
LaunchTime: awsgo.Time(now.Add(1)),
LaunchTime: aws.Time(now.Add(1)),
},
},
},
},
},
DescribeInstanceAttributeOutput: map[string]ec2.DescribeInstanceAttributeOutput{
testId1: {
DisableApiTermination: &ec2.AttributeBooleanValue{
Value: awsgo.Bool(false),
DisableApiTermination: &types.AttributeBooleanValue{
Value: aws.Bool(false),
},
},
testId2: {
DisableApiTermination: &ec2.AttributeBooleanValue{
Value: awsgo.Bool(false),
DisableApiTermination: &types.AttributeBooleanValue{
Value: aws.Bool(false),
},
},
},
Expand Down Expand Up @@ -139,43 +128,72 @@ func TestEc2Instances_GetAll(t *testing.T) {
EC2: tc.configObj,
})
require.NoError(t, err)
require.Equal(t, tc.expected, awsgo.StringValueSlice(names))
require.Equal(t, tc.expected, aws.ToStringSlice(names))
})
}
}

func TestEc2Instances_NukeAll(t *testing.T) {

t.Parallel()

ei := EC2Instances{
BaseAwsResource: BaseAwsResource{
Context: context.Background(),
},
Client: mockedEC2Instances{
TerminateInstancesOutput: ec2.TerminateInstancesOutput{},
DescribeInstancesOutput: ec2.DescribeInstancesOutput{
Reservations: []types.Reservation{
{
Instances: []types.Instance{
{
InstanceId: aws.String("testId1"),
State: &types.InstanceState{
Name: types.InstanceStateNameTerminated,
},
},
},
},
},
},
},
}

err := ei.nukeAll([]*string{awsgo.String("testId1")})
err := ei.nukeAll([]*string{aws.String("testId1")})
require.NoError(t, err)
}

func TestEc2InstancesWithEIP_NukeAll(t *testing.T) {
logging.ParseLogLevel("debug")
t.Parallel()

ei := EC2Instances{
BaseAwsResource: BaseAwsResource{
Context: context.Background(),
},
Client: mockedEC2Instances{
DescribeInstancesOutput: ec2.DescribeInstancesOutput{
Reservations: []types.Reservation{
{
Instances: []types.Instance{
{
InstanceId: aws.String("testId1"),
State: &types.InstanceState{
Name: types.InstanceStateNameTerminated,
},
},
},
},
},
},
TerminateInstancesOutput: ec2.TerminateInstancesOutput{},
DescribeAddressesOutput: ec2.DescribeAddressesOutput{
Addresses: []*ec2.Address{
Addresses: []types.Address{
{
AllocationId: awsgo.String("alloc-test-id1"),
InstanceId: awsgo.String("testId1"),
AllocationId: aws.String("alloc-test-id1"),
InstanceId: aws.String("testId1"),
},
},
},
},
}

err := ei.nukeAll([]*string{awsgo.String("testId1")})
err := ei.nukeAll([]*string{aws.String("testId1")})
require.NoError(t, err)
}
Loading

0 comments on commit d434a9c

Please sign in to comment.