Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor EC2 instance, clusters, and services #550

Merged
merged 1 commit into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 10 additions & 19 deletions aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,7 @@ func GetAllResources(targetRegions []string, excludeAfter time.Time, resourceTyp
}
if IsNukeable(ec2Instances.ResourceName(), resourceTypes) {
start := time.Now()
instanceIds, err := getAllEc2Instances(cloudNukeSession, region, excludeAfter, configObj)
instanceIds, err := ec2Instances.getAll(configObj)
if err != nil {
ge := report.GeneralError{
Error: err,
Expand Down Expand Up @@ -819,29 +819,20 @@ func GetAllResources(targetRegions []string, excludeAfter time.Time, resourceTyp
}
if IsNukeable(ecsServices.ResourceName(), resourceTypes) {
start := time.Now()
clusterArns, err := getAllEcsClusters(cloudNukeSession)

serviceArns, err := ecsServices.getAll(configObj)
if err != nil {
ge := report.GeneralError{
Error: err,
Description: "Unable to retrieve ECS clusters",
ResourceType: ecsServices.ResourceName(),
}
report.RecordError(ge)
}
if len(clusterArns) > 0 {
serviceArns, serviceClusterMap, err := getAllEcsServices(cloudNukeSession, clusterArns, excludeAfter, configObj)
if err != nil {
return nil, errors.WithStackTrace(err)
}
ecsServices.Services = awsgo.StringValueSlice(serviceArns)
ecsServices.ServiceClusterMap = serviceClusterMap
resourcesInRegion.Resources = append(resourcesInRegion.Resources, ecsServices)
return nil, errors.WithStackTrace(err)
}

ecsServices.Services = awsgo.StringValueSlice(serviceArns)
resourcesInRegion.Resources = append(resourcesInRegion.Resources, ecsServices)

telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Done Listing ECS Services",
}, map[string]interface{}{
"region": region,
"recordCount": len(clusterArns),
"recordCount": len(serviceArns),
"actionTime": time.Since(start).Seconds(),
})
}
Expand All @@ -852,7 +843,7 @@ func GetAllResources(targetRegions []string, excludeAfter time.Time, resourceTyp
}
if IsNukeable(ecsClusters.ResourceName(), resourceTypes) {
start := time.Now()
ecsClusterArns, err := getAllEcsClustersOlderThan(cloudNukeSession, excludeAfter, configObj)
ecsClusterArns, err := ecsClusters.getAll(configObj)
if err != nil {
ge := report.GeneralError{
Error: err,
Expand Down
54 changes: 20 additions & 34 deletions aws/ec2.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (

awsgo "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"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/gruntwork-io/cloud-nuke/config"
Expand All @@ -21,20 +20,21 @@ import (
)

// returns only instance Ids of unprotected ec2 instances
func filterOutProtectedInstances(svc *ec2.EC2, output *ec2.DescribeInstancesOutput, excludeAfter time.Time, configObj config.Config) ([]*string, error) {
func (ei EC2Instances) filterOutProtectedInstances(output *ec2.DescribeInstancesOutput, configObj config.Config) ([]*string, error) {
var filteredIds []*string
for _, reservation := range output.Reservations {
for _, instance := range reservation.Instances {
instanceID := *instance.InstanceId

attr, err := svc.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
attr, err := ei.Client.DescribeInstanceAttribute(&ec2.DescribeInstanceAttributeInput{
Attribute: awsgo.String("disableApiTermination"),
InstanceId: awsgo.String(instanceID),
})
if err != nil {
return nil, errors.WithStackTrace(err)
}
if shouldIncludeInstanceId(instance, excludeAfter, *attr.DisableApiTermination.Value, configObj) {

if shouldIncludeInstanceId(instance, *attr.DisableApiTermination.Value, configObj) {
filteredIds = append(filteredIds, &instanceID)
}
}
Expand All @@ -44,9 +44,7 @@ func filterOutProtectedInstances(svc *ec2.EC2, output *ec2.DescribeInstancesOutp
}

// Returns a formatted string of EC2 instance ids
func getAllEc2Instances(session *session.Session, region string, excludeAfter time.Time, configObj config.Config) ([]*string, error) {
svc := ec2.New(session)

func (ei EC2Instances) getAll(configObj config.Config) ([]*string, error) {
params := &ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{
{
Expand All @@ -59,70 +57,58 @@ func getAllEc2Instances(session *session.Session, region string, excludeAfter ti
},
}

output, err := svc.DescribeInstances(params)
output, err := ei.Client.DescribeInstances(params)
if err != nil {
return nil, errors.WithStackTrace(err)
}

instanceIds, err := filterOutProtectedInstances(svc, output, excludeAfter, configObj)
instanceIds, err := ei.filterOutProtectedInstances(output, configObj)
if err != nil {
return nil, errors.WithStackTrace(err)
}

return instanceIds, nil
}

func shouldIncludeInstanceId(instance *ec2.Instance, excludeAfter time.Time, protected bool, configObj config.Config) bool {
if instance == nil {
return false
}

if excludeAfter.Before(*instance.LaunchTime) {
return false
}

func shouldIncludeInstanceId(instance *ec2.Instance, protected bool, configObj config.Config) bool {
if protected {
return false
}

// If Name is unset, GetEC2ResourceNameTagValue returns error and zero value string
// Ignore this error and pass empty string to config.ShouldInclude
instanceName := GetEC2ResourceNameTagValue(instance.Tags)

return config.ShouldInclude(
*instanceName,
configObj.EC2.IncludeRule.NamesRegExp,
configObj.EC2.ExcludeRule.NamesRegExp,
)
return configObj.EC2.ShouldInclude(config.ResourceValue{
Name: instanceName,
Time: instance.LaunchTime,
})
}

// Deletes all non protected EC2 instances
func nukeAllEc2Instances(session *session.Session, instanceIds []*string) error {
svc := ec2.New(session)

func (ei EC2Instances) nukeAll(instanceIds []*string) error {
if len(instanceIds) == 0 {
logging.Logger.Debugf("No EC2 instances to nuke in region %s", *session.Config.Region)
logging.Logger.Debugf("No EC2 instances to nuke in region %s", ei.Region)
return nil
}

logging.Logger.Debugf("Terminating all EC2 instances in region %s", *session.Config.Region)
logging.Logger.Debugf("Terminating all EC2 instances in region %s", ei.Region)

params := &ec2.TerminateInstancesInput{
InstanceIds: instanceIds,
}

_, err := svc.TerminateInstances(params)
_, err := ei.Client.TerminateInstances(params)
if err != nil {
logging.Logger.Debugf("[Failed] %s", err)
telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Error Nuking EC2 Instance",
}, map[string]interface{}{
"region": *session.Config.Region,
"region": ei.Region,
})
return errors.WithStackTrace(err)
}

err = svc.WaitUntilInstanceTerminated(&ec2.DescribeInstancesInput{
err = ei.Client.WaitUntilInstanceTerminated(&ec2.DescribeInstancesInput{
Filters: []*ec2.Filter{
{
Name: awsgo.String("instance-id"),
Expand All @@ -140,12 +126,12 @@ func nukeAllEc2Instances(session *session.Session, instanceIds []*string) error
telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Error Nuking EC2 Instance",
}, map[string]interface{}{
"region": *session.Config.Region,
"region": ei.Region,
})
return errors.WithStackTrace(err)
}

logging.Logger.Debugf("[OK] %d instance(s) terminated in %s", len(instanceIds), *session.Config.Region)
logging.Logger.Debugf("[OK] %d instance(s) terminated in %s", len(instanceIds), ei.Region)
return nil
}

Expand Down
Loading