Skip to content

Commit

Permalink
chore(CORE-659): Improve filtering for EBS Volumes and Snapshots (#439)
Browse files Browse the repository at this point in the history
* Add filter to only list available and creating ebs volumes

* Add filter to only list completed ebs snapshots that are not managed by AWS backup
  • Loading branch information
MoonMoon1919 authored Apr 11, 2023
1 parent f9dd63d commit 0ece707
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 6 deletions.
13 changes: 11 additions & 2 deletions aws/ebs.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package aws

import (
"time"

"github.com/gruntwork-io/cloud-nuke/telemetry"
commonTelemetry "github.com/gruntwork-io/go-commons/telemetry"
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
Expand All @@ -19,7 +20,15 @@ import (
func getAllEbsVolumes(session *session.Session, region string, excludeAfter time.Time, configObj config.Config) ([]*string, error) {
svc := ec2.New(session)

result, err := svc.DescribeVolumes(&ec2.DescribeVolumesInput{})
// Available statuses: (creating | available | in-use | deleting | deleted | error).
// 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 := svc.DescribeVolumes(&ec2.DescribeVolumesInput{
Filters: []*ec2.Filter{&statusFilter},
})
if err != nil {
return nil, errors.WithStackTrace(err)
}
Expand Down
24 changes: 22 additions & 2 deletions aws/ebs_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package aws

import (
"github.com/gruntwork-io/cloud-nuke/telemetry"
"regexp"
"testing"
"time"

"github.com/gruntwork-io/cloud-nuke/telemetry"

"github.com/aws/aws-sdk-go/aws"
awsgo "github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
Expand Down Expand Up @@ -85,6 +86,24 @@ func findEBSVolumesByNameTag(t *testing.T, session *session.Session, name string
return volumeIds
}

func findallEBSVolumesByStatus(t *testing.T, session *session.Session, status string) ([]*string, error) {
statusFilter := ec2.Filter{Name: aws.String("status"), Values: aws.StringSlice([]string{status})}

output, err := ec2.New(session).DescribeVolumes(&ec2.DescribeVolumesInput{
Filters: []*ec2.Filter{&statusFilter},
})
if err != nil {
return nil, err
}

var volumeIds []*string
for _, volume := range output.Volumes {
volumeIds = append(volumeIds, volume.VolumeId)
}

return volumeIds, nil
}

func TestListEBSVolumes(t *testing.T) {
telemetry.InitTelemetry("cloud-nuke", "", "")
t.Parallel()
Expand Down Expand Up @@ -250,8 +269,9 @@ func TestNukeEBSVolumesInUse(t *testing.T) {
assert.Fail(t, errors.WithStackTrace(err).Error())
}

volumeIds, err = getAllEbsVolumes(session, region, time.Now().Add(1*time.Hour), config.Config{})
volumeIds, err = findallEBSVolumesByStatus(t, session, "in-use")
if err != nil {
assert.Fail(t, errors.WithStackTrace(err).Error())
assert.Fail(t, "Unable to fetch list of EBS Volumes")
}

Expand Down
28 changes: 26 additions & 2 deletions aws/snapshot.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package aws

import (
"time"

"github.com/gruntwork-io/cloud-nuke/telemetry"
commonTelemetry "github.com/gruntwork-io/go-commons/telemetry"
"time"

"github.com/aws/aws-sdk-go/aws"
awsgo "github.com/aws/aws-sdk-go/aws"
Expand All @@ -18,8 +19,15 @@ import (
func getAllSnapshots(session *session.Session, region string, excludeAfter time.Time) ([]*string, error) {
svc := ec2.New(session)

// status - The status of the snapshot (pending | completed | error).
// Since the output of this function is used to delete the returned snapshots
// We only want to list EBS Snapshots with a status of "completed"
// Since that is the only status that is eligible for deletion
status_filter := ec2.Filter{Name: awsgo.String("status"), Values: aws.StringSlice([]string{"completed", "error"})}

params := &ec2.DescribeSnapshotsInput{
OwnerIds: []*string{awsgo.String("self")},
Filters: []*ec2.Filter{&status_filter},
}

output, err := svc.DescribeSnapshots(params)
Expand All @@ -29,14 +37,30 @@ func getAllSnapshots(session *session.Session, region string, excludeAfter time.

var snapshotIds []*string
for _, snapshot := range output.Snapshots {
if excludeAfter.After(*snapshot.StartTime) {
if excludeAfter.After(*snapshot.StartTime) && !SnapshotHasAWSBackupTag(snapshot.Tags) {
snapshotIds = append(snapshotIds, snapshot.SnapshotId)
}
}

return snapshotIds, nil
}

// Check if the image has an AWS Backup tag
// Resources created by AWS Backup are listed as owned by self, but are actually
// AWS managed resources and cannot be deleted here.
func SnapshotHasAWSBackupTag(tags []*ec2.Tag) bool {
t := make(map[string]string)

for _, v := range tags {
t[awsgo.StringValue(v.Key)] = awsgo.StringValue(v.Value)
}

if _, ok := t["aws:backup:source-resource"]; ok {
return true
}
return false
}

// Deletes all Snapshots
func nukeAllSnapshots(session *session.Session, snapshotIds []*string) error {
svc := ec2.New(session)
Expand Down

0 comments on commit 0ece707

Please sign in to comment.