/
ebs.go
131 lines (115 loc) · 4.01 KB
/
ebs.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
package resources
import (
"context"
"github.com/gruntwork-io/cloud-nuke/telemetry"
"github.com/gruntwork-io/cloud-nuke/util"
commonTelemetry "github.com/gruntwork-io/go-commons/telemetry"
"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/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 EBS volume ids
func (ev *EBSVolumes) getAll(c context.Context, configObj config.Config) ([]*string, error) {
// 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 := ev.Client.DescribeVolumes(&ec2.DescribeVolumesInput{
Filters: []*ec2.Filter{&statusFilter},
})
if err != nil {
return nil, errors.WithStackTrace(err)
}
var volumeIds []*string
for _, volume := range result.Volumes {
if shouldIncludeEBSVolume(volume, configObj) {
volumeIds = append(volumeIds, volume.VolumeId)
}
}
return volumeIds, nil
}
func shouldIncludeEBSVolume(volume *ec2.Volume, configObj config.Config) bool {
name := ""
for _, tag := range volume.Tags {
if tag != nil && aws.StringValue(tag.Key) == "Name" {
name = aws.StringValue(tag.Value)
}
}
return configObj.EBSVolume.ShouldInclude(config.ResourceValue{
Name: &name,
Time: volume.CreateTime,
Tags: util.ConvertEC2TagsToMap(volume.Tags),
})
}
// Deletes all EBS Volumes
func (ev *EBSVolumes) nukeAll(volumeIds []*string) error {
if len(volumeIds) == 0 {
logging.Debugf("No EBS volumes to nuke in region %s", ev.Region)
return nil
}
logging.Debugf("Deleting all EBS volumes in region %s", ev.Region)
var deletedVolumeIDs []*string
for _, volumeID := range volumeIds {
params := &ec2.DeleteVolumeInput{
VolumeId: volumeID,
}
_, err := ev.Client.DeleteVolume(params)
// Record status of this resource
e := report.Entry{
Identifier: aws.StringValue(volumeID),
ResourceType: "EBS Volume",
Error: err,
}
report.Record(e)
if err != nil {
if awsErr, isAwsErr := err.(awserr.Error); isAwsErr && awsErr.Code() == "VolumeInUse" {
telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Error Nuking EBS Volume",
}, map[string]interface{}{
"region": ev.Region,
"reason": "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" {
telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Error Nuking EBS Volume",
}, map[string]interface{}{
"region": ev.Region,
"reason": "InvalidVolume.NotFound",
})
logging.Debugf("EBS volume %s has already been deleted", *volumeID)
} else {
telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Error Nuking EBS Volume",
}, map[string]interface{}{
"region": ev.Region,
})
logging.Debugf("[Failed] %s", err)
}
} else {
deletedVolumeIDs = append(deletedVolumeIDs, volumeID)
logging.Debugf("Deleted EBS Volume: %s", *volumeID)
}
}
if len(deletedVolumeIDs) > 0 {
err := ev.Client.WaitUntilVolumeDeleted(&ec2.DescribeVolumesInput{
VolumeIds: deletedVolumeIDs,
})
if err != nil {
logging.Debugf("[Failed] %s", err)
telemetry.TrackEvent(commonTelemetry.EventContext{
EventName: "Error Nuking EBS Volume",
}, map[string]interface{}{
"region": ev.Region,
})
return errors.WithStackTrace(err)
}
}
logging.Debugf("[OK] %d EBS volumes(s) terminated in %s", len(deletedVolumeIDs), ev.Region)
return nil
}