Skip to content

Commit

Permalink
Refactor EC2 instance, clusters, and services (#550)
Browse files Browse the repository at this point in the history
  • Loading branch information
james03160927 authored Aug 10, 2023
1 parent 03cf5df commit e502102
Show file tree
Hide file tree
Showing 13 changed files with 440 additions and 1,698 deletions.
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

0 comments on commit e502102

Please sign in to comment.