Skip to content

Commit

Permalink
Add additional checks and debug message for nil exception checks (#809)
Browse files Browse the repository at this point in the history
Co-authored-by: James Kwon <96548424+hongil0316@users.noreply.github.com>
  • Loading branch information
james03160927 and james03160927 authored Dec 17, 2024
1 parent 2b83d10 commit 562dc1f
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 99 deletions.
40 changes: 24 additions & 16 deletions aws/resources/ec2_network_acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,18 @@ func (nacl *NetworkACL) nuke(id *string) error {
// Thus, to remove the association, it requires another network ACL ID. Here, we check the default network ACL of the VPC to which the current network ACL is attached,
// and then associate that network ACL with the association.
func (nacl *NetworkACL) nukeAssociatedSubnets(id string) error {
logging.Debugf("[nukeAssociatedSubnets] Start describing network ACL: %s", id)

resp, err := nacl.Client.DescribeNetworkAcls(nacl.Context, &ec2.DescribeNetworkAclsInput{
NetworkAclIds: []string{id},
})
if err != nil {
logging.Debugf("[Network ACL] Failed to describe network ACL: %s", err)
logging.Debugf("[nukeAssociatedSubnets] Failed to describe network ACL: %s", err)
return err
}

if len(resp.NetworkAcls) == 0 {
logging.Debugf("[Network ACL] Nothing found: %s", id)
logging.Debugf("[nukeAssociatedSubnets] No network ACL found for ID: %s", id)
return nil
}

Expand All @@ -115,43 +117,50 @@ func (nacl *NetworkACL) nukeAssociatedSubnets(id string) error {
vpcID = networkAcl.VpcId
)

// Get the default nacl association id
// Get the default network ACL association ID
logging.Debugf("[nukeAssociatedSubnets] Describing default network ACL for VPC: %s", *vpcID)
networkACLs, err := nacl.Client.DescribeNetworkAcls(
nacl.Context,
&ec2.DescribeNetworkAclsInput{
Filters: []types.Filter{
{
Name: awsgo.String("vpc-id"),
Values: []string{*vpcID},
}, {
},
{
Name: awsgo.String("default"),
Values: []string{"true"},
},
},
},
)
if err != nil {
logging.Debugf("[Network ACL] Failed to describe network ACL: %s", err)
logging.Debugf("[nukeAssociatedSubnets] Failed to describe default network ACL: %s", err)
return err
}

if len(networkACLs.NetworkAcls) == 0 {
logging.Debugf("[Network ACL] Nothing found to check the default association: %s", id)
logging.Debugf("[nukeAssociatedSubnets] No default network ACL found for VPC: %s", *vpcID)
return nil
}

defaultNetworkAclID := networkACLs.NetworkAcls[0].NetworkAclId
logging.Debugf("[nukeAssociatedSubnets] Default network ACL ID: %s", *defaultNetworkAclID)

var associations []*types.NetworkAclAssociation
for i := range networkAcl.Associations {
associations = append(associations, &networkAcl.Associations[i])
}

// Replacing network ACL associations
logging.Debugf("[nukeAssociatedSubnets] Replacing network ACL associations for ID: %s", *defaultNetworkAclID)
err = replaceNetworkAclAssociation(nacl.Client, defaultNetworkAclID, associations)
if err != nil {
logging.Debugf("Failed to replace network ACL associations: %s", *defaultNetworkAclID)
logging.Debugf("[nukeAssociatedSubnets] Failed to replace network ACL associations: %s", *defaultNetworkAclID)
return errors.WithStackTrace(err)
}

logging.Debugf("[nukeAssociatedSubnets] Successfully replaced network ACL associations for ID: %s", *defaultNetworkAclID)
return nil
}

Expand Down Expand Up @@ -191,36 +200,35 @@ func (nacl *NetworkACL) nukeAll(identifiers []*string) error {
}

func replaceNetworkAclAssociation(client NetworkACLAPI, networkAclId *string, associations []*types.NetworkAclAssociation) error {
logging.Debugf("Start replacing network ACL associations: %s", *networkAclId)
logging.Debugf("[replaceNetworkAclAssociation] Start replacing network ACL associations: %s", *networkAclId)

for _, association := range associations {
logging.Debugf("Found %d network ACL associations to replace", len(associations))
logging.Debugf("[replaceNetworkAclAssociation] Found %d network ACL associations to replace", len(associations))

_, err := client.ReplaceNetworkAclAssociation(context.TODO(), &ec2.ReplaceNetworkAclAssociationInput{
AssociationId: association.NetworkAclAssociationId,
NetworkAclId: networkAclId,
})
if err != nil {
logging.Debugf("Failed to replace network ACL association: %s to default", *association.NetworkAclAssociationId)
logging.Debugf("[replaceNetworkAclAssociation] Failed to replace network ACL association: %s", *association.NetworkAclAssociationId)
return errors.WithStackTrace(err)
}
logging.Debugf("Successfully replaced network ACL association: %s to default",
*association.NetworkAclAssociationId)
logging.Debugf("[replaceNetworkAclAssociation] Successfully replaced network ACL association: %s", *association.NetworkAclAssociationId)
}
logging.Debugf("Successfully replaced network ACL associations: %s", *networkAclId)
logging.Debugf("[replaceNetworkAclAssociation] Successfully replaced network ACL associations: %s", *networkAclId)
return nil
}

func nukeNetworkAcl(client NetworkACLAPI, id *string) error {
logging.Debugf("Deleting network Acl %s", *id)
logging.Debugf("[nukeNetworkAcl] Deleting network ACL %s", *id)

if _, err := client.DeleteNetworkAcl(context.TODO(), &ec2.DeleteNetworkAclInput{
NetworkAclId: id,
}); err != nil {
logging.Debugf("An error happened while nuking NACL %s, error %v", *id, err)
logging.Debugf("[nukeNetworkAcl] An error occurred while deleting network ACL %s: %v", *id, err)
return err
}
logging.Debugf("[Ok] network acl deleted successfully %s", *id)
logging.Debugf("[nukeNetworkAcl] Successfully deleted network ACL %s", *id)

return nil
}
91 changes: 62 additions & 29 deletions aws/resources/ec2_network_interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,98 +89,131 @@ func (ni *NetworkInterface) nuke(id *string) error {
}

func (ni *NetworkInterface) detachNetworkInterface(id *string) error {
logging.Debugf("Detaching network interface %s from instances ", awsgo.ToString(id))
if id == nil || awsgo.ToString(id) == "" {
logging.Debugf("[detachNetworkInterface] Network interface ID is nil or empty, skipping detachment process")
return nil
}

logging.Debugf("[detachNetworkInterface] Detaching network interface %s from instances", awsgo.ToString(id))

// Describe the network interface to get details
output, err := ni.Client.DescribeNetworkInterfaces(ni.Context, &ec2.DescribeNetworkInterfacesInput{
NetworkInterfaceIds: []string{*id},
NetworkInterfaceIds: []string{awsgo.ToString(id)},
})
if err != nil {
logging.Debugf("[Failed] Error describing network interface %s: %s", awsgo.ToString(id), err)
logging.Debugf("[detachNetworkInterface] Failed to describe network interface %s: %v", awsgo.ToString(id), err)
return errors.WithStackTrace(err)
}

for _, networkInterface := range output.NetworkInterfaces {

// check there has some attachments
if networkInterface.Attachment == nil {
// Check if the network interface has an attachment
if networkInterface.Attachment == nil || networkInterface.Attachment.InstanceId == nil {
logging.Debugf("[detachNetworkInterface] No attachment found for network interface %s, skipping", awsgo.ToString(id))
continue
}

// nuking the attached instance
// this will also remove the network interface
if err := ni.nukeInstance(networkInterface.Attachment.InstanceId); err != nil {
logging.Debugf("[Failed] Error nuking the attached instance %s on network interface %s %s", awsgo.ToString(networkInterface.Attachment.InstanceId), awsgo.ToString(id), err)
instanceID := awsgo.ToString(networkInterface.Attachment.InstanceId)
logging.Debugf("[detachNetworkInterface] Found attached instance %s for network interface %s", instanceID, awsgo.ToString(id))

// Nuke the attached instance
err := ni.nukeInstance(networkInterface.Attachment.InstanceId)
if err != nil {
logging.Debugf("[detachNetworkInterface] Failed to nuke instance %s attached to network interface %s: %v", instanceID, awsgo.ToString(id), err)
return errors.WithStackTrace(err)
}
}

logging.Debugf("[OK] successfully detached network interface associated on instances")
logging.Debugf("[detachNetworkInterface] Successfully nuked instance %s and detached network interface %s", instanceID, awsgo.ToString(id))
}

logging.Debugf("[detachNetworkInterface] Successfully detached network interface %s from instances", awsgo.ToString(id))
return nil
}

func (ni *NetworkInterface) releaseEIPs(instance *string) error {
logging.Debugf("Releasing Elastic IP address(s) associated on instance %s", awsgo.ToString(instance))
// get the elastic ip's associated with the EC2's
if instance == nil || awsgo.ToString(instance) == "" {
logging.Debugf("[releaseEIPs] Instance ID is nil or empty, skipping Elastic IP release process")
return nil
}

logging.Debugf("[releaseEIPs] Releasing Elastic IP address(es) associated with instance %s", awsgo.ToString(instance))

// Fetch the Elastic IPs associated with the instance
output, err := ni.Client.DescribeAddresses(ni.Context, &ec2.DescribeAddressesInput{
Filters: []types.Filter{
{
Name: awsgo.String("instance-id"),
Values: []string{
*instance,
awsgo.ToString(instance),
},
},
},
})
if err != nil {
logging.Debugf("[releaseEIPs] Failed to describe addresses for instance %s: %v", awsgo.ToString(instance), err)
return err
}

// Release each Elastic IP
for _, address := range output.Addresses {
if _, err := ni.Client.ReleaseAddress(ni.Context, &ec2.ReleaseAddressInput{
if address.AllocationId == nil {
logging.Debugf("[releaseEIPs] Skipping address with nil Allocation ID for instance %s", awsgo.ToString(instance))
continue
}

_, err := ni.Client.ReleaseAddress(ni.Context, &ec2.ReleaseAddressInput{
AllocationId: address.AllocationId,
}); err != nil {
logging.Debugf("An error happened while releasing the elastic ip address %s, error %v", awsgo.ToString(address.AllocationId), err)
})
if err != nil {
logging.Debugf("[releaseEIPs] Failed to release Elastic IP address %s for instance %s: %v",
awsgo.ToString(address.AllocationId), awsgo.ToString(instance), err)
continue
}

logging.Debugf("Released Elastic IP address %s from instance %s", awsgo.ToString(address.AllocationId), awsgo.ToString(instance))
logging.Debugf("[releaseEIPs] Successfully released Elastic IP address %s from instance %s",
awsgo.ToString(address.AllocationId), awsgo.ToString(instance))
}

logging.Debugf("[OK] successfully released Elastic IP address(s) associated on instances")

logging.Debugf("[releaseEIPs] Successfully completed Elastic IP release process for instance %s", awsgo.ToString(instance))
return nil
}

func (ni *NetworkInterface) nukeInstance(id *string) error {
if id == nil || awsgo.ToString(id) == "" {
logging.Debugf("[nukeInstance] Instance ID is nil or empty, skipping termination process")
return nil
}

instanceID := awsgo.ToString(id)
logging.Debugf("[nukeInstance] Starting to nuke instance %s", instanceID)

// Release the elastic IPs attached to the instance before nuking
if err := ni.releaseEIPs(id); err != nil {
logging.Debugf("[Failed EIP release] %s", err)
logging.Debugf("[nukeInstance] Failed to release Elastic IPs for instance %s: %v", instanceID, err)
return errors.WithStackTrace(err)
}

// Terminate the instance
_, err := ni.Client.TerminateInstances(ni.Context, &ec2.TerminateInstancesInput{
InstanceIds: []string{*id},
InstanceIds: []string{instanceID},
})
if err != nil {
logging.Debugf("[Failed] EC2 termination %s", err)
logging.Debugf("[nukeInstance] Failed to terminate instance %s: %v", instanceID, err)
return errors.WithStackTrace(err)
}

logging.Debugf("[Instance Termination] waiting to terminate instance %s", awsgo.ToString(id))
logging.Debugf("[nukeInstance] Waiting for instance %s to terminate", instanceID)

// Use the NewInstanceTerminatedWaiter
// Use the NewInstanceTerminatedWaiter to wait until the instance is terminated
waiter := ec2.NewInstanceTerminatedWaiter(ni.Client)
err = waiter.Wait(ni.Context, &ec2.DescribeInstancesInput{
InstanceIds: []string{*id},
InstanceIds: []string{instanceID},
}, 5*time.Minute)
if err != nil {
logging.Debugf("[Instance Termination Waiting] Failed to terminate instance %s : %s", *id, err)
logging.Debugf("[nukeInstance] Instance termination waiting failed for instance %s: %v", instanceID, err)
return errors.WithStackTrace(err)
}

logging.Debugf("[OK] successfully nuked instance %v", awsgo.ToString(id))
logging.Debugf("[nukeInstance] Successfully nuked instance %s", instanceID)
return nil
}

Expand Down
Loading

0 comments on commit 562dc1f

Please sign in to comment.