diff --git a/aws/data_source_aws_lambda_invocation.go b/aws/data_source_aws_lambda_invocation.go index e865f43fddd..6e532686fa9 100644 --- a/aws/data_source_aws_lambda_invocation.go +++ b/aws/data_source_aws_lambda_invocation.go @@ -4,6 +4,7 @@ import ( "crypto/md5" "encoding/json" "fmt" + "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/lambda" @@ -36,6 +37,11 @@ func dataSourceAwsLambdaInvocation() *schema.Resource { }, "result": { + Type: schema.TypeString, + Computed: true, + }, + + "result_map": { Type: schema.TypeMap, Computed: true, Elem: &schema.Schema{ @@ -68,14 +74,18 @@ func dataSourceAwsLambdaInvocationRead(d *schema.ResourceData, meta interface{}) return fmt.Errorf("Lambda function (%s) returned error: (%s)", functionName, string(res.Payload)) } + if err = d.Set("result", string(res.Payload)); err != nil { + return err + } + var result map[string]interface{} if err = json.Unmarshal(res.Payload, &result); err != nil { return err } - if err = d.Set("result", result); err != nil { - return fmt.Errorf("Lambda function (%s) returned invalid JSON: %s", functionName, err) + if err = d.Set("result_map", result); err != nil { + log.Printf("[WARN] Cannot use the result invocation as a string map: %s", err) } d.SetId(fmt.Sprintf("%s_%s_%x", functionName, qualifier, md5.Sum(input))) diff --git a/aws/data_source_aws_lambda_invocation_test.go b/aws/data_source_aws_lambda_invocation_test.go index 7620ba81345..6ade20a3365 100644 --- a/aws/data_source_aws_lambda_invocation_test.go +++ b/aws/data_source_aws_lambda_invocation_test.go @@ -5,8 +5,34 @@ import ( "testing" "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" ) +func testAccCheckLambdaInvocationResult(name, expectedResult string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } + + result, ok := rs.Primary.Attributes["result"] + + if !ok { + return fmt.Errorf("No result is set") + } + + if !suppressEquivalentJsonDiffs("", result, expectedResult, nil) { + return fmt.Errorf("%s: Attribute 'result' expected %s, got %s", name, expectedResult, result) + } + + return nil + } +} + func TestAccDataSourceAwsLambdaInvocation_basic(t *testing.T) { testData := "value3" @@ -17,10 +43,11 @@ func TestAccDataSourceAwsLambdaInvocation_basic(t *testing.T) { { Config: testAccDataSourceAwsLambdaInvocation_basic_config("tf-test-lambda-role", "tf-test-lambda-invocation", testData), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.%", "3"), - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.key1", "value1"), - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.key2", "value2"), - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.key3", testData), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.%", "3"), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.key1", "value1"), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.key2", "value2"), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.key3", testData), + testAccCheckLambdaInvocationResult("data.aws_lambda_invocation.invocation_test", `{"key1":"value1","key2":"value2","key3":"`+testData+`"}`), ), }, }, @@ -37,10 +64,28 @@ func TestAccDataSourceAwsLambdaInvocation_qualifier(t *testing.T) { { Config: testAccDataSourceAwsLambdaInvocation_qualifier_config("tf-test-lambda-role-qualifier", "tf-test-lambda-invocation-qualifier", testData), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.%", "3"), - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.key1", "value1"), - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.key2", "value2"), - resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result.key3", testData), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.%", "3"), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.key1", "value1"), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.key2", "value2"), + resource.TestCheckResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map.key3", testData), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsLambdaInvocation_complex(t *testing.T) { + testData := "value3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsLambdaInvocation_complex_config("tf-test-lambda-role-complex", "tf-test-lambda-invocation-complex", testData), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckNoResourceAttr("data.aws_lambda_invocation.invocation_test", "result_map"), + testAccCheckLambdaInvocationResult("data.aws_lambda_invocation.invocation_test", `{"key1":{"subkey1":"subvalue1"},"key2":{"subkey2":"subvalue2","subkey3":{"a": "b"}},"key3":"`+testData+`"}`), ), }, }, @@ -136,3 +181,35 @@ JSON } `, lambdaName, testData) } + +func testAccDataSourceAwsLambdaInvocation_complex_config(roleName, lambdaName, testData string) string { + return fmt.Sprintf(testAccDataSourceAwsLambdaInvocation_base_config(roleName)+` +resource "aws_lambda_function" "lambda" { + depends_on = ["aws_iam_role_policy_attachment.lambda_role_policy"] + + filename = "test-fixtures/lambda_invocation.zip" + function_name = "%s" + role = "${aws_iam_role.lambda_role.arn}" + handler = "lambda_invocation.handler" + runtime = "nodejs8.10" + publish = true + + environment { + variables = { + TEST_DATA = "%s" + } + } +} + +data "aws_lambda_invocation" "invocation_test" { + function_name = "${aws_lambda_function.lambda.function_name}" + + input = < **NOTE**: The `input` argument is JSON encoded and passed as payload to the -lambda function. All values in `input` map are converted to strings. -The lambda function is invoked with -[RequestResponse](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestSyntax) -invocation type. Response of lambda must be map of primitive types (string, bool or float). +The lambda function is invoked with [RequestResponse](https://docs.aws.amazon.com/lambda/latest/dg/API_Invoke.html#API_Invoke_RequestSyntax) +invocation type. ## Example Usage @@ -31,8 +27,12 @@ JSON } +output "result_entry" { + value = "${data.aws_lambda_invocation.result_map["key1"]}" +} + output "result" { - value = "${data.aws_lambda_invocation.result["key1"]}" + value = "${data.aws_lambda_invocation.result}" } ``` @@ -45,4 +45,5 @@ output "result" { ## Attributes Reference - * `result` - A map of string values returned from the lambda invocation. + * `result` - A result of the lambda function invocation. + * `result_map` - This field is set only if result is a map of primitive types.