Skip to content

Commit

Permalink
r/aws_lambda_provisioned_concurrency_configuration: add `skip_destroy…
Browse files Browse the repository at this point in the history
…` argument (#31646)

* r/aws_lambda_provisioned_concurrency_configuration: add skip_destroy argument

* chore: changelog

* r/aws_lambda_provisioned_concurrency_config: versioned function skip_destroy tests
  • Loading branch information
jar-b authored Jun 1, 2023
1 parent abed243 commit 451166b
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .changelog/31646.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_lambda_provisioned_concurrency_configuration: Add `skip_destroy` argument
```
10 changes: 10 additions & 0 deletions internal/service/lambda/provisioned_concurrency_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func ResourceProvisionedConcurrencyConfig() *schema.Resource {
ForceNew: true,
ValidateFunc: validation.NoZeroValues,
},
"skip_destroy": {
Type: schema.TypeBool,
Optional: true,
Default: false,
},
},
}
}
Expand Down Expand Up @@ -147,6 +152,11 @@ func resourceProvisionedConcurrencyConfigUpdate(ctx context.Context, d *schema.R

func resourceProvisionedConcurrencyConfigDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
if v, ok := d.GetOk("skip_destroy"); ok && v.(bool) {
log.Printf("[DEBUG] Retaining Lambda Provisioned Concurrency Config %q", d.Id())
return diags
}

conn := meta.(*conns.AWSClient).LambdaConn()

functionName, qualifier, err := ProvisionedConcurrencyConfigParseID(d.Id())
Expand Down
147 changes: 120 additions & 27 deletions internal/service/lambda/provisioned_concurrency_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,20 @@ func TestAccLambdaProvisionedConcurrencyConfig_basic(t *testing.T) {
CheckDestroy: testAccCheckProvisionedConcurrencyConfigDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccProvisionedConcurrencyConfigConfig_qualifierFunctionVersion(rName),
Config: testAccProvisionedConcurrencyConfigConfig_concurrentExecutions(rName, 1),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyExistsConfig(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
resource.TestCheckResourceAttrPair(resourceName, "function_name", lambdaFunctionResourceName, "function_name"),
resource.TestCheckResourceAttr(resourceName, "provisioned_concurrent_executions", "1"),
resource.TestCheckResourceAttrPair(resourceName, "qualifier", lambdaFunctionResourceName, "version"),
resource.TestCheckResourceAttr(resourceName, "skip_destroy", "false"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"skip_destroy"},
},
},
})
Expand All @@ -65,7 +67,7 @@ func TestAccLambdaProvisionedConcurrencyConfig_Disappears_lambdaFunction(t *test
Config: testAccProvisionedConcurrencyConfigConfig_concurrentExecutions(rName, 1),
Check: resource.ComposeTestCheckFunc(
testAccCheckFunctionExists(ctx, lambdaFunctionResourceName, &function),
testAccCheckProvisionedConcurrencyExistsConfig(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
testAccCheckFunctionDisappears(ctx, &function),
),
ExpectNonEmptyPlan: true,
Expand All @@ -88,7 +90,7 @@ func TestAccLambdaProvisionedConcurrencyConfig_Disappears_lambdaProvisionedConcu
{
Config: testAccProvisionedConcurrencyConfigConfig_concurrentExecutions(rName, 1),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyExistsConfig(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
testAccCheckProvisionedConcurrencyDisappearsConfig(ctx, resourceName),
),
ExpectNonEmptyPlan: true,
Expand All @@ -115,21 +117,22 @@ func TestAccLambdaProvisionedConcurrencyConfig_provisionedConcurrentExecutions(t
{
Config: testAccProvisionedConcurrencyConfigConfig_concurrentExecutions(rName, 1),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyExistsConfig(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
resource.TestCheckResourceAttr(resourceName, "function_name", rName),
resource.TestCheckResourceAttr(resourceName, "provisioned_concurrent_executions", "1"),
resource.TestCheckResourceAttr(resourceName, "qualifier", "1"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"skip_destroy"},
},
{
Config: testAccProvisionedConcurrencyConfigConfig_concurrentExecutions(rName, 2),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyExistsConfig(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
resource.TestCheckResourceAttr(resourceName, "function_name", rName),
resource.TestCheckResourceAttr(resourceName, "provisioned_concurrent_executions", "2"),
resource.TestCheckResourceAttr(resourceName, "qualifier", "1"),
Expand All @@ -154,14 +157,63 @@ func TestAccLambdaProvisionedConcurrencyConfig_Qualifier_aliasName(t *testing.T)
{
Config: testAccProvisionedConcurrencyConfigConfig_qualifierAliasName(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyExistsConfig(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
resource.TestCheckResourceAttrPair(resourceName, "qualifier", lambdaAliasResourceName, "name"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"skip_destroy"},
},
},
})
}

func TestAccLambdaProvisionedConcurrencyConfig_skipDestroy(t *testing.T) {
ctx := acctest.Context(t)
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
filename1 := "test-fixtures/lambdapinpoint.zip"
filename2 := "test-fixtures/lambdapinpoint_modified.zip"
version1 := "1"
version2 := "2"
lambdaFunctionResourceName := "aws_lambda_function.test"
resourceName := "aws_lambda_provisioned_concurrency_config.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.LambdaEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckProvisionedConcurrencyConfigDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccProvisionedConcurrencyConfigConfig_skipDestroy(rName, filename1, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
resource.TestCheckResourceAttrPair(resourceName, "function_name", lambdaFunctionResourceName, "function_name"),
resource.TestCheckResourceAttr(resourceName, "provisioned_concurrent_executions", "1"),
resource.TestCheckResourceAttrPair(resourceName, "qualifier", lambdaFunctionResourceName, "version"),
resource.TestCheckResourceAttr(resourceName, "skip_destroy", "true"),
),
},
{
Config: testAccProvisionedConcurrencyConfigConfig_skipDestroy(rName, filename2, true),
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyConfigExists(ctx, resourceName),
testAccCheckProvisionedConcurrencyConfigExistsByName(ctx, rName, version1), // verify config on previous version still exists
resource.TestCheckResourceAttrPair(resourceName, "function_name", lambdaFunctionResourceName, "function_name"),
resource.TestCheckResourceAttr(resourceName, "provisioned_concurrent_executions", "1"),
resource.TestCheckResourceAttrPair(resourceName, "qualifier", lambdaFunctionResourceName, "version"),
resource.TestCheckResourceAttr(resourceName, "skip_destroy", "true"),
),
},
{
Config: testAccProvisionedConcurrencyConfigConfigBase_withFilename(rName, filename2), // remove the provisioned concurrency config completely
Check: resource.ComposeTestCheckFunc(
testAccCheckProvisionedConcurrencyConfigExistsByName(ctx, rName, version1),
testAccCheckProvisionedConcurrencyConfigExistsByName(ctx, rName, version2),
),
},
},
})
Expand Down Expand Up @@ -239,7 +291,7 @@ func testAccCheckProvisionedConcurrencyDisappearsConfig(ctx context.Context, res
}
}

func testAccCheckProvisionedConcurrencyExistsConfig(ctx context.Context, resourceName string) resource.TestCheckFunc {
func testAccCheckProvisionedConcurrencyConfigExists(ctx context.Context, resourceName string) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[resourceName]
if !ok {
Expand Down Expand Up @@ -277,7 +329,38 @@ func testAccCheckProvisionedConcurrencyExistsConfig(ctx context.Context, resourc
}
}

func testAccProvisionedConcurrencyConfig_base(rName string) string {
// testAccCheckProvisionedConcurrencyConfigExistsByName is a helper to verify a
// provisioned concurrency setting is in place on a specific function version.
// This variant of the test check function accepts function name and qualifer arguments
// directly to support skip_destroy checks where the provisioned concurrency configuration
// resource is removed from state, but should still exist remotely.
func testAccCheckProvisionedConcurrencyConfigExistsByName(ctx context.Context, functionName, qualifier string) resource.TestCheckFunc {
return func(s *terraform.State) error {
conn := acctest.Provider.Meta().(*conns.AWSClient).LambdaClient()
input := &lambda.GetProvisionedConcurrencyConfigInput{
FunctionName: aws.String(functionName),
Qualifier: aws.String(qualifier),
}

output, err := conn.GetProvisionedConcurrencyConfig(ctx, input)

if err != nil {
return err
}

if got, want := output.Status, types.ProvisionedConcurrencyStatusEnumReady; got != want {
return fmt.Errorf("Lambda Provisioned Concurrency Config (%s) expected status (%s), got: %s", functionName, want, got)
}

return nil
}
}

func testAccProvisionedConcurrencyConfigConfigBase(rName string) string {
return testAccProvisionedConcurrencyConfigConfigBase_withFilename(rName, "test-fixtures/lambdapinpoint.zip")
}

func testAccProvisionedConcurrencyConfigConfigBase_withFilename(rName, filename string) string {
return fmt.Sprintf(`
data "aws_partition" "current" {}
Expand Down Expand Up @@ -307,30 +390,35 @@ resource "aws_iam_role_policy_attachment" "test" {
}
resource "aws_lambda_function" "test" {
filename = "test-fixtures/lambdapinpoint.zip"
function_name = %[1]q
filename = %[2]q
role = aws_iam_role.test.arn
handler = "lambdapinpoint.handler"
publish = true
runtime = "nodejs16.x"
depends_on = [aws_iam_role_policy_attachment.test]
}
`, rName)
`, rName, filename)
}

func testAccProvisionedConcurrencyConfigConfig_concurrentExecutions(rName string, provisionedConcurrentExecutions int) string {
return testAccProvisionedConcurrencyConfig_base(rName) + fmt.Sprintf(`
return acctest.ConfigCompose(
testAccProvisionedConcurrencyConfigConfigBase(rName),
fmt.Sprintf(`
resource "aws_lambda_provisioned_concurrency_config" "test" {
function_name = aws_lambda_function.test.function_name
provisioned_concurrent_executions = %[1]d
qualifier = aws_lambda_function.test.version
}
`, provisionedConcurrentExecutions)
`, provisionedConcurrentExecutions),
)
}

func testAccProvisionedConcurrencyConfigConfig_qualifierAliasName(rName string) string {
return testAccProvisionedConcurrencyConfig_base(rName) + `
return acctest.ConfigCompose(
testAccProvisionedConcurrencyConfigConfigBase(rName),
`
resource "aws_lambda_alias" "test" {
function_name = aws_lambda_function.test.function_name
function_version = aws_lambda_function.test.version
Expand All @@ -342,15 +430,20 @@ resource "aws_lambda_provisioned_concurrency_config" "test" {
provisioned_concurrent_executions = 1
qualifier = aws_lambda_alias.test.name
}
`
`,
)
}

func testAccProvisionedConcurrencyConfigConfig_qualifierFunctionVersion(rName string) string {
return testAccProvisionedConcurrencyConfig_base(rName) + `
func testAccProvisionedConcurrencyConfigConfig_skipDestroy(rName, filename string, skipDestroy bool) string {
return acctest.ConfigCompose(
testAccProvisionedConcurrencyConfigConfigBase_withFilename(rName, filename),
fmt.Sprintf(`
resource "aws_lambda_provisioned_concurrency_config" "test" {
function_name = aws_lambda_function.test.function_name
provisioned_concurrent_executions = 1
qualifier = aws_lambda_function.test.version
skip_destroy = %[1]t
}
`
`, skipDestroy))
}
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ description: |-

Manages a Lambda Provisioned Concurrency Configuration.

~> **NOTE:** Setting `skip_destroy` to `true` means that the AWS Provider will _not_ destroy a provisioned concurrency configuration, even when running `terraform destroy`. The configuration is thus an intentional dangling resource that is _not_ managed by Terraform and may incur extra expense in your AWS account.

## Example Usage

### Alias Name
Expand Down Expand Up @@ -40,6 +42,10 @@ The following arguments are required:
* `provisioned_concurrent_executions` - (Required) Amount of capacity to allocate. Must be greater than or equal to `1`.
* `qualifier` - (Required) Lambda Function version or Lambda Alias name.

The following arguments are optional:

* `skip_destroy` - (Optional) Whether to retain the provisoned concurrency configuration upon destruction. Defaults to `false`. If set to `true`, the resource in simply removed from state instead.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:
Expand Down

0 comments on commit 451166b

Please sign in to comment.