Skip to content

Commit d7be6e0

Browse files
authored
Disable EC2 Instance Stop Protection (rebuy-de#986)
* First pass at implementing the logic to disable EC2 instance stop protection * Improved comments and formatting of EC2 Instance termination/stop protection code. Also fixed the feature flag name.
1 parent 375dcef commit d7be6e0

File tree

2 files changed

+49
-17
lines changed

2 files changed

+49
-17
lines changed

pkg/config/config.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,9 @@ type Nuke struct {
3737
}
3838

3939
type FeatureFlags struct {
40-
DisableDeletionProtection DisableDeletionProtection `yaml:"disable-deletion-protection"`
41-
ForceDeleteLightsailAddOns bool `yaml:"force-delete-lightsail-addons"`
40+
DisableDeletionProtection DisableDeletionProtection `yaml:"disable-deletion-protection"`
41+
DisableEC2InstanceStopProtection bool `yaml:"disable-ec2-instance-stop-protection"`
42+
ForceDeleteLightsailAddOns bool `yaml:"force-delete-lightsail-addons"`
4243
}
4344

4445
type DisableDeletionProtection struct {

resources/ec2-instances.go

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -72,28 +72,59 @@ func (i *EC2Instance) Remove() error {
7272

7373
_, err := i.svc.TerminateInstances(params)
7474
if err != nil {
75-
if i.featureFlags.DisableDeletionProtection.EC2Instance {
76-
awsErr, ok := err.(awserr.Error)
77-
if ok && awsErr.Code() == "OperationNotPermitted" &&
78-
awsErr.Message() == "The instance '"+*i.instance.InstanceId+"' may not be terminated. "+
79-
"Modify its 'disableApiTermination' instance attribute and try again." {
80-
err = i.DisableProtection()
81-
if err != nil {
82-
return err
83-
}
84-
_, err := i.svc.TerminateInstances(params)
85-
if err != nil {
86-
return err
87-
}
88-
return nil
75+
awsErr, ok := err.(awserr.Error)
76+
// Check for Termination Protection, disable it, and try termination again.
77+
if ok && awsErr.Code() == "OperationNotPermitted" &&
78+
awsErr.Message() == "The instance '"+*i.instance.InstanceId+"' may not be "+
79+
"terminated. Modify its 'disableApiTermination' instance attribute and "+
80+
"try again." && i.featureFlags.DisableDeletionProtection.EC2Instance {
81+
termErr := i.DisableTerminationProtection()
82+
if termErr != nil {
83+
return termErr
84+
}
85+
_, err = i.svc.TerminateInstances(params)
86+
// If we still get an error, we'll check for type and let the next routine
87+
// handle it.
88+
if err != nil {
89+
awsErr, ok = err.(awserr.Error)
8990
}
9091
}
92+
93+
// Check for Stop Protection, disable it, and try termination again.
94+
if ok && awsErr.Code() == "OperationNotPermitted" &&
95+
awsErr.Message() == "The instance '"+*i.instance.InstanceId+"' may not be "+
96+
"terminated. Modify its 'disableApiStop' instance attribute and try "+
97+
"again." && i.featureFlags.DisableEC2InstanceStopProtection {
98+
stopErr := i.DisableStopProtection()
99+
if stopErr != nil {
100+
return stopErr
101+
}
102+
_, err = i.svc.TerminateInstances(params)
103+
}
104+
105+
// If we still have an error at this point, we'll return it.
106+
if err != nil {
107+
return err
108+
}
109+
}
110+
return nil
111+
}
112+
113+
func (i *EC2Instance) DisableStopProtection() error {
114+
params := &ec2.ModifyInstanceAttributeInput{
115+
InstanceId: i.instance.InstanceId,
116+
DisableApiStop: &ec2.AttributeBooleanValue{
117+
Value: aws.Bool(false),
118+
},
119+
}
120+
_, err := i.svc.ModifyInstanceAttribute(params)
121+
if err != nil {
91122
return err
92123
}
93124
return nil
94125
}
95126

96-
func (i *EC2Instance) DisableProtection() error {
127+
func (i *EC2Instance) DisableTerminationProtection() error {
97128
params := &ec2.ModifyInstanceAttributeInput{
98129
InstanceId: i.instance.InstanceId,
99130
DisableApiTermination: &ec2.AttributeBooleanValue{

0 commit comments

Comments
 (0)