diff --git a/.changelog/17534.txt b/.changelog/17534.txt new file mode 100644 index 00000000000..c3e39ab718c --- /dev/null +++ b/.changelog/17534.txt @@ -0,0 +1,3 @@ +```release-note:bug +resource/aws_lb_target_group: Use gRPC matcher when using gRPC protocol +``` diff --git a/aws/resource_aws_lb_target_group.go b/aws/resource_aws_lb_target_group.go index cfaf1bade91..57919277488 100644 --- a/aws/resource_aws_lb_target_group.go +++ b/aws/resource_aws_lb_target_group.go @@ -80,10 +80,20 @@ func resourceAwsLbTargetGroup() *schema.Resource { return strings.ToUpper(v.(string)) }, ValidateFunc: validation.StringInSlice([]string{ + "GRPC", "HTTP1", "HTTP2", - "GRPC", }, true), + DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool { + if d.Get("target_type").(string) == elbv2.TargetTypeEnumLambda { + return true + } + switch d.Get("protocol").(string) { + case elbv2.ProtocolEnumHttp, elbv2.ProtocolEnumHttps: + return false + } + return true + }, }, "vpc_id": { @@ -337,9 +347,16 @@ func resourceAwsLbTargetGroupCreate(d *schema.ResourceData, meta interface{}) er } m := healthCheck["matcher"].(string) + protocolVersion := d.Get("protocol_version").(string) if m != "" { - params.Matcher = &elbv2.Matcher{ - HttpCode: aws.String(m), + if protocolVersion == "GRPC" { + params.Matcher = &elbv2.Matcher{ + GrpcCode: aws.String(m), + } + } else { + params.Matcher = &elbv2.Matcher{ + HttpCode: aws.String(m), + } } } } @@ -416,10 +433,16 @@ func resourceAwsLbTargetGroupUpdate(d *schema.ResourceData, meta interface{}) er } healthCheckProtocol := healthCheck["protocol"].(string) - + protocolVersion := d.Get("protocol_version").(string) if healthCheckProtocol != elbv2.ProtocolEnumTcp && !d.IsNewResource() { - params.Matcher = &elbv2.Matcher{ - HttpCode: aws.String(healthCheck["matcher"].(string)), + if protocolVersion == "GRPC" { + params.Matcher = &elbv2.Matcher{ + GrpcCode: aws.String(healthCheck["matcher"].(string)), + } + } else { + params.Matcher = &elbv2.Matcher{ + HttpCode: aws.String(healthCheck["matcher"].(string)), + } } params.HealthCheckPath = aws.String(healthCheck["path"].(string)) params.HealthCheckIntervalSeconds = aws.Int64(int64(healthCheck["interval"].(int))) @@ -645,6 +668,9 @@ func flattenAwsLbTargetGroupResource(d *schema.ResourceData, meta interface{}, t if targetGroup.Matcher != nil && targetGroup.Matcher.HttpCode != nil { healthCheck["matcher"] = aws.StringValue(targetGroup.Matcher.HttpCode) } + if targetGroup.Matcher != nil && targetGroup.Matcher.GrpcCode != nil { + healthCheck["matcher"] = aws.StringValue(targetGroup.Matcher.GrpcCode) + } if v, _ := d.Get("target_type").(string); v != elbv2.TargetTypeEnumLambda { d.Set("vpc_id", targetGroup.VpcId) d.Set("port", targetGroup.Port) diff --git a/aws/resource_aws_lb_target_group_test.go b/aws/resource_aws_lb_target_group_test.go index 171b5897b25..b1ceba292d5 100644 --- a/aws/resource_aws_lb_target_group_test.go +++ b/aws/resource_aws_lb_target_group_test.go @@ -402,6 +402,60 @@ func TestAccAWSLBTargetGroup_Protocol_Tls(t *testing.T) { }) } +func TestAccAWSLBTargetGroup_ProtocolVersion_GRPC_HealthCheck(t *testing.T) { + var targetGroup1 elbv2.TargetGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lb_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshName: resourceName, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBTargetGroupConfig_GRPC_ProtocolVersion(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "health_check.#", "1"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.path", "/Test.Check/healthcheck"), + resource.TestCheckResourceAttr(resourceName, "health_check.0.matcher", "0-99"), + ), + }, + }, + }) +} + +func TestAccAWSLBTargetGroup_ProtocolVersion_HTTP_GRPC_Update(t *testing.T) { + var targetGroup1 elbv2.TargetGroup + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_lb_target_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSLBTargetGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSLBTargetGroupConfig_basic(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTPS"), + resource.TestCheckResourceAttr(resourceName, "protocol_version", "HTTP1"), + ), + }, + { + Config: testAccAWSLBTargetGroupConfig_GRPC_ProtocolVersion(rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSLBTargetGroupExists(resourceName, &targetGroup1), + resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "protocol_version", "GRPC"), + ), + }, + }, + }) +} + func TestAccAWSLBTargetGroup_networkLB_TargetGroupWithProxy(t *testing.T) { var confBefore, confAfter elbv2.TargetGroup targetGroupName := fmt.Sprintf("test-target-group-%s", acctest.RandString(10)) @@ -952,6 +1006,7 @@ func TestAccAWSLBTargetGroup_defaults_application(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "name", targetGroupName), resource.TestCheckResourceAttr(resourceName, "port", "443"), resource.TestCheckResourceAttr(resourceName, "protocol", "HTTP"), + resource.TestCheckResourceAttr(resourceName, "protocol_version", "HTTP1"), resource.TestCheckResourceAttrSet(resourceName, "vpc_id"), resource.TestCheckResourceAttr(resourceName, "deregistration_delay", "200"), resource.TestCheckResourceAttr(resourceName, "slow_start", "0"), @@ -1847,6 +1902,56 @@ resource "aws_vpc" "test" { `, targetGroupName) } +func testAccAWSLBTargetGroupConfig_GRPC_ProtocolVersion(targetGroupName string) string { + return fmt.Sprintf(` +resource "aws_lb_target_group" "test" { + name = "%s" + port = 80 + protocol = "HTTP" + protocol_version = "GRPC" + vpc_id = aws_vpc.test2.id + + deregistration_delay = 200 + + stickiness { + type = "lb_cookie" + cookie_duration = 10000 + } + + health_check { + path = "/Test.Check/healthcheck" + interval = 60 + port = 8080 + protocol = "HTTP" + timeout = 3 + healthy_threshold = 3 + unhealthy_threshold = 3 + matcher = "0-99" + } + + tags = { + Name = "TestAccAWSLBTargetGroup_basic" + } +} + +resource "aws_vpc" "test2" { + cidr_block = "10.10.0.0/16" + + tags = { + Name = "terraform-testacc-lb-target-group-basic-2" + } +} + +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + + tags = { + Name = "terraform-testacc-lb-target-group-basic" + } +} +`, targetGroupName) +} + func testAccAWSLBTargetGroupConfig_updatedVpc(targetGroupName string) string { return fmt.Sprintf(` resource "aws_lb_target_group" "test" { diff --git a/website/docs/r/lb_target_group.html.markdown b/website/docs/r/lb_target_group.html.markdown index 8e9a37e23f2..d7ead675b57 100644 --- a/website/docs/r/lb_target_group.html.markdown +++ b/website/docs/r/lb_target_group.html.markdown @@ -103,10 +103,11 @@ The underlying function is invoked when `target_type` is set to `lambda`. * `path` - (Required for HTTP/HTTPS ALB and HTTP NLB) The destination for the health check request. Applies to only HTTP/HTTPS. * `port` - (Optional) The port to use to connect with the target. Valid values are either ports 1-65535, or `traffic-port`. Defaults to `traffic-port`. * `protocol` - (Optional) The protocol to use to connect with the target. Defaults to `HTTP`. Not applicable when `target_type` is `lambda`. +* `protocol_version` - (Optional) The protocol version. Defaults to `HTTP1`. Specify GRPC to send requests to targets using GRPC, HTTP2 to send requests to targets using HTTP/2, HTTP1 to send requests to targets using HTTP/1.1. * `timeout` - (Optional) The amount of time, in seconds, during which no response means a failed health check. For Application Load Balancers, the range is 2 to 120 seconds, and the default is 5 seconds for the `instance` target type and 30 seconds for the `lambda` target type. For Network Load Balancers, you cannot set a custom value, and the default is 10 seconds for TCP and HTTPS health checks and 6 seconds for HTTP health checks. * `healthy_threshold` - (Optional) The number of consecutive health checks successes required before considering an unhealthy target healthy. Defaults to 3. * `unhealthy_threshold` - (Optional) The number of consecutive health check failures required before considering the target unhealthy . For Network Load Balancers, this value must be the same as the `healthy_threshold`. Defaults to 3. -* `matcher` (Required for HTTP/HTTPS ALB) The HTTP codes to use when checking for a successful response from a target. You can specify multiple values (for example, "200,202") or a range of values (for example, "200-299"). Applies to Application Load Balancers only (HTTP/HTTPS), not Network Load Balancers (TCP). +* `matcher` (Required for HTTP/HTTPS/GRPC ALB) The response codes to use when checking for a healthy responses from a target. You can specify multiple values (for example, "200,202" for HTTP(s) or "0,12" for GRPC) or a range of values (for example, "200-299" or "0-99"). Applies to Application Load Balancers only (HTTP/HTTPS/GRPC), not Network Load Balancers (TCP). ## Attributes Reference