From dae789d4f16556d840428cc520bbc7e1ed27eac9 Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Mon, 11 Nov 2019 21:26:17 -0500 Subject: [PATCH] resource/aws_lambda_function: Support waiting for State on CreateFunction and LastUpdatedStatus on UpdateFunctionConfiguration Output from acceptance testing in AWS Commercial (us-west-2): ``` --- PASS: TestAccAWSLambdaFunction_basic (369.24s) --- PASS: TestAccAWSLambdaFunction_concurrency (250.87s) --- PASS: TestAccAWSLambdaFunction_concurrencyCycle (470.65s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfig (515.49s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfigUpdated (509.55s) --- PASS: TestAccAWSLambdaFunction_EmptyVpcConfig (167.42s) --- PASS: TestAccAWSLambdaFunction_encryptedEnvVariables (323.02s) --- PASS: TestAccAWSLambdaFunction_envVariables (140.79s) --- PASS: TestAccAWSLambdaFunction_expectFilenameAndS3Attributes (21.51s) --- PASS: TestAccAWSLambdaFunction_Layers (65.21s) --- PASS: TestAccAWSLambdaFunction_LayersUpdate (553.66s) --- PASS: TestAccAWSLambdaFunction_localUpdate (270.54s) --- PASS: TestAccAWSLambdaFunction_localUpdate_nameOnly (241.10s) --- PASS: TestAccAWSLambdaFunction_nilDeadLetterConfig (165.93s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java8 (166.81s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs10x (173.61s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs810 (298.36s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_noRuntime (0.91s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_provided (272.34s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python27 (438.99s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python36 (480.28s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python37 (467.07s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby25 (473.34s) --- PASS: TestAccAWSLambdaFunction_s3 (42.83s) --- PASS: TestAccAWSLambdaFunction_s3Update_basic (61.96s) --- PASS: TestAccAWSLambdaFunction_s3Update_unversioned (64.14s) --- PASS: TestAccAWSLambdaFunction_tags (406.96s) --- PASS: TestAccAWSLambdaFunction_tracingConfig (458.91s) --- PASS: TestAccAWSLambdaFunction_updateRuntime (549.47s) --- PASS: TestAccAWSLambdaFunction_versioned (58.40s) --- PASS: TestAccAWSLambdaFunction_versionedUpdate (614.81s) --- PASS: TestAccAWSLambdaFunction_VPC (1806.38s) --- PASS: TestAccAWSLambdaFunction_VPC_withInvocation (1627.71s) --- PASS: TestAccAWSLambdaFunction_VPCUpdate (1820.07s) ``` Output from acceptance testing in AWS Commercial (us-east-2): ``` --- PASS: TestAccAWSLambdaFunction_basic (38.55s) --- PASS: TestAccAWSLambdaFunction_concurrency (42.00s) --- PASS: TestAccAWSLambdaFunction_concurrencyCycle (47.59s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfig (48.46s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfigUpdated (56.49s) --- PASS: TestAccAWSLambdaFunction_EmptyVpcConfig (29.17s) --- PASS: TestAccAWSLambdaFunction_encryptedEnvVariables (59.43s) --- PASS: TestAccAWSLambdaFunction_envVariables (68.92s) --- PASS: TestAccAWSLambdaFunction_expectFilenameAndS3Attributes (12.06s) --- PASS: TestAccAWSLambdaFunction_Layers (30.71s) --- PASS: TestAccAWSLambdaFunction_LayersUpdate (57.00s) --- PASS: TestAccAWSLambdaFunction_localUpdate (37.25s) --- PASS: TestAccAWSLambdaFunction_localUpdate_nameOnly (35.00s) --- PASS: TestAccAWSLambdaFunction_nilDeadLetterConfig (10.17s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java8 (34.43s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs10x (33.29s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs810 (29.69s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_noRuntime (0.59s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_provided (27.31s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python27 (35.12s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python36 (26.88s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python37 (32.30s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby25 (25.78s) --- PASS: TestAccAWSLambdaFunction_s3 (29.69s) --- PASS: TestAccAWSLambdaFunction_s3Update_basic (35.45s) --- PASS: TestAccAWSLambdaFunction_s3Update_unversioned (35.65s) --- PASS: TestAccAWSLambdaFunction_tags (39.01s) --- PASS: TestAccAWSLambdaFunction_tracingConfig (47.01s) --- PASS: TestAccAWSLambdaFunction_updateRuntime (41.10s) --- PASS: TestAccAWSLambdaFunction_versioned (31.86s) --- PASS: TestAccAWSLambdaFunction_versionedUpdate (40.01s) --- PASS: TestAccAWSLambdaFunction_VPC (1331.10s) --- PASS: TestAccAWSLambdaFunction_VPC_withInvocation (1356.30s) --- PASS: TestAccAWSLambdaFunction_VpcConfig_ProperIamDependencies (1289.59s) --- PASS: TestAccAWSLambdaFunction_VPCUpdate (1455.46s) ``` Output from acceptance testing in AWS GovCloud (US) (us-gov-west-1): ``` --- PASS: TestAccAWSLambdaFunction_basic (96.45s) --- PASS: TestAccAWSLambdaFunction_concurrency (128.26s) --- PASS: TestAccAWSLambdaFunction_concurrencyCycle (153.75s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfig (127.93s) --- PASS: TestAccAWSLambdaFunction_DeadLetterConfigUpdated (133.99s) --- PASS: TestAccAWSLambdaFunction_EmptyVpcConfig (102.99s) --- PASS: TestAccAWSLambdaFunction_encryptedEnvVariables (173.12s) --- PASS: TestAccAWSLambdaFunction_envVariables (188.44s) --- PASS: TestAccAWSLambdaFunction_expectFilenameAndS3Attributes (24.13s) --- PASS: TestAccAWSLambdaFunction_Layers (116.48s) --- PASS: TestAccAWSLambdaFunction_LayersUpdate (152.43s) --- PASS: TestAccAWSLambdaFunction_localUpdate (155.31s) --- PASS: TestAccAWSLambdaFunction_localUpdate_nameOnly (137.67s) --- PASS: TestAccAWSLambdaFunction_nilDeadLetterConfig (66.45s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_java8 (49.98s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs10x (83.39s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_NodeJs810 (115.81s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_noRuntime (1.48s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_provided (89.89s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python27 (57.00s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python36 (44.05s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_python37 (63.82s) --- PASS: TestAccAWSLambdaFunction_runtimeValidation_ruby25 (70.84s) --- PASS: TestAccAWSLambdaFunction_s3 (41.56s) --- PASS: TestAccAWSLambdaFunction_s3Update_basic (70.50s) --- PASS: TestAccAWSLambdaFunction_s3Update_unversioned (66.96s) --- PASS: TestAccAWSLambdaFunction_tags (115.43s) --- PASS: TestAccAWSLambdaFunction_updateRuntime (130.79s) --- PASS: TestAccAWSLambdaFunction_versioned (119.31s) --- PASS: TestAccAWSLambdaFunction_versionedUpdate (169.21s) --- PASS: TestAccAWSLambdaFunction_VPC (160.10s) --- PASS: TestAccAWSLambdaFunction_VPC_withInvocation (165.84s) --- PASS: TestAccAWSLambdaFunction_VpcConfig_ProperIamDependencies (153.32s) --- PASS: TestAccAWSLambdaFunction_VPCRemoval (157.20s) --- PASS: TestAccAWSLambdaFunction_VPCUpdate (177.42s) ``` --- aws/resource_aws_lambda_function.go | 88 +++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/aws/resource_aws_lambda_function.go b/aws/resource_aws_lambda_function.go index d73adb30396f..aca09c9db08b 100644 --- a/aws/resource_aws_lambda_function.go +++ b/aws/resource_aws_lambda_function.go @@ -447,6 +447,10 @@ func resourceAwsLambdaFunctionCreate(d *schema.ResourceData, meta interface{}) e d.SetId(d.Get("function_name").(string)) + if err := waitForLambdaFunctionCreation(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return fmt.Errorf("error waiting for Lambda Function (%s) creation: %s", d.Id(), err) + } + if reservedConcurrentExecutions >= 0 { log.Printf("[DEBUG] Setting Concurrency to %d for the Lambda Function %s", reservedConcurrentExecutions, functionName) @@ -819,6 +823,10 @@ func resourceAwsLambdaFunctionUpdate(d *schema.ResourceData, meta interface{}) e } } + if err := waitForLambdaFunctionUpdate(conn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil { + return fmt.Errorf("error waiting for Lambda Function (%s) update: %s", d.Id(), err) + } + d.SetPartial("description") d.SetPartial("handler") d.SetPartial("memory_size") @@ -933,3 +941,83 @@ func lambdaFunctionInvokeArn(functionArn string, meta interface{}) string { Resource: fmt.Sprintf("path/2015-03-31/functions/%s/invocations", functionArn), }.String() } + +func refreshLambdaFunctionLastUpdateStatus(conn *lambda.Lambda, functionName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &lambda.GetFunctionInput{ + FunctionName: aws.String(functionName), + } + + output, err := conn.GetFunction(input) + + if err != nil { + return nil, "", err + } + + if output == nil || output.Configuration == nil { + return nil, "", nil + } + + lastUpdateStatus := aws.StringValue(output.Configuration.LastUpdateStatus) + + if lastUpdateStatus == lambda.LastUpdateStatusFailed { + return output.Configuration, lastUpdateStatus, fmt.Errorf("%s: %s", aws.StringValue(output.Configuration.LastUpdateStatusReasonCode), aws.StringValue(output.Configuration.LastUpdateStatusReason)) + } + + return output.Configuration, lastUpdateStatus, nil + } +} + +func refreshLambdaFunctionState(conn *lambda.Lambda, functionName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + input := &lambda.GetFunctionInput{ + FunctionName: aws.String(functionName), + } + + output, err := conn.GetFunction(input) + + if err != nil { + return nil, "", err + } + + if output == nil || output.Configuration == nil { + return nil, "", nil + } + + state := aws.StringValue(output.Configuration.State) + + if state == lambda.StateFailed { + return output.Configuration, state, fmt.Errorf("%s: %s", aws.StringValue(output.Configuration.StateReasonCode), aws.StringValue(output.Configuration.StateReason)) + } + + return output.Configuration, state, nil + } +} + +func waitForLambdaFunctionCreation(conn *lambda.Lambda, functionName string, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{lambda.StatePending}, + Target: []string{lambda.StateActive}, + Refresh: refreshLambdaFunctionState(conn, functionName), + Timeout: timeout, + Delay: 5 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +} + +func waitForLambdaFunctionUpdate(conn *lambda.Lambda, functionName string, timeout time.Duration) error { + stateConf := &resource.StateChangeConf{ + Pending: []string{lambda.LastUpdateStatusInProgress}, + Target: []string{lambda.LastUpdateStatusSuccessful}, + Refresh: refreshLambdaFunctionLastUpdateStatus(conn, functionName), + Timeout: timeout, + Delay: 5 * time.Second, + } + + _, err := stateConf.WaitForState() + + return err +}