From 6c490f1cad4269bb81ae545dce5b584e5fa15d0c Mon Sep 17 00:00:00 2001 From: Stefan Sundin Date: Fri, 7 Sep 2018 14:01:26 -0700 Subject: [PATCH 1/2] Remove default qualifier from d/aws_lambda_function. --- aws/data_source_aws_lambda_function.go | 1 - aws/data_source_aws_lambda_function_test.go | 1 - 2 files changed, 2 deletions(-) diff --git a/aws/data_source_aws_lambda_function.go b/aws/data_source_aws_lambda_function.go index 392a0e4442b..899e3bcda6f 100644 --- a/aws/data_source_aws_lambda_function.go +++ b/aws/data_source_aws_lambda_function.go @@ -16,7 +16,6 @@ func dataSourceAwsLambdaFunction() *schema.Resource { "qualifier": { Type: schema.TypeString, Optional: true, - Default: "$LATEST", }, "description": { Type: schema.TypeString, diff --git a/aws/data_source_aws_lambda_function_test.go b/aws/data_source_aws_lambda_function_test.go index 0d59e35d76f..c52f5d3de85 100644 --- a/aws/data_source_aws_lambda_function_test.go +++ b/aws/data_source_aws_lambda_function_test.go @@ -31,7 +31,6 @@ func TestAccDataSourceAWSLambdaFunction_basic(t *testing.T) { resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "invoke_arn"), resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "function_name", funcName), resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "description", funcName), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "qualifier", "$LATEST"), resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "handler", "exports.example"), resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "memory_size", "128"), resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "runtime", "nodejs4.3"), From ba9e4dedcf1b1eeb68207021d7c521aed9bc171c Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Sat, 23 Feb 2019 00:42:51 -0500 Subject: [PATCH 2/2] data-source/aws_lambda_function: Implement standalone Read function and refactor testing to check data source state values against the resource state values References: * https://github.com/terraform-providers/terraform-provider-aws/pull/5812 * https://github.com/hashicorp/terraform/issues/10810#issuecomment-466533814 * https://github.com/terraform-providers/terraform-provider-aws/issues/6966 Previously, the `aws_lambda_function` data source was utilizing the Read function from the `aws_lambda_function` resource. This legacy practice has longterm maintenance issues with missing schema and documentation updates. Here we implement a fresh new Read function for the data source that includes the following changes: * Properly error when Lambda Function is not found * Always return the `arn` attribute as unqualified (e.g. without a qualifier or version suffix) * Always return the `qualified_arn` attribute as qualified (e.g. with the qualifier or version suffix) * Always return the `tags` attribute The acceptance testing changes modernize and simplify the testing: * Utilize `resource.TestCheckResourceAttrPair()` where possible to ensure data source state values match appropriate resource state values * Consolidate random naming to single variable * Only provision VPC resources in VPC specific test Output from acceptance testing: ``` --- PASS: TestAccDataSourceAWSLambdaFunction_version (20.89s) --- PASS: TestAccDataSourceAWSLambdaFunction_environment (22.75s) --- PASS: TestAccDataSourceAWSLambdaFunction_alias (23.68s) --- PASS: TestAccDataSourceAWSLambdaFunction_basic (23.76s) --- PASS: TestAccDataSourceAWSLambdaFunction_layers (28.82s) --- PASS: TestAccDataSourceAWSLambdaFunction_vpc (36.48s) ``` --- aws/data_source_aws_lambda_function.go | 113 +++++- aws/data_source_aws_lambda_function_test.go | 363 +++++++++---------- website/docs/d/lambda_function.html.markdown | 8 +- 3 files changed, 288 insertions(+), 196 deletions(-) diff --git a/aws/data_source_aws_lambda_function.go b/aws/data_source_aws_lambda_function.go index ed7ba5d9977..dbd49a854fc 100644 --- a/aws/data_source_aws_lambda_function.go +++ b/aws/data_source_aws_lambda_function.go @@ -1,6 +1,12 @@ package aws import ( + "fmt" + "log" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lambda" "github.com/hashicorp/terraform/helper/schema" ) @@ -151,11 +157,114 @@ func dataSourceAwsLambdaFunction() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "tags": tagsSchemaComputed(), }, } } func dataSourceAwsLambdaFunctionRead(d *schema.ResourceData, meta interface{}) error { - d.SetId(d.Get("function_name").(string)) - return resourceAwsLambdaFunctionRead(d, meta) + conn := meta.(*AWSClient).lambdaconn + functionName := d.Get("function_name").(string) + + input := &lambda.GetFunctionInput{ + FunctionName: aws.String(functionName), + } + + if v, ok := d.GetOk("qualifier"); ok { + input.Qualifier = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Getting Lambda Function: %s", input) + output, err := conn.GetFunction(input) + + if err != nil { + return fmt.Errorf("error getting Lambda Function (%s): %s", functionName, err) + } + + if output == nil { + return fmt.Errorf("error getting Lambda Function (%s): empty response", functionName) + } + + function := output.Configuration + + functionARN := aws.StringValue(function.FunctionArn) + qualifierSuffix := fmt.Sprintf(":%s", d.Get("qualifier").(string)) + versionSuffix := fmt.Sprintf(":%s", aws.StringValue(function.Version)) + + qualifiedARN := functionARN + if !strings.HasSuffix(functionARN, qualifierSuffix) && !strings.HasSuffix(functionARN, versionSuffix) { + qualifiedARN = functionARN + versionSuffix + } + + unqualifiedARN := strings.TrimSuffix(functionARN, qualifierSuffix) + + d.Set("arn", unqualifiedARN) + + deadLetterConfig := []interface{}{} + if function.DeadLetterConfig != nil { + deadLetterConfig = []interface{}{ + map[string]interface{}{ + "target_arn": aws.StringValue(function.DeadLetterConfig.TargetArn), + }, + } + } + if err := d.Set("dead_letter_config", deadLetterConfig); err != nil { + return fmt.Errorf("error setting dead_letter_config: %s", err) + } + + d.Set("description", function.Description) + + if err := d.Set("environment", flattenLambdaEnvironment(function.Environment)); err != nil { + return fmt.Errorf("error setting environment: %s", err) + } + + d.Set("handler", function.Handler) + d.Set("invoke_arn", lambdaFunctionInvokeArn(aws.StringValue(function.FunctionArn), meta)) + d.Set("kms_key_arn", function.KMSKeyArn) + d.Set("last_modified", function.LastModified) + + if err := d.Set("layers", flattenLambdaLayers(function.Layers)); err != nil { + return fmt.Errorf("Error setting layers for Lambda Function (%s): %s", d.Id(), err) + } + + d.Set("memory_size", function.MemorySize) + d.Set("qualified_arn", qualifiedARN) + + reservedConcurrentExecutions := int64(-1) + if output.Concurrency != nil { + reservedConcurrentExecutions = aws.Int64Value(output.Concurrency.ReservedConcurrentExecutions) + } + d.Set("reserved_concurrent_executions", reservedConcurrentExecutions) + + d.Set("role", function.Role) + d.Set("runtime", function.Runtime) + d.Set("source_code_hash", function.CodeSha256) + d.Set("source_code_size", function.CodeSize) + + if err := d.Set("tags", tagsToMapGeneric(output.Tags)); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + tracingConfig := []map[string]interface{}{ + { + "mode": lambda.TracingModePassThrough, + }, + } + if function.TracingConfig != nil { + tracingConfig[0]["mode"] = aws.StringValue(function.TracingConfig.Mode) + } + if err := d.Set("tracing_config", tracingConfig); err != nil { + return fmt.Errorf("error setting tracing_config: %s", tracingConfig) + } + + d.Set("timeout", function.Timeout) + d.Set("version", function.Version) + + if err := d.Set("vpc_config", flattenLambdaVpcConfigResponse(function.VpcConfig)); err != nil { + return fmt.Errorf("error setting vpc_config: %s", err) + } + + d.SetId(aws.StringValue(function.FunctionName)) + + return nil } diff --git a/aws/data_source_aws_lambda_function_test.go b/aws/data_source_aws_lambda_function_test.go index 0c598d41807..cad19dd3be3 100644 --- a/aws/data_source_aws_lambda_function_test.go +++ b/aws/data_source_aws_lambda_function_test.go @@ -9,37 +9,36 @@ import ( ) func TestAccDataSourceAWSLambdaFunction_basic(t *testing.T) { - rString := acctest.RandString(7) - roleName := fmt.Sprintf("tf-acctest-d-lambda-function-basic-role-%s", rString) - policyName := fmt.Sprintf("tf-acctest-d-lambda-function-basic-policy-%s", rString) - sgName := fmt.Sprintf("tf-acctest-d-lambda-function-basic-sg-%s", rString) - funcName := fmt.Sprintf("tf-acctest-d-lambda-function-basic-func-%s", rString) + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_lambda_function.test" + resourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAWSLambdaFunctionConfigBasic(roleName, policyName, sgName, funcName), + Config: testAccDataSourceAWSLambdaFunctionConfigBasic(rName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"), - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "role"), - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "source_code_hash"), - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "source_code_size"), - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "last_modified"), - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "qualified_arn"), - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "invoke_arn"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "function_name", funcName), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "description", funcName), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "handler", "exports.example"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "memory_size", "128"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "runtime", "nodejs8.10"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "timeout", "3"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "version", "$LATEST"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "reserved_concurrent_executions", "0"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "dead_letter_config.#", "0"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "tracing_config.#", "1"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "tracing_config.0.mode", "PassThrough"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "dead_letter_config.#", resourceName, "dead_letter_config.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"), + resource.TestCheckResourceAttrPair(dataSourceName, "function_name", resourceName, "function_name"), + resource.TestCheckResourceAttrPair(dataSourceName, "handler", resourceName, "handler"), + resource.TestCheckResourceAttrPair(dataSourceName, "invoke_arn", resourceName, "invoke_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "last_modified", resourceName, "last_modified"), + resource.TestCheckResourceAttrPair(dataSourceName, "memory_size", resourceName, "memory_size"), + resource.TestCheckResourceAttrPair(dataSourceName, "qualified_arn", resourceName, "qualified_arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "reserved_concurrent_executions", resourceName, "reserved_concurrent_executions"), + resource.TestCheckResourceAttrPair(dataSourceName, "role", resourceName, "role"), + resource.TestCheckResourceAttrPair(dataSourceName, "runtime", resourceName, "runtime"), + resource.TestCheckResourceAttrPair(dataSourceName, "source_code_hash", resourceName, "source_code_hash"), + resource.TestCheckResourceAttrPair(dataSourceName, "source_code_size", resourceName, "source_code_size"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "timeout", resourceName, "timeout"), + resource.TestCheckResourceAttrPair(dataSourceName, "tracing_config.#", resourceName, "tracing_config.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "tracing_config.0.mode", resourceName, "tracing_config.0.mode"), + resource.TestCheckResourceAttrPair(dataSourceName, "version", resourceName, "version"), ), }, }, @@ -47,23 +46,21 @@ func TestAccDataSourceAWSLambdaFunction_basic(t *testing.T) { } func TestAccDataSourceAWSLambdaFunction_version(t *testing.T) { - rString := acctest.RandString(7) - roleName := fmt.Sprintf("tf-acctest-d-lambda-function-version-role-%s", rString) - policyName := fmt.Sprintf("tf-acctest-d-lambda-function-version-policy-%s", rString) - sgName := fmt.Sprintf("tf-acctest-d-lambda-function-version-sg-%s", rString) - funcName := fmt.Sprintf("tf-acctest-d-lambda-function-version-func-%s", rString) + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_lambda_function.test" + resourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAWSLambdaFunctionConfigVersion(roleName, policyName, sgName, funcName), + Config: testAccDataSourceAWSLambdaFunctionConfigVersion(rName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "function_name", funcName), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "qualifier", "1"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "version", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "qualified_arn", resourceName, "qualified_arn"), + resource.TestCheckResourceAttr(dataSourceName, "qualifier", "1"), + resource.TestCheckResourceAttr(dataSourceName, "version", "1"), ), }, }, @@ -71,23 +68,22 @@ func TestAccDataSourceAWSLambdaFunction_version(t *testing.T) { } func TestAccDataSourceAWSLambdaFunction_alias(t *testing.T) { - rString := acctest.RandString(7) - roleName := fmt.Sprintf("tf-acctest-d-lambda-function-alias-role-%s", rString) - policyName := fmt.Sprintf("tf-acctest-d-lambda-function-alias-policy-%s", rString) - sgName := fmt.Sprintf("tf-acctest-d-lambda-function-alias-sg-%s", rString) - funcName := fmt.Sprintf("tf-acctest-d-lambda-function-alias-func-%s", rString) + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_lambda_function.test" + lambdaAliasResourceName := "aws_lambda_alias.test" + resourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAWSLambdaFunctionConfigAlias(roleName, policyName, sgName, funcName), + Config: testAccDataSourceAWSLambdaFunctionConfigAlias(rName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "function_name", funcName), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "qualifier", "alias-name"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "version", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "qualified_arn", lambdaAliasResourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "qualifier", lambdaAliasResourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "version", lambdaAliasResourceName, "function_version"), ), }, }, @@ -95,22 +91,19 @@ func TestAccDataSourceAWSLambdaFunction_alias(t *testing.T) { } func TestAccDataSourceAWSLambdaFunction_layers(t *testing.T) { - rString := acctest.RandString(7) - roleName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-role-%s", rString) - policyName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-policy-%s", rString) - sgName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-sg-%s", rString) - funcName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-func-%s", rString) - layerName := fmt.Sprintf("tf-acctest-d-lambda-function-layer-layer-%s", rString) + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_lambda_function.test" + resourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAWSLambdaFunctionConfigLayers(roleName, policyName, sgName, funcName, layerName), + Config: testAccDataSourceAWSLambdaFunctionConfigLayers(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "layers.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "layers.#", resourceName, "layers.#"), ), }, }, @@ -118,23 +111,21 @@ func TestAccDataSourceAWSLambdaFunction_layers(t *testing.T) { } func TestAccDataSourceAWSLambdaFunction_vpc(t *testing.T) { - rString := acctest.RandString(7) - roleName := fmt.Sprintf("tf-acctest-d-lambda-function-vpc-role-%s", rString) - policyName := fmt.Sprintf("tf-acctest-d-lambda-function-vpc-policy-%s", rString) - sgName := fmt.Sprintf("tf-acctest-d-lambda-function-vpc-sg-%s", rString) - funcName := fmt.Sprintf("tf-acctest-d-lambda-function-vpc-func-%s", rString) + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_lambda_function.test" + resourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAWSLambdaFunctionConfigVPC(roleName, policyName, sgName, funcName), + Config: testAccDataSourceAWSLambdaFunctionConfigVPC(rName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "vpc_config.#", "1"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "vpc_config.0.security_group_ids.#", "1"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "vpc_config.0.subnet_ids.#", "1"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpc_config.#", resourceName, "vpc_config.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpc_config.0.security_group_ids.#", resourceName, "vpc_config.0.security_group_ids.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpc_config.0.subnet_ids.#", resourceName, "vpc_config.0.subnet_ids.#"), ), }, }, @@ -142,34 +133,32 @@ func TestAccDataSourceAWSLambdaFunction_vpc(t *testing.T) { } func TestAccDataSourceAWSLambdaFunction_environment(t *testing.T) { - rString := acctest.RandString(7) - roleName := fmt.Sprintf("tf-acctest-d-lambda-function-environment-role-%s", rString) - policyName := fmt.Sprintf("tf-acctest-d-lambda-function-environment-policy-%s", rString) - sgName := fmt.Sprintf("tf-acctest-d-lambda-function-environment-sg-%s", rString) - funcName := fmt.Sprintf("tf-acctest-d-lambda-function-environment-func-%s", rString) + rName := acctest.RandomWithPrefix("tf-acc-test") + dataSourceName := "data.aws_lambda_function.test" + resourceName := "aws_lambda_function.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccDataSourceAWSLambdaFunctionConfigEnvironment(roleName, policyName, sgName, funcName), + Config: testAccDataSourceAWSLambdaFunctionConfigEnvironment(rName), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckResourceAttrSet("data.aws_lambda_function.acctest", "arn"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "environment.#", "1"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "environment.0.variables.%", "2"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "environment.0.variables.key1", "value1"), - resource.TestCheckResourceAttr("data.aws_lambda_function.acctest", "environment.0.variables.key2", "value2"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "environment.#", resourceName, "environment.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "environment.0.variables.%", resourceName, "environment.0.variables.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "environment.0.variables.key1", resourceName, "environment.0.variables.key1"), + resource.TestCheckResourceAttrPair(dataSourceName, "environment.0.variables.key2", resourceName, "environment.0.variables.key2"), ), }, }, }) } -func testAccDataSourceAWSLambdaFunctionConfigBase(roleName, policyName, sgName string) string { +func testAccDataSourceAWSLambdaFunctionConfigBase(rName string) string { return fmt.Sprintf(` resource "aws_iam_role" "lambda" { - name = "%s" + name = %[1]q assume_role_policy = <