From 1e09e14e3f95e700e16957ffbbf408d0721b1d17 Mon Sep 17 00:00:00 2001 From: Vahe Sahakyan Date: Sun, 15 Apr 2018 11:54:29 +0200 Subject: [PATCH 1/5] Add aws_lambda_invoke data source --- aws/data_source_aws_lambda_invoke.go | 91 ++++++++++++++ aws/data_source_aws_lambda_invoke_test.go | 134 +++++++++++++++++++++ aws/provider.go | 1 + aws/test-fixtures/lambda_invoke.js | 6 + aws/test-fixtures/lambda_invoke.zip | Bin 0 -> 282 bytes website/docs/d/lambda_invoke.html.markdown | 45 +++++++ 6 files changed, 277 insertions(+) create mode 100644 aws/data_source_aws_lambda_invoke.go create mode 100644 aws/data_source_aws_lambda_invoke_test.go create mode 100644 aws/test-fixtures/lambda_invoke.js create mode 100644 aws/test-fixtures/lambda_invoke.zip create mode 100644 website/docs/d/lambda_invoke.html.markdown diff --git a/aws/data_source_aws_lambda_invoke.go b/aws/data_source_aws_lambda_invoke.go new file mode 100644 index 00000000000..d332a446c73 --- /dev/null +++ b/aws/data_source_aws_lambda_invoke.go @@ -0,0 +1,91 @@ +package aws + +import ( + "crypto/md5" + "encoding/json" + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lambda" + "github.com/hashicorp/terraform/helper/schema" +) + +func dataSourceAwsLambdaInvoke() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsLambdaInvokeRead, + + Schema: map[string]*schema.Schema{ + "function_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "qualifier": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: "$LATEST", + }, + + "input": { + Type: schema.TypeMap, + Required: true, + ForceNew: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + + "result": { + Type: schema.TypeMap, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + }, + }, + }, + } +} + +func dataSourceAwsLambdaInvokeRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lambdaconn + + functionName := d.Get("function_name").(string) + qualifier := d.Get("qualifier").(string) + + payload, err := json.Marshal(d.Get("input")) + + if err != nil { + return err + } + + res, err := conn.Invoke(&lambda.InvokeInput{ + FunctionName: aws.String(functionName), + InvocationType: aws.String(lambda.InvocationTypeRequestResponse), + Payload: payload, + Qualifier: aws.String(qualifier), + }) + + if err != nil { + return err + } + + if res.FunctionError != nil { + return fmt.Errorf("Lambda function (%s) returned error: (%s)", functionName, string(res.Payload)) + } + + 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) + } + + d.SetId(fmt.Sprintf("%s_%s_%x", functionName, qualifier, md5.Sum(payload))) + + return nil +} diff --git a/aws/data_source_aws_lambda_invoke_test.go b/aws/data_source_aws_lambda_invoke_test.go new file mode 100644 index 00000000000..5a5138a5c02 --- /dev/null +++ b/aws/data_source_aws_lambda_invoke_test.go @@ -0,0 +1,134 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAwsLambdaInvoke_basic(t *testing.T) { + testData := "value3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsLambdaInvoke_basic_config("tf-test-lambda-role", "tf-test-lambda-invoke", testData), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.%", "3"), + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.key1", "value1"), + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.key2", "value2"), + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.key3", testData), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsLambdaInvoke_qualifier(t *testing.T) { + testData := "value3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceAwsLambdaInvoke_qualifier_config("tf-test-lambda-role-qualifier", "tf-test-lambda-invoke-qualifier", testData), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.%", "3"), + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.key1", "value1"), + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.key2", "value2"), + resource.TestCheckResourceAttr("data.aws_lambda_invoke.invoke_test", "result.key3", testData), + ), + }, + }, + }) +} + +func testAccDataSourceAwsLambdaInvoke_base_config(roleName string) string { + return fmt.Sprintf(` +data "aws_iam_policy_document" "lambda_assume_role_policy" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "lambda_role" { + name = "%s" + assume_role_policy = "${data.aws_iam_policy_document.lambda_assume_role_policy.json}" +} + +resource "aws_iam_role_policy_attachment" "lambda_role_policy" { + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + role = "${aws_iam_role.lambda_role.name}" +} +`, roleName) +} + +func testAccDataSourceAwsLambdaInvoke_basic_config(roleName, lambdaName, testData string) string { + return fmt.Sprintf(testAccDataSourceAwsLambdaInvoke_base_config(roleName)+` +resource "aws_lambda_function" "lambda" { + depends_on = ["aws_iam_role_policy_attachment.lambda_role_policy"] + + filename = "test-fixtures/lambda_invoke.zip" + function_name = "%s" + role = "${aws_iam_role.lambda_role.arn}" + handler = "lambda_invoke.handler" + runtime = "nodejs8.10" + + environment { + variables = { + TEST_DATA = "%s" + } + } +} + +data "aws_lambda_invoke" "invoke_test" { + function_name = "${aws_lambda_function.lambda.function_name}" + + input { + key1 = "value1" + key2 = "value2" + } +} +`, lambdaName, testData) +} + +func testAccDataSourceAwsLambdaInvoke_qualifier_config(roleName, lambdaName, testData string) string { + return fmt.Sprintf(testAccDataSourceAwsLambdaInvoke_base_config(roleName)+` +resource "aws_lambda_function" "lambda" { + depends_on = ["aws_iam_role_policy_attachment.lambda_role_policy"] + + filename = "test-fixtures/lambda_invoke.zip" + function_name = "%s" + role = "${aws_iam_role.lambda_role.arn}" + handler = "lambda_invoke.handler" + runtime = "nodejs8.10" + publish = true + + environment { + variables = { + TEST_DATA = "%s" + } + } +} + +data "aws_lambda_invoke" "invoke_test" { + function_name = "${aws_lambda_function.lambda.function_name}" + qualifier = "${aws_lambda_function.lambda.version}" + + input { + key1 = "value1" + key2 = "value2" + } +} +`, lambdaName, testData) +} diff --git a/aws/provider.go b/aws/provider.go index 270a23f0a5b..9a47bd361a3 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -211,6 +211,7 @@ func Provider() terraform.ResourceProvider { "aws_kms_ciphertext": dataSourceAwsKmsCiphertext(), "aws_kms_key": dataSourceAwsKmsKey(), "aws_kms_secret": dataSourceAwsKmsSecret(), + "aws_lambda_invoke": dataSourceAwsLambdaInvoke(), "aws_nat_gateway": dataSourceAwsNatGateway(), "aws_network_interface": dataSourceAwsNetworkInterface(), "aws_partition": dataSourceAwsPartition(), diff --git a/aws/test-fixtures/lambda_invoke.js b/aws/test-fixtures/lambda_invoke.js new file mode 100644 index 00000000000..abc0191f982 --- /dev/null +++ b/aws/test-fixtures/lambda_invoke.js @@ -0,0 +1,6 @@ +exports.handler = async (event) => { + if (process.env.TEST_DATA) { + event.key3 = process.env.TEST_DATA; + } + return event; +} diff --git a/aws/test-fixtures/lambda_invoke.zip b/aws/test-fixtures/lambda_invoke.zip new file mode 100644 index 0000000000000000000000000000000000000000..aa3dd9a9f336f74b43d7a3200161cd6daec308b9 GIT binary patch literal 282 zcmWIWW@Zs#U|`^2&`g=&BR_wSb_$T!1H=LhG7LG1xk)LB@tJvL`Pr#@S;e6toD9rw ztFJ`82jbESZU#n{uZ#=~U=zI8YMjv5(!6%st9>zK z!`9#x&w?15&X}FkR0IaXp&L1H4(; PK4 literal 0 HcmV?d00001 diff --git a/website/docs/d/lambda_invoke.html.markdown b/website/docs/d/lambda_invoke.html.markdown new file mode 100644 index 00000000000..8fd026922ae --- /dev/null +++ b/website/docs/d/lambda_invoke.html.markdown @@ -0,0 +1,45 @@ +--- +layout: "aws" +page_title: "AWS: aws_lambda_invoke" +sidebar_current: "docs-aws-datasource-lambda-invoke" +description: |- + Invoke AWS Lambda Function as data source +--- + +# Data Source: aws_lambda_invoke + +Use this data source to invoke custom lambda functions as data source. + +~> **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). + +## Example Usage + +```hcl +data "aws_lambda_invoke" "example" { + function_name = "${aws_lambda_function.lambda_function_test.function_name}" + + input { + param1 = "value1" + param2 = "value2" + } +} + +output "result" { + value = "${data.aws_lambda_invoke.result["key1"]}" +} +``` + +## Argument Reference + + * `function_name` - (Required) The name of the lambda function. + * `input` - (Required) Map of string values to send as payload to the lambda function. + * `qualifier` - (Optional) The qualifier (a.k.a version) of the lambda function. Defaults + to `$LATEST`. + +## Attributes Reference + + * `result` - A map of string values returned from the lambda invocation. From 72e0f02f81d7d6072c0e6624df1216255924d4ee Mon Sep 17 00:00:00 2001 From: Vahe Sahakyan Date: Tue, 17 Apr 2018 22:05:32 +0200 Subject: [PATCH 2/5] Add d/aws_lambda_invoke link in website --- website/aws.erb | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/aws.erb b/website/aws.erb index 05f3638a36f..ceef7bf6103 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -187,6 +187,9 @@ > aws_kms_secret + > + aws_lambda_invoke + > aws_nat_gateway From 80ca22fe9f2b83c2f368af5cfbc9728168b72123 Mon Sep 17 00:00:00 2001 From: Vahe Sahakyan Date: Sat, 28 Apr 2018 15:07:40 +0400 Subject: [PATCH 3/5] Rename aws_lambda_invoke to aws_lambda_invocation, use TypeString for input field --- ...o => data_source_aws_lambda_invocation.go} | 27 ++-- aws/data_source_aws_lambda_invocation_test.go | 138 ++++++++++++++++++ aws/data_source_aws_lambda_invoke_test.go | 134 ----------------- aws/provider.go | 2 +- ...{lambda_invoke.js => lambda_invocation.js} | 0 aws/test-fixtures/lambda_invocation.zip | Bin 0 -> 290 bytes aws/test-fixtures/lambda_invoke.zip | Bin 282 -> 0 bytes 7 files changed, 149 insertions(+), 152 deletions(-) rename aws/{data_source_aws_lambda_invoke.go => data_source_aws_lambda_invocation.go} (77%) create mode 100644 aws/data_source_aws_lambda_invocation_test.go delete mode 100644 aws/data_source_aws_lambda_invoke_test.go rename aws/test-fixtures/{lambda_invoke.js => lambda_invocation.js} (100%) create mode 100644 aws/test-fixtures/lambda_invocation.zip delete mode 100644 aws/test-fixtures/lambda_invoke.zip diff --git a/aws/data_source_aws_lambda_invoke.go b/aws/data_source_aws_lambda_invocation.go similarity index 77% rename from aws/data_source_aws_lambda_invoke.go rename to aws/data_source_aws_lambda_invocation.go index d332a446c73..e865f43fddd 100644 --- a/aws/data_source_aws_lambda_invoke.go +++ b/aws/data_source_aws_lambda_invocation.go @@ -10,9 +10,9 @@ import ( "github.com/hashicorp/terraform/helper/schema" ) -func dataSourceAwsLambdaInvoke() *schema.Resource { +func dataSourceAwsLambdaInvocation() *schema.Resource { return &schema.Resource{ - Read: dataSourceAwsLambdaInvokeRead, + Read: dataSourceAwsLambdaInvocationRead, Schema: map[string]*schema.Schema{ "function_name": { @@ -29,12 +29,10 @@ func dataSourceAwsLambdaInvoke() *schema.Resource { }, "input": { - Type: schema.TypeMap, - Required: true, - ForceNew: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - }, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateJsonString, }, "result": { @@ -48,22 +46,17 @@ func dataSourceAwsLambdaInvoke() *schema.Resource { } } -func dataSourceAwsLambdaInvokeRead(d *schema.ResourceData, meta interface{}) error { +func dataSourceAwsLambdaInvocationRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).lambdaconn functionName := d.Get("function_name").(string) qualifier := d.Get("qualifier").(string) - - payload, err := json.Marshal(d.Get("input")) - - if err != nil { - return err - } + input := []byte(d.Get("input").(string)) res, err := conn.Invoke(&lambda.InvokeInput{ FunctionName: aws.String(functionName), InvocationType: aws.String(lambda.InvocationTypeRequestResponse), - Payload: payload, + Payload: input, Qualifier: aws.String(qualifier), }) @@ -85,7 +78,7 @@ func dataSourceAwsLambdaInvokeRead(d *schema.ResourceData, meta interface{}) err return fmt.Errorf("Lambda function (%s) returned invalid JSON: %s", functionName, err) } - d.SetId(fmt.Sprintf("%s_%s_%x", functionName, qualifier, md5.Sum(payload))) + d.SetId(fmt.Sprintf("%s_%s_%x", functionName, qualifier, md5.Sum(input))) return nil } diff --git a/aws/data_source_aws_lambda_invocation_test.go b/aws/data_source_aws_lambda_invocation_test.go new file mode 100644 index 00000000000..7620ba81345 --- /dev/null +++ b/aws/data_source_aws_lambda_invocation_test.go @@ -0,0 +1,138 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" +) + +func TestAccDataSourceAwsLambdaInvocation_basic(t *testing.T) { + testData := "value3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + 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), + ), + }, + }, + }) +} + +func TestAccDataSourceAwsLambdaInvocation_qualifier(t *testing.T) { + testData := "value3" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + 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), + ), + }, + }, + }) +} + +func testAccDataSourceAwsLambdaInvocation_base_config(roleName string) string { + return fmt.Sprintf(` +data "aws_iam_policy_document" "lambda_assume_role_policy" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["lambda.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "lambda_role" { + name = "%s" + assume_role_policy = "${data.aws_iam_policy_document.lambda_assume_role_policy.json}" +} + +resource "aws_iam_role_policy_attachment" "lambda_role_policy" { + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + role = "${aws_iam_role.lambda_role.name}" +} +`, roleName) +} + +func testAccDataSourceAwsLambdaInvocation_basic_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" + + environment { + variables = { + TEST_DATA = "%s" + } + } +} + +data "aws_lambda_invocation" "invocation_test" { + function_name = "${aws_lambda_function.lambda.function_name}" + + input = <9*0WckX-zyLPId#%O^eJ#yvr#;SipY+rX+7RlYv+j&{*aZ(= z@3Yz$LpE#;Uhyo5q3MhXYj4w{KTobaO4@s6kI`O%>klSWh#wbl_g%pxz>t0EwBK42 zHmR1-t)>yVx-)dVbTxHPHD_#kw(2PpLx49UlN>WHH%kCr&cFb455tm15DU8xSRp<@ VbA5m}D;r1;BM?Rb=}jOG0{|OZS0MlZ literal 0 HcmV?d00001 diff --git a/aws/test-fixtures/lambda_invoke.zip b/aws/test-fixtures/lambda_invoke.zip deleted file mode 100644 index aa3dd9a9f336f74b43d7a3200161cd6daec308b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282 zcmWIWW@Zs#U|`^2&`g=&BR_wSb_$T!1H=LhG7LG1xk)LB@tJvL`Pr#@S;e6toD9rw ztFJ`82jbESZU#n{uZ#=~U=zI8YMjv5(!6%st9>zK z!`9#x&w?15&X}FkR0IaXp&L1H4(; PK4 From c79c7a0b66e2b3adea7f3bace18c0f0594f0084a Mon Sep 17 00:00:00 2001 From: Vahe Sahakyan Date: Fri, 11 May 2018 11:08:31 +0200 Subject: [PATCH 4/5] Update docs for aws_lambda_invocation --- website/aws.erb | 4 ++-- ...rkdown => lambda_invocation.html.markdown} | 23 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) rename website/docs/d/{lambda_invoke.html.markdown => lambda_invocation.html.markdown} (70%) diff --git a/website/aws.erb b/website/aws.erb index fdc016f926a..44eafce3c4e 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -202,8 +202,8 @@ > aws_kms_secret - > - aws_lambda_invoke + > + aws_lambda_invocation > aws_nat_gateway diff --git a/website/docs/d/lambda_invoke.html.markdown b/website/docs/d/lambda_invocation.html.markdown similarity index 70% rename from website/docs/d/lambda_invoke.html.markdown rename to website/docs/d/lambda_invocation.html.markdown index 8fd026922ae..435c7f19a44 100644 --- a/website/docs/d/lambda_invoke.html.markdown +++ b/website/docs/d/lambda_invocation.html.markdown @@ -1,12 +1,12 @@ --- layout: "aws" -page_title: "AWS: aws_lambda_invoke" -sidebar_current: "docs-aws-datasource-lambda-invoke" +page_title: "AWS: aws_lambda_invocation" +sidebar_current: "docs-aws-datasource-lambda-invocation" description: |- Invoke AWS Lambda Function as data source --- -# Data Source: aws_lambda_invoke +# Data Source: aws_lambda_invocation Use this data source to invoke custom lambda functions as data source. @@ -19,24 +19,27 @@ invocation type. Response of lambda must be map of primitive types (string, bool ## Example Usage ```hcl -data "aws_lambda_invoke" "example" { +data "aws_lambda_invocation" "example" { function_name = "${aws_lambda_function.lambda_function_test.function_name}" - input { - param1 = "value1" - param2 = "value2" - } + input = < Date: Mon, 14 May 2018 21:09:11 +0200 Subject: [PATCH 5/5] Add raw result to aws_lambda_invocation data source --- aws/data_source_aws_lambda_invocation.go | 14 ++- aws/data_source_aws_lambda_invocation_test.go | 93 +++++++++++++++++-- .../docs/d/lambda_invocation.html.markdown | 17 ++-- 3 files changed, 106 insertions(+), 18 deletions(-) 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.