Skip to content

Commit

Permalink
Merge pull request #15894 from ewbankkit/b-aws_apigatewayv2_integrati…
Browse files Browse the repository at this point in the history
…on-request_parameters-update-for-AWS-service

r/aws_apigatewayv2_integration: Specify required parameters on update
  • Loading branch information
breathingdust authored Oct 29, 2020
2 parents 2b6a2b2 + 2bb5271 commit 1e6951d
Show file tree
Hide file tree
Showing 5 changed files with 148 additions and 51 deletions.
13 changes: 12 additions & 1 deletion aws/resource_aws_apigatewayv2_integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter
req := &apigatewayv2.UpdateIntegrationInput{
ApiId: aws.String(d.Get("api_id").(string)),
IntegrationId: aws.String(d.Id()),
// Always specify the integration type.
IntegrationType: aws.String(d.Get("integration_type").(string)),
}
if d.HasChange("connection_id") {
req.ConnectionId = aws.String(d.Get("connection_id").(string))
Expand All @@ -281,6 +283,10 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter
if d.HasChange("integration_method") {
req.IntegrationMethod = aws.String(d.Get("integration_method").(string))
}
// Always specify any integration subtype.
if v, ok := d.GetOk("integration_subtype"); ok {
req.IntegrationSubtype = aws.String(v.(string))
}
if d.HasChange("integration_uri") {
req.IntegrationUri = aws.String(d.Get("integration_uri").(string))
}
Expand All @@ -292,7 +298,7 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter
}
if d.HasChange("request_parameters") {
o, n := d.GetChange("request_parameters")
add, del := diffStringMaps(o.(map[string]interface{}), n.(map[string]interface{}))
add, del, nop := diffStringMaps(o.(map[string]interface{}), n.(map[string]interface{}))
// Parameters are removed by setting the associated value to "".
for k := range del {
del[k] = aws.String("")
Expand All @@ -301,6 +307,11 @@ func resourceAwsApiGatewayV2IntegrationUpdate(d *schema.ResourceData, meta inter
for k, v := range add {
variables[k] = v
}
// Also specify any request parameters that are unchanged as for AWS service integrations some parameters are always required:
// https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-develop-integrations-aws-services-reference.html
for k, v := range nop {
variables[k] = v
}
req.RequestParameters = variables
}
if d.HasChange("request_templates") {
Expand Down
151 changes: 111 additions & 40 deletions aws/resource_aws_apigatewayv2_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,6 @@ func TestAccAWSAPIGatewayV2Integration_LambdaWebSocket(t *testing.T) {
var apiId string
var v apigatewayv2.GetIntegrationOutput
resourceName := "aws_apigatewayv2_integration.test"
callerIdentityDatasourceName := "data.aws_caller_identity.current"
lambdaResourceName := "aws_lambda_function.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

Expand All @@ -212,7 +211,7 @@ func TestAccAWSAPIGatewayV2Integration_LambdaWebSocket(t *testing.T) {
testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v),
resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"),
resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", "CONVERT_TO_TEXT"),
resource.TestCheckResourceAttrPair(resourceName, "credentials_arn", callerIdentityDatasourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""),
resource.TestCheckResourceAttr(resourceName, "description", "Test Lambda"),
resource.TestCheckResourceAttr(resourceName, "integration_method", "POST"),
resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", "${integration.response.body.errorMessage}"),
Expand Down Expand Up @@ -242,7 +241,6 @@ func TestAccAWSAPIGatewayV2Integration_LambdaHttp(t *testing.T) {
var apiId string
var v apigatewayv2.GetIntegrationOutput
resourceName := "aws_apigatewayv2_integration.test"
callerIdentityDatasourceName := "data.aws_caller_identity.current"
lambdaResourceName := "aws_lambda_function.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

Expand All @@ -257,7 +255,7 @@ func TestAccAWSAPIGatewayV2Integration_LambdaHttp(t *testing.T) {
testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v),
resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"),
resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""),
resource.TestCheckResourceAttrPair(resourceName, "credentials_arn", callerIdentityDatasourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "credentials_arn", ""),
resource.TestCheckResourceAttr(resourceName, "description", "Test Lambda"),
resource.TestCheckResourceAttr(resourceName, "integration_method", "POST"),
resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""),
Expand Down Expand Up @@ -407,6 +405,9 @@ func TestAccAWSAPIGatewayV2Integration_AwsServiceIntegration(t *testing.T) {
var apiId string
var v apigatewayv2.GetIntegrationOutput
resourceName := "aws_apigatewayv2_integration.test"
iamRoleResourceName := "aws_iam_role.test"
sqsQueue1ResourceName := "aws_sqs_queue.test.0"
sqsQueue2ResourceName := "aws_sqs_queue.test.1"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
Expand All @@ -415,11 +416,12 @@ func TestAccAWSAPIGatewayV2Integration_AwsServiceIntegration(t *testing.T) {
CheckDestroy: testAccCheckAWSAPIGatewayV2IntegrationDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSAPIGatewayV2IntegrationConfig_sqsIntegration(rName),
Config: testAccAWSAPIGatewayV2IntegrationConfig_sqsIntegration(rName, 0),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v),
resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"),
resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""),
resource.TestCheckResourceAttrPair(resourceName, "credentials_arn", iamRoleResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "description", "Test SQS send"),
resource.TestCheckResourceAttr(resourceName, "integration_method", ""),
resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""),
Expand All @@ -428,9 +430,35 @@ func TestAccAWSAPIGatewayV2Integration_AwsServiceIntegration(t *testing.T) {
resource.TestCheckResourceAttr(resourceName, "integration_uri", ""),
resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", ""),
resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.%", "2"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.QueueUrl", "$request.header.queueUrl"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.MessageBody", "$request.body.message"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.%", "3"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.MessageBody", "$request.body"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.MessageGroupId", "$request.body.authentication_key"),
resource.TestCheckResourceAttrPair(resourceName, "request_parameters.QueueUrl", sqsQueue1ResourceName, "id"),
resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"),
resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""),
resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"),
resource.TestCheckResourceAttr(resourceName, "tls_config.#", "0"),
),
},
{
Config: testAccAWSAPIGatewayV2IntegrationConfig_sqsIntegration(rName, 1),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSAPIGatewayV2IntegrationExists(resourceName, &apiId, &v),
resource.TestCheckResourceAttr(resourceName, "connection_type", "INTERNET"),
resource.TestCheckResourceAttr(resourceName, "content_handling_strategy", ""),
resource.TestCheckResourceAttrPair(resourceName, "credentials_arn", iamRoleResourceName, "arn"),
resource.TestCheckResourceAttr(resourceName, "description", "Test SQS send"),
resource.TestCheckResourceAttr(resourceName, "integration_method", ""),
resource.TestCheckResourceAttr(resourceName, "integration_response_selection_expression", ""),
resource.TestCheckResourceAttr(resourceName, "integration_subtype", "SQS-SendMessage"),
resource.TestCheckResourceAttr(resourceName, "integration_type", "AWS_PROXY"),
resource.TestCheckResourceAttr(resourceName, "integration_uri", ""),
resource.TestCheckResourceAttr(resourceName, "passthrough_behavior", ""),
resource.TestCheckResourceAttr(resourceName, "payload_format_version", "1.0"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.%", "3"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.MessageBody", "$request.body"),
resource.TestCheckResourceAttr(resourceName, "request_parameters.MessageGroupId", "$request.body.authentication_key"),
resource.TestCheckResourceAttrPair(resourceName, "request_parameters.QueueUrl", sqsQueue2ResourceName, "id"),
resource.TestCheckResourceAttr(resourceName, "request_templates.%", "0"),
resource.TestCheckResourceAttr(resourceName, "template_selection_expression", ""),
resource.TestCheckResourceAttr(resourceName, "timeout_milliseconds", "29000"),
Expand Down Expand Up @@ -544,6 +572,60 @@ resource "aws_apigatewayv2_api" "test" {
`, rName)
}

func testAccAWSAPIGatewayV2IntegrationConfig_lambdaBase(rName string) string {
return fmt.Sprintf(`
resource "aws_iam_role" "test" {
name = %[1]q
assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["sts:AssumeRole"],
"Principal": {"Service": "lambda.amazonaws.com"}
}]
}
EOF
}
resource "aws_iam_role_policy" "test" {
name = %[1]q
role = aws_iam_role.test.id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": ["*"]
}]
}
EOF
}
resource "aws_lambda_function" "test" {
filename = "test-fixtures/lambdatest.zip"
function_name = %[1]q
role = aws_iam_role.test.arn
handler = "index.handler"
runtime = "nodejs10.x"
depends_on = [aws_iam_role_policy.test]
}
resource "aws_lambda_permission" "test" {
action = "lambda:*"
function_name = aws_lambda_function.test.arn
principal = "apigateway.amazonaws.com"
}
`, rName)
}

func testAccAWSAPIGatewayV2IntegrationConfig_vpcLinkHttpBase(rName string) string {
return composeConfig(
testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName),
Expand Down Expand Up @@ -656,59 +738,41 @@ resource "aws_apigatewayv2_integration" "test" {
func testAccAWSAPIGatewayV2IntegrationConfig_lambdaWebSocket(rName string) string {
return composeConfig(
testAccAWSAPIGatewayV2IntegrationConfig_apiWebSocket(rName),
baseAccAWSLambdaConfig(rName, rName, rName),
fmt.Sprintf(`
data "aws_caller_identity" "current" {}
resource "aws_lambda_function" "test" {
filename = "test-fixtures/lambdatest.zip"
function_name = %[1]q
role = aws_iam_role.iam_for_lambda.arn
handler = "index.handler"
runtime = "nodejs10.x"
}
testAccAWSAPIGatewayV2IntegrationConfig_lambdaBase(rName),
`
resource "aws_apigatewayv2_integration" "test" {
api_id = aws_apigatewayv2_api.test.id
integration_type = "AWS"
connection_type = "INTERNET"
content_handling_strategy = "CONVERT_TO_TEXT"
credentials_arn = data.aws_caller_identity.current.arn
description = "Test Lambda"
integration_uri = aws_lambda_function.test.invoke_arn
passthrough_behavior = "WHEN_NO_MATCH"
depends_on = [aws_lambda_permission.test]
}
`, rName))
`)
}

func testAccAWSAPIGatewayV2IntegrationConfig_lambdaHttp(rName string) string {
return composeConfig(
testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName),
baseAccAWSLambdaConfig(rName, rName, rName),
fmt.Sprintf(`
data "aws_caller_identity" "current" {}
resource "aws_lambda_function" "test" {
filename = "test-fixtures/lambdatest.zip"
function_name = %[1]q
role = aws_iam_role.iam_for_lambda.arn
handler = "index.handler"
runtime = "nodejs10.x"
}
testAccAWSAPIGatewayV2IntegrationConfig_lambdaBase(rName),
`
resource "aws_apigatewayv2_integration" "test" {
api_id = aws_apigatewayv2_api.test.id
integration_type = "AWS_PROXY"
connection_type = "INTERNET"
credentials_arn = data.aws_caller_identity.current.arn
description = "Test Lambda"
integration_uri = aws_lambda_function.test.invoke_arn
payload_format_version = "2.0"
depends_on = [aws_lambda_permission.test]
}
`, rName))
`)
}

func testAccAWSAPIGatewayV2IntegrationConfig_httpProxy(rName string) string {
Expand Down Expand Up @@ -830,7 +894,7 @@ resource "aws_apigatewayv2_integration" "test" {
`, rName))
}

func testAccAWSAPIGatewayV2IntegrationConfig_sqsIntegration(rName string) string {
func testAccAWSAPIGatewayV2IntegrationConfig_sqsIntegration(rName string, queueIndex int) string {
return composeConfig(
testAccAWSAPIGatewayV2IntegrationConfig_apiHttp(rName),
fmt.Sprintf(`
Expand Down Expand Up @@ -865,6 +929,12 @@ resource "aws_iam_role_policy" "test" {
EOF
}
resource "aws_sqs_queue" "test" {
count = 2
name = "%[1]s-${count.index}"
}
resource "aws_apigatewayv2_integration" "test" {
api_id = aws_apigatewayv2_api.test.id
credentials_arn = aws_iam_role.test.arn
Expand All @@ -873,11 +943,12 @@ resource "aws_apigatewayv2_integration" "test" {
integration_subtype = "SQS-SendMessage"
request_parameters = {
"QueueUrl" = "$request.header.queueUrl"
"MessageBody" = "$request.body.message"
"QueueUrl" = aws_sqs_queue.test.%[2]d.id
"MessageGroupId" = "$request.body.authentication_key"
"MessageBody" = "$request.body"
}
depends_on = [aws_iam_role_policy.test]
}
`, rName))
`, rName, queueIndex))
}
2 changes: 1 addition & 1 deletion aws/resource_aws_apigatewayv2_stage.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ func resourceAwsApiGatewayV2StageUpdate(d *schema.ResourceData, meta interface{}
}
if d.HasChange("stage_variables") {
o, n := d.GetChange("stage_variables")
add, del := diffStringMaps(o.(map[string]interface{}), n.(map[string]interface{}))
add, del, _ := diffStringMaps(o.(map[string]interface{}), n.(map[string]interface{}))
// Variables are removed by setting the associated value to "".
for k := range del {
del[k] = aws.String("")
Expand Down
13 changes: 7 additions & 6 deletions aws/structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -1568,30 +1568,31 @@ func stringMapToPointers(m map[string]interface{}) map[string]*string {
return list
}

// diffStringMaps returns the set of keys and values that must be created,
// and the set of keys and values that must be destroyed.
// Equivalent to 'diffTagsGeneric'.
func diffStringMaps(oldMap, newMap map[string]interface{}) (map[string]*string, map[string]*string) {
// diffStringMaps returns the set of keys and values that must be created, the set of keys
// and values that must be destroyed, and the set of keys and values that are unchanged.
func diffStringMaps(oldMap, newMap map[string]interface{}) (map[string]*string, map[string]*string, map[string]*string) {
// First, we're creating everything we have
create := map[string]*string{}
for k, v := range newMap {
create[k] = aws.String(v.(string))
}

// Build the map of what to remove
// Build the maps of what to remove and what is unchanged
remove := map[string]*string{}
unchanged := map[string]*string{}
for k, v := range oldMap {
old, ok := create[k]
if !ok || aws.StringValue(old) != v.(string) {
// Delete it!
remove[k] = aws.String(v.(string))
} else if ok {
unchanged[k] = aws.String(v.(string))
// already present so remove from new
delete(create, k)
}
}

return create, remove
return create, remove, unchanged
}

func flattenDSVpcSettings(
Expand Down
Loading

0 comments on commit 1e6951d

Please sign in to comment.