Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional checks and debug message for nil exception checks #809

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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