diff --git a/aws/data_source_aws_lb_target_group.go b/aws/data_source_aws_lb_target_group.go index 5f7f20f728b..4083051e78a 100644 --- a/aws/data_source_aws_lb_target_group.go +++ b/aws/data_source_aws_lb_target_group.go @@ -49,6 +49,11 @@ func dataSourceAwsLbTargetGroup() *schema.Resource { Computed: true, }, + "lambda_multi_value_headers_enabled": { + Type: schema.TypeBool, + Computed: true, + }, + "slow_start": { Type: schema.TypeInt, Computed: true, diff --git a/aws/resource_aws_alb_target_group_test.go b/aws/resource_aws_alb_target_group_test.go index a696918f3d1..3bfcf7e630f 100644 --- a/aws/resource_aws_alb_target_group_test.go +++ b/aws/resource_aws_alb_target_group_test.go @@ -505,20 +505,79 @@ func testAccCheckAWSALBTargetGroupDestroy(s *terraform.State) error { } func TestAccAWSALBTargetGroup_lambda(t *testing.T) { - var conf elbv2.TargetGroup - targetGroupName := fmt.Sprintf("test-target-group-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum)) + var targetGroup1 elbv2.TargetGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_alb_target_group.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, - IDRefreshName: "aws_alb_target_group.test", - Providers: testAccProviders, - CheckDestroy: testAccCheckAWSALBTargetGroupDestroy, + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSALBTargetGroupDestroy, Steps: []resource.TestStep{ { - Config: testAccAWSALBTargetGroupConfig_lambda(targetGroupName), + Config: testAccAWSALBTargetGroupConfig_lambda(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSALBTargetGroupExists("aws_alb_target_group.test", &conf), - resource.TestCheckResourceAttr("aws_alb_target_group.test", "target_type", "lambda"), + testAccCheckAWSALBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "lambda_multi_value_headers_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "target_type", "lambda"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "deregistration_delay", + "proxy_protocol_v2", + "slow_start", + }, + }, + }, + }) +} + +func TestAccAWSALBTargetGroup_lambdaMultiValueHeadersEnabled(t *testing.T) { + var targetGroup1 elbv2.TargetGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_alb_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSALBTargetGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSALBTargetGroupConfig_lambdaMultiValueHeadersEnabled(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSALBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "lambda_multi_value_headers_enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "target_type", "lambda"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "deregistration_delay", + "proxy_protocol_v2", + "slow_start", + }, + }, + { + Config: testAccAWSALBTargetGroupConfig_lambdaMultiValueHeadersEnabled(rName, false), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSALBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "lambda_multi_value_headers_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "target_type", "lambda"), + ), + }, + { + Config: testAccAWSALBTargetGroupConfig_lambdaMultiValueHeadersEnabled(rName, true), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSALBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "lambda_multi_value_headers_enabled", "true"), + resource.TestCheckResourceAttr(resourceName, "target_type", "lambda"), ), }, }, @@ -918,6 +977,16 @@ func testAccAWSALBTargetGroupConfig_lambda(targetGroupName string) string { }`, targetGroupName) } +func testAccAWSALBTargetGroupConfig_lambdaMultiValueHeadersEnabled(rName string, lambdaMultiValueHadersEnabled bool) string { + return fmt.Sprintf(` +resource "aws_alb_target_group" "test" { + lambda_multi_value_headers_enabled = %[1]t + name = %[2]q + target_type = "lambda" +} +`, lambdaMultiValueHadersEnabled, rName) +} + func testAccAWSALBTargetGroupConfig_missing_port(targetGroupName string) string { return fmt.Sprintf(`resource "aws_alb_target_group" "test" { name = "%s" diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index 94ffb3d8af2..49a5f8ea4bf 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -100,6 +100,12 @@ func resourceAwsLbTargetGroup() *schema.Resource { Default: false, }, + "lambda_multi_value_headers_enabled": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "target_type": { Type: schema.TypeString, Optional: true, @@ -367,9 +373,10 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er } } - if d.Get("target_type").(string) != elbv2.TargetTypeEnumLambda { - var attrs []*elbv2.TargetGroupAttribute + var attrs []*elbv2.TargetGroupAttribute + switch d.Get("target_type").(string) { + case elbv2.TargetTypeEnumInstance, elbv2.TargetTypeEnumIp: if d.HasChange("deregistration_delay") { attrs = append(attrs, &elbv2.TargetGroupAttribute{ Key: aws.String("deregistration_delay.timeout_seconds"), @@ -395,7 +402,7 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er // groups, so long as it's not enabled. This allows for better support for // modules, but also means we need to completely skip sending the data to the // API if it's defined on a TCP target group. - if d.HasChange("stickiness") && d.Get("protocol") != "TCP" && d.Get("target_type").(string) != elbv2.TargetTypeEnumLambda { + if d.HasChange("stickiness") && d.Get("protocol") != "TCP" { stickinessBlocks := d.Get("stickiness").([]interface{}) if len(stickinessBlocks) == 1 { stickiness := stickinessBlocks[0].(map[string]interface{}) @@ -420,17 +427,24 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er }) } } + case elbv2.TargetTypeEnumLambda: + if d.HasChange("lambda_multi_value_headers_enabled") { + attrs = append(attrs, &elbv2.TargetGroupAttribute{ + Key: aws.String("lambda.multi_value_headers.enabled"), + Value: aws.String(strconv.FormatBool(d.Get("lambda_multi_value_headers_enabled").(bool))), + }) + } + } - if len(attrs) > 0 { - params := &elbv2.ModifyTargetGroupAttributesInput{ - TargetGroupArn: aws.String(d.Id()), - Attributes: attrs, - } + if len(attrs) > 0 { + params := &elbv2.ModifyTargetGroupAttributesInput{ + TargetGroupArn: aws.String(d.Id()), + Attributes: attrs, + } - _, err := elbconn.ModifyTargetGroupAttributes(params) - if err != nil { - return fmt.Errorf("Error modifying Target Group Attributes: %s", err) - } + _, err := elbconn.ModifyTargetGroupAttributes(params) + if err != nil { + return fmt.Errorf("Error modifying Target Group Attributes: %s", err) } } @@ -551,6 +565,12 @@ func flattenAwsLbTargetGroupResource(d *schema.ResourceData, meta interface{}, t for _, attr := range attrResp.Attributes { switch aws.StringValue(attr.Key) { + case "lambda.multi_value_headers.enabled": + enabled, err := strconv.ParseBool(aws.StringValue(attr.Value)) + if err != nil { + return fmt.Errorf("Error converting lambda.multi_value_headers.enabled to bool: %s", aws.StringValue(attr.Value)) + } + d.Set("lambda_multi_value_headers_enabled", enabled) case "proxy_protocol_v2.enabled": enabled, err := strconv.ParseBool(aws.StringValue(attr.Value)) if err != nil { diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index c85f038dd5c..38273a68441 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -66,6 +66,7 @@ The following arguments are supported: * `vpc_id` - (Optional, Forces new resource) The identifier of the VPC in which to create the target group. Required when `target_type` is `instance` or `ip`. Does not apply when `target_type` is `lambda`. * `deregistration_delay` - (Optional) The amount time for Elastic Load Balancing to wait before changing the state of a deregistering target from draining to unused. The range is 0-3600 seconds. The default value is 300 seconds. * `slow_start` - (Optional) The amount time for targets to warm up before the load balancer sends them a full share of requests. The range is 30-900 seconds or 0 to disable. The default value is 0 seconds. +* `lambda_multi_value_headers_enabled` - (Optional) Boolean whether the request and response headers exchanged between the load balancer and the Lambda function include arrays of values or strings. Only applies when `target_type` is `lambda`. * `proxy_protocol_v2` - (Optional) Boolean to enable / disable support for proxy protocol v2 on Network Load Balancers. See [doc](https://docs.aws.amazon.com/elasticloadbalancing/latest/network/load-balancer-target-groups.html#proxy-protocol) for more information. * `stickiness` - (Optional) A Stickiness block. Stickiness blocks are documented below. `stickiness` is only valid if used with Load Balancers of type `Application` * `health_check` - (Optional) A Health Check block. Health Check blocks are documented below.