func deleteLingeringLambdaENIs(conn *ec2.EC2, d *schema.ResourceData) error { lambdaENIs := getLambdaENIs(conn, d) for i := 0; i < len(lambdaENIs); i++ { params := &ec2.DetachNetworkInterfaceInput{ AttachmentId: lambdaENIs[i].Attachment.AttachmentId, } _, err := conn.DetachNetworkInterface(params) if err != nil { return err } } all_enis_detached := false for all_enis_detached == false { all_enis_detached = true lambdaENIs = getLambdaENIs(conn, d) for i := 0; i < len(lambdaENIs); i++ { if *lambdaENIs[i].Status != "available" { all_enis_detached = false } } time.Sleep(time.Second) } for i := 0; i < len(lambdaENIs); i++ { params := &ec2.DeleteNetworkInterfaceInput{ NetworkInterfaceId: lambdaENIs[i].NetworkInterfaceId, } _, err := conn.DeleteNetworkInterface(params) if err != nil { return err } } return nil }
// The AWS Lambda service creates ENIs behind the scenes and keeps these around for a while // which would prevent SGs attached to such ENIs from being destroyed func deleteLingeringLambdaENIs(conn *ec2.EC2, d *schema.ResourceData) error { // Here we carefully find the offenders params := &ec2.DescribeNetworkInterfacesInput{ Filters: []*ec2.Filter{ &ec2.Filter{ Name: aws.String("group-id"), Values: []*string{aws.String(d.Id())}, }, &ec2.Filter{ Name: aws.String("description"), Values: []*string{aws.String("AWS Lambda VPC ENI: *")}, }, &ec2.Filter{ Name: aws.String("requester-id"), Values: []*string{aws.String("*:awslambda_*")}, }, }, } networkInterfaceResp, err := conn.DescribeNetworkInterfaces(params) if err != nil { return err } // Then we detach and finally delete those v := networkInterfaceResp.NetworkInterfaces for _, eni := range v { if eni.Attachment != nil { detachNetworkInterfaceParams := &ec2.DetachNetworkInterfaceInput{ AttachmentId: eni.Attachment.AttachmentId, } _, detachNetworkInterfaceErr := conn.DetachNetworkInterface(detachNetworkInterfaceParams) if detachNetworkInterfaceErr != nil { return detachNetworkInterfaceErr } log.Printf("[DEBUG] Waiting for ENI (%s) to become detached", *eni.NetworkInterfaceId) stateConf := &resource.StateChangeConf{ Pending: []string{"true"}, Target: []string{"false"}, Refresh: networkInterfaceAttachedRefreshFunc(conn, *eni.NetworkInterfaceId), Timeout: 10 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { return fmt.Errorf( "Error waiting for ENI (%s) to become detached: %s", *eni.NetworkInterfaceId, err) } } deleteNetworkInterfaceParams := &ec2.DeleteNetworkInterfaceInput{ NetworkInterfaceId: eni.NetworkInterfaceId, } _, deleteNetworkInterfaceErr := conn.DeleteNetworkInterface(deleteNetworkInterfaceParams) if deleteNetworkInterfaceErr != nil { return deleteNetworkInterfaceErr } } return nil }