diff --git a/aws/provider.go b/aws/provider.go index ed4f6d70e28..d4ace8b149c 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -781,6 +781,7 @@ func Provider() *schema.Provider { "aws_lambda_event_source_mapping": resourceAwsLambdaEventSourceMapping(), "aws_lambda_function_event_invoke_config": resourceAwsLambdaFunctionEventInvokeConfig(), "aws_lambda_function": resourceAwsLambdaFunction(), + "aws_lambda_invocation": resourceAwsLambdaInvocation(), "aws_lambda_layer_version": resourceAwsLambdaLayerVersion(), "aws_lambda_permission": resourceAwsLambdaPermission(), "aws_lambda_provisioned_concurrency_config": resourceAwsLambdaProvisionedConcurrencyConfig(), diff --git a/aws/resource_aws_lambda_invocation.go b/aws/resource_aws_lambda_invocation.go new file mode 100644 index 00000000000..9aee912eea5 --- /dev/null +++ b/aws/resource_aws_lambda_invocation.go @@ -0,0 +1,100 @@ +package aws + +import ( + "crypto/md5" + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/lambda" + + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" +) + +func resourceAwsLambdaInvocation() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsLambdaInvocationCreate, + Read: resourceAwsLambdaInvocationRead, + Update: resourceAwsLambdaInvocationUpdate, + Delete: resourceAwsLambdaInvocationDelete, + + Schema: map[string]*schema.Schema{ + "function_name": { + Type: schema.TypeString, + Required: true, + }, + + "qualifier": { + Type: schema.TypeString, + Optional: true, + Default: "$LATEST", + }, + + "input": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringIsJSON, + }, + + "invoke_on_update": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + + "result": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceAwsLambdaInvocationCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).lambdaconn + + functionName := d.Get("function_name").(string) + qualifier := d.Get("qualifier").(string) + input := []byte(d.Get("input").(string)) + + res, err := conn.Invoke(&lambda.InvokeInput{ + FunctionName: aws.String(functionName), + InvocationType: aws.String(lambda.InvocationTypeRequestResponse), + Payload: input, + 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)) + } + + if err = d.Set("result", string(res.Payload)); err != nil { + return err + } + + d.SetId(fmt.Sprintf("%s_%s_%x", functionName, qualifier, md5.Sum(input))) + + return nil +} + +func resourceAwsLambdaInvocationRead(d *schema.ResourceData, meta interface{}) error { + return nil +} + +func resourceAwsLambdaInvocationUpdate(d *schema.ResourceData, meta interface{}) error { + if d.Get("invoke_on_update").(bool) { + return resourceAwsLambdaInvocationCreate(d, meta) + } else { + return nil + } +} + +func resourceAwsLambdaInvocationDelete(d *schema.ResourceData, meta interface{}) error { + d.SetId("") + d.Set("result", nil) + return nil +} diff --git a/aws/resource_aws_lambda_invocation_test.go b/aws/resource_aws_lambda_invocation_test.go new file mode 100644 index 00000000000..9008c4da343 --- /dev/null +++ b/aws/resource_aws_lambda_invocation_test.go @@ -0,0 +1,195 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccResourceAwsLambdaInvocation_basic(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + testData := "value3" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaInvocationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccResourceAwsLambdaInvocation_basic_config(rName, testData), + Check: resource.ComposeTestCheckFunc( + testAccCheckLambdaInvocationResult("aws_lambda_invocation.invocation_test", `{"key1":"value1","key2":"value2","key3":"`+testData+`"}`), + ), + }, + }, + }) +} + +func TestAccResourceAwsLambdaInvocation_qualifier(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + testData := "value3" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaInvocationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccResourceAwsLambdaInvocation_qualifier_config(rName, testData), + Check: resource.ComposeTestCheckFunc( + testAccCheckLambdaInvocationResult("aws_lambda_invocation.invocation_test", `{"key1":"value1","key2":"value2","key3":"`+testData+`"}`), + ), + }, + }, + }) +} + +func TestAccResourceAwsLambdaInvocation_complex(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + testData := "value3" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckLambdaInvocationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccResourceAwsLambdaInvocation_complex_config(rName, testData), + Check: resource.ComposeTestCheckFunc( + testAccCheckLambdaInvocationResult("aws_lambda_invocation.invocation_test", `{"key1":{"subkey1":"subvalue1"},"key2":{"subkey2":"subvalue2","subkey3":{"a": "b"}},"key3":"`+testData+`"}`), + ), + }, + }, + }) +} + +func testAccCheckLambdaInvocationDestroy(s *terraform.State) error { + // Nothing to check on destroy + return nil + +} + +func testAccResourceAwsLambdaInvocation_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 testAccResourceAwsLambdaInvocation_basic_config(rName, testData string) string { + return fmt.Sprintf(testAccResourceAwsLambdaInvocation_base_config(rName)+` +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 = "nodejs12.x" + + environment { + variables = { + TEST_DATA = "%s" + } + } +} + +resource "aws_lambda_invocation" "invocation_test" { + function_name = aws_lambda_function.lambda.function_name + + input = <