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

r/aws_lambda_function: re-implement replace_security_groups_on_destroy #37624

Merged
merged 1 commit into from
May 23, 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
3 changes: 3 additions & 0 deletions .changelog/37624.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_lambda_function: Remove `replace_security_group_on_destroy` and `replacement_security_group_ids` deprecations, re-implement with alternate workflow
```
13 changes: 13 additions & 0 deletions internal/service/ec2/findv2.go
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,19 @@ func findSecurityGroupsV2(ctx context.Context, conn *ec2.Client, input *ec2.Desc
return output, nil
}

// FindSecurityGroupByNameAndVPCIDV2 looks up a security group by name, VPC ID. Returns a retry.NotFoundError if not found.
func FindSecurityGroupByNameAndVPCIDV2(ctx context.Context, conn *ec2.Client, name, vpcID string) (*awstypes.SecurityGroup, error) {
input := &ec2.DescribeSecurityGroupsInput{
Filters: newAttributeFilterListV2(
map[string]string{
"group-name": name,
"vpc-id": vpcID,
},
),
}
return findSecurityGroupV2(ctx, conn, input)
}

func findIPAMPoolAllocationsV2(ctx context.Context, conn *ec2.Client, input *ec2.GetIpamPoolAllocationsInput) ([]awstypes.IpamPoolAllocation, error) {
var output []awstypes.IpamPoolAllocation

Expand Down
72 changes: 68 additions & 4 deletions internal/service/lambda/function.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
"github.com/hashicorp/terraform-provider-aws/internal/sdkv2"
tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
Expand Down Expand Up @@ -292,14 +293,10 @@ func resourceFunction() *schema.Resource {
Computed: true,
},
"replace_security_groups_on_destroy": {
Deprecated: "AWS no longer supports this operation. This attribute now has " +
"no effect and will be removed in a future major version.",
Type: schema.TypeBool,
Optional: true,
},
"replacement_security_group_ids": {
Deprecated: "AWS no longer supports this operation. This attribute now has " +
"no effect and will be removed in a future major version.",
Type: schema.TypeSet,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
Expand Down Expand Up @@ -1045,6 +1042,12 @@ func resourceFunctionDelete(ctx context.Context, d *schema.ResourceData, meta in
return diags
}

if _, ok := d.GetOk("replace_security_groups_on_destroy"); ok {
if err := replaceSecurityGroupsOnDestroy(ctx, d, meta); err != nil {
return sdkdiag.AppendFromErr(diags, err)
}
}

log.Printf("[INFO] Deleting Lambda Function: %s", d.Id())
_, err := tfresource.RetryWhenIsAErrorMessageContains[*awstypes.InvalidParameterValueException](ctx, d.Timeout(schema.TimeoutDelete), func() (interface{}, error) {
return conn.DeleteFunction(ctx, &lambda.DeleteFunctionInput{
Expand Down Expand Up @@ -1120,6 +1123,67 @@ func findLatestFunctionVersionByName(ctx context.Context, conn *lambda.Client, n
return output, nil
}

// replaceSecurityGroupsOnDestroy sets the VPC configuration security groups
// prior to resource destruction
//
// This function is called when the replace_security_groups_on_destroy
// argument is set. If the replacement_security_group_ids attribute is set,
// those values will be used as replacements. Otherwise, the default
// security group is used.
//
// Configuring this option can decrease destroy times for the security
// groups included in the VPC configuration block during normal operation
// by freeing them from association with ENI's left behind after destruction
// of the function.
func replaceSecurityGroupsOnDestroy(ctx context.Context, d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).LambdaClient(ctx)
ec2Conn := meta.(*conns.AWSClient).EC2Client(ctx)

var sgIDs []string
var vpcID string
if v, ok := d.GetOk(names.AttrVPCConfig); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
tfMap := v.([]interface{})[0].(map[string]interface{})
sgIDs = flex.ExpandStringValueSet(tfMap[names.AttrSecurityGroupIDs].(*schema.Set))
vpcID = tfMap[names.AttrVPCID].(string)
} else { // empty VPC config, nothing to do
return nil
}

if len(sgIDs) == 0 { // no security groups, nothing to do
return nil
}

var replacementSGIDs []string
if v, ok := d.GetOk("replacement_security_group_ids"); ok {
replacementSGIDs = flex.ExpandStringValueSet(v.(*schema.Set))
} else {
defaultSG, err := tfec2.FindSecurityGroupByNameAndVPCIDV2(ctx, ec2Conn, "default", vpcID)
if err != nil || defaultSG == nil {
return fmt.Errorf("finding VPC (%s) default security group: %s", vpcID, err)
}
replacementSGIDs = []string{aws.ToString(defaultSG.GroupId)}
}

input := &lambda.UpdateFunctionConfigurationInput{
FunctionName: aws.String(d.Id()),
VpcConfig: &awstypes.VpcConfig{
SecurityGroupIds: replacementSGIDs,
},
}

if _, err := retryFunctionOp(ctx, func() (*lambda.UpdateFunctionConfigurationOutput, error) {
return conn.UpdateFunctionConfiguration(ctx, input)
}); err != nil {
return fmt.Errorf("updating Lambda Function (%s) configuration: %s", d.Id(), err)
}

if _, err := waitFunctionUpdated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil {
return fmt.Errorf("waiting for Lambda Function (%s) configuration update: %s", d.Id(), err)
}

return nil
}

func statusFunctionLastUpdateStatus(ctx context.Context, conn *lambda.Client, name string) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
output, err := findFunctionByName(ctx, conn, name)
Expand Down
8 changes: 6 additions & 2 deletions website/docs/r/lambda_function.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,12 @@ The following arguments are optional:
* `package_type` - (Optional) Lambda deployment package type. Valid values are `Zip` and `Image`. Defaults to `Zip`.
* `publish` - (Optional) Whether to publish creation/change as new Lambda Function Version. Defaults to `false`.
* `reserved_concurrent_executions` - (Optional) Amount of reserved concurrent executions for this lambda function. A value of `0` disables lambda from being triggered and `-1` removes any concurrency limitations. Defaults to Unreserved Concurrency Limits `-1`. See [Managing Concurrency][9]
* `replace_security_groups_on_destroy` - (Optional, **Deprecated**) **AWS no longer supports this operation. This attribute now has no effect and will be removed in a future major version.** Whether to replace the security groups on associated lambda network interfaces upon destruction. Removing these security groups from orphaned network interfaces can speed up security group deletion times by avoiding a dependency on AWS's internal cleanup operations. By default, the ENI security groups will be replaced with the `default` security group in the function's VPC. Set the `replacement_security_group_ids` attribute to use a custom list of security groups for replacement.
* `replacement_security_group_ids` - (Optional, **Deprecated**) List of security group IDs to assign to orphaned Lambda function network interfaces upon destruction. `replace_security_groups_on_destroy` must be set to `true` to use this attribute.
* `replace_security_groups_on_destroy` - (Optional) Whether to replace the security groups on the function's VPC configuration prior to destruction.
Removing these security group associations prior to function destruction can speed up security group deletion times of AWS's internal cleanup operations.
By default, the security groups will be replaced with the `default` security group in the function's configured VPC.
Set the `replacement_security_group_ids` attribute to use a custom list of security groups for replacement.
* `replacement_security_group_ids` - (Optional) List of security group IDs to assign to the function's VPC configuration prior to destruction.
`replace_security_groups_on_destroy` must be set to `true` to use this attribute.
* `runtime` - (Optional) Identifier of the function's runtime. See [Runtimes][6] for valid values.
* `s3_bucket` - (Optional) S3 bucket location containing the function's deployment package. This bucket must reside in the same AWS region where you are creating the Lambda function. Exactly one of `filename`, `image_uri`, or `s3_bucket` must be specified. When `s3_bucket` is set, `s3_key` is required.
* `s3_key` - (Optional) S3 key of an object containing the function's deployment package. When `s3_bucket` is set, `s3_key` is required.
Expand Down
Loading