diff --git a/aws/resource_aws_appmesh_route.go b/aws/resource_aws_appmesh_route.go index a8816cb322c..5419b31f7e9 100644 --- a/aws/resource_aws_appmesh_route.go +++ b/aws/resource_aws_appmesh_route.go @@ -61,12 +61,12 @@ func resourceAwsAppmeshRoute() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "http_route": { + "grpc_route": { Type: schema.TypeList, Optional: true, MinItems: 0, MaxItems: 1, - ConflictsWith: []string{"spec.0.tcp_route"}, + ConflictsWith: []string{"spec.0.http2_route", "spec.0.http_route", "spec.0.tcp_route"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "action": { @@ -108,7 +108,7 @@ func resourceAwsAppmeshRoute() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "header": { + "metadata": { Type: schema.TypeSet, Optional: true, MinItems: 0, @@ -184,22 +184,15 @@ func resourceAwsAppmeshRoute() *schema.Resource { }, }, - "method": { + "method_name": { Type: schema.TypeString, Optional: true, - ValidateFunc: validation.StringInSlice(appmesh.HttpMethod_Values(), false), + ValidateFunc: validation.StringLenBetween(0, 50), }, - "prefix": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), - }, - - "scheme": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(appmesh.HttpScheme_Values(), false), + "service_name": { + Type: schema.TypeString, + Optional: true, }, }, }, @@ -212,6 +205,14 @@ func resourceAwsAppmeshRoute() *schema.Resource { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "grpc_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + "http_retry_events": { Type: schema.TypeSet, Optional: true, @@ -260,6 +261,18 @@ func resourceAwsAppmeshRoute() *schema.Resource { }, }, + "http2_route": func() *schema.Schema { + schema := appmeshRouteHttpRouteSchema() + schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http_route", "spec.0.tcp_route"} + return schema + }(), + + "http_route": func() *schema.Schema { + schema := appmeshRouteHttpRouteSchema() + schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.tcp_route"} + return schema + }(), + "priority": { Type: schema.TypeInt, Optional: true, @@ -271,7 +284,7 @@ func resourceAwsAppmeshRoute() *schema.Resource { Optional: true, MinItems: 0, MaxItems: 1, - ConflictsWith: []string{"spec.0.http_route"}, + ConflictsWith: []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.http_route"}, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "action": { @@ -337,6 +350,207 @@ func resourceAwsAppmeshRoute() *schema.Resource { } } +// appmeshRouteHttpRouteSchema returns the schema for `http2_route` and `http_route` attributes. +func appmeshRouteHttpRouteSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + + "weight": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 100), + }, + }, + }, + }, + }, + }, + }, + + "match": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "invert": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + + "match": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + + "prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + + "range": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end": { + Type: schema.TypeInt, + Required: true, + }, + + "start": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + + "regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + + "suffix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, + + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 50), + }, + }, + }, + }, + + "method": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(appmesh.HttpMethod_Values(), false), + }, + + "prefix": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + }, + + "scheme": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(appmesh.HttpScheme_Values(), false), + }, + }, + }, + }, + + "retry_policy": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + + "max_retries": { + Type: schema.TypeInt, + Required: true, + }, + + "per_retry_timeout": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + + "value": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + + "tcp_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + Set: schema.HashString, + }, + }, + }, + }, + }, + }, + } +} + func resourceAwsAppmeshRouteCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).appmeshconn diff --git a/aws/resource_aws_appmesh_route_test.go b/aws/resource_aws_appmesh_route_test.go index 0d000192fd8..faf58bab1b3 100644 --- a/aws/resource_aws_appmesh_route_test.go +++ b/aws/resource_aws_appmesh_route_test.go @@ -100,6 +100,288 @@ func testSweepAppmeshRoutes(region string) error { return nil } +func testAccAwsAppmeshRoute_grpcRoute(t *testing.T) { + var r appmesh.RouteData + resourceName := "aws_appmesh_route.test" + meshName := acctest.RandomWithPrefix("tf-acc-test") + vrName := acctest.RandomWithPrefix("tf-acc-test") + vn1Name := acctest.RandomWithPrefix("tf-acc-test") + vn2Name := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsAppmeshRouteConfig_grpcRoute(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshRouteExists(resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.weighted_target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.metadata.#", "1"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.grpc_route.0.match.0.metadata.*", map[string]string{ + "invert": "false", + "match.#": "0", + "name": "X-Testing1", + }), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.method_name", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.#", "2"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.*", "deadline-exceeded"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.*", "resource-exhausted"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.*", "server-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.max_retries", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.0.unit", "s"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.0.value", "15"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.tcp_retry_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + testAccCheckResourceAttrAccountID(resourceName, "resource_owner"), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + Config: testAccAwsAppmeshRouteConfig_grpcRouteUpdated(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshRouteExists(resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.weighted_target.#", "2"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.metadata.#", "2"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.grpc_route.0.match.0.metadata.*", map[string]string{ + "invert": "true", + "match.#": "0", + "name": "X-Testing1", + }), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.grpc_route.0.match.0.metadata.*", map[string]string{ + "invert": "false", + "match.#": "1", + "match.0.range.#": "1", + "match.0.range.0.end": "7", + "match.0.range.0.start": "2", + "name": "X-Testing2", + }), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.method_name", "test"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", "test.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.*", "cancelled"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.#", "2"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.*", "gateway-error"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.*", "client-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.max_retries", "3"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.0.unit", "ms"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.0.value", "250000"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.tcp_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.tcp_retry_events.*", "connection-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + testAccCheckResourceAttrAccountID(resourceName, "resource_owner"), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + Config: testAccAwsAppmeshRouteConfig_grpcRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshRouteExists(resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.weighted_target.#", "2"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.metadata.#", "2"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.grpc_route.0.match.0.metadata.*", map[string]string{ + "invert": "true", + "match.#": "0", + "name": "X-Testing1", + }), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.grpc_route.0.match.0.metadata.*", map[string]string{ + "invert": "false", + "match.#": "1", + "match.0.range.#": "1", + "match.0.range.0.end": "7", + "match.0.range.0.start": "2", + "name": "X-Testing2", + }), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.method_name", "test"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", "test.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.grpc_retry_events.*", "cancelled"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.#", "2"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.*", "gateway-error"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.http_retry_events.*", "client-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.max_retries", "3"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.0.unit", "ms"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.per_retry_timeout.0.value", "250000"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.tcp_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.grpc_route.0.retry_policy.0.tcp_retry_events.*", "connection-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + testAccCheckResourceAttrAccountID(resourceName, "resource_owner"), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAwsAppmeshRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsAppmeshRoute_http2Route(t *testing.T) { + var r appmesh.RouteData + resourceName := "aws_appmesh_route.test" + meshName := acctest.RandomWithPrefix("tf-acc-test") + vrName := acctest.RandomWithPrefix("tf-acc-test") + vn1Name := acctest.RandomWithPrefix("tf-acc-test") + vn2Name := acctest.RandomWithPrefix("tf-acc-test") + rName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsAppmeshRouteConfig_http2Route(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshRouteExists(resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.weighted_target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.header.#", "1"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.http2_route.0.match.0.header.*", map[string]string{ + "invert": "false", + "match.#": "0", + "name": "X-Testing1", + }), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.method", "POST"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.scheme", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.http_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.http_retry_events.*", "server-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.max_retries", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.per_retry_timeout.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.per_retry_timeout.0.unit", "s"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.per_retry_timeout.0.value", "15"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.tcp_retry_events.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + testAccCheckResourceAttrAccountID(resourceName, "resource_owner"), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + Config: testAccAwsAppmeshRouteConfig_http2RouteUpdated(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshRouteExists(resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.weighted_target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.header.#", "2"), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.http2_route.0.match.0.header.*", map[string]string{ + "invert": "true", + "match.#": "0", + "name": "X-Testing1", + }), + tfawsresource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.http2_route.0.match.0.header.*", map[string]string{ + "invert": "false", + "match.#": "1", + "match.0.range.#": "1", + "match.0.range.0.end": "7", + "match.0.range.0.start": "2", + "name": "X-Testing2", + }), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.method", "PUT"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/path"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.scheme", "https"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.http_retry_events.#", "2"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.http_retry_events.*", "gateway-error"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.http_retry_events.*", "client-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.max_retries", "3"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.per_retry_timeout.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.per_retry_timeout.0.unit", "ms"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.per_retry_timeout.0.value", "250000"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.tcp_retry_events.#", "1"), + tfawsresource.TestCheckTypeSetElemAttr(resourceName, "spec.0.http2_route.0.retry_policy.0.tcp_retry_events.*", "connection-error"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + testAccCheckResourceAttrAccountID(resourceName, "resource_owner"), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAwsAppmeshRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccAwsAppmeshRoute_httpRoute(t *testing.T) { var r appmesh.RouteData resourceName := "aws_appmesh_route.test" @@ -123,6 +405,8 @@ func testAccAwsAppmeshRoute_httpRoute(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -150,6 +434,8 @@ func testAccAwsAppmeshRoute_httpRoute(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "2"), @@ -226,6 +512,8 @@ func testAccAwsAppmeshRoute_tcpRoute(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "1"), @@ -247,6 +535,8 @@ func testAccAwsAppmeshRoute_tcpRoute(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "1"), @@ -361,6 +651,8 @@ func testAccAwsAppmeshRoute_httpHeader(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -393,6 +685,8 @@ func testAccAwsAppmeshRoute_httpHeader(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -457,6 +751,8 @@ func testAccAwsAppmeshRoute_routePriority(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -484,6 +780,8 @@ func testAccAwsAppmeshRoute_routePriority(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -535,6 +833,8 @@ func testAccAwsAppmeshRoute_httpRetryPolicy(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -568,6 +868,8 @@ func testAccAwsAppmeshRoute_httpRetryPolicy(t *testing.T) { testAccCheckResourceAttrAccountID(resourceName, "mesh_owner"), resource.TestCheckResourceAttr(resourceName, "virtual_router_name", vrName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.#", "1"), @@ -667,7 +969,7 @@ func testAccCheckAppmeshRouteExists(name string, v *appmesh.RouteData) resource. } } -func testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name string) string { +func testAccAppmeshRouteConfigBase(meshName, vrName, vrProtocol, vn1Name, vn2Name string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q @@ -681,30 +983,321 @@ resource "aws_appmesh_virtual_router" "test" { listener { port_mapping { port = 8080 - protocol = "http" + protocol = %[3]q } } } } resource "aws_appmesh_virtual_node" "foo" { - name = %[3]q + name = %[4]q mesh_name = aws_appmesh_mesh.test.id spec {} } resource "aws_appmesh_virtual_node" "bar" { - name = %[4]q + name = %[5]q mesh_name = aws_appmesh_mesh.test.id spec {} } -`, meshName, vrName, vn1Name, vn2Name) +`, meshName, vrName, vrProtocol, vn1Name, vn2Name) +} + +func testAccAwsAppmeshRouteConfig_grpcRoute(meshName, vrName, vn1Name, vn2Name, rName string) string { + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + grpc_route { + match { + metadata { + name = "X-Testing1" + } + } + + retry_policy { + grpc_retry_events = [ + "deadline-exceeded", + "resource-exhausted", + ] + + http_retry_events = [ + "server-error", + ] + + max_retries = 1 + + per_retry_timeout { + unit = "s" + value = 15 + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.foo.name + weight = 100 + } + } + } + } +} +`, rName)) +} + +func testAccAwsAppmeshRouteConfig_grpcRouteUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + grpc_route { + match { + method_name = "test" + service_name = "test.local" + + metadata { + name = "X-Testing1" + invert = true + } + + metadata { + name = "X-Testing2" + invert = false + + match { + range { + start = 2 + end = 7 + } + } + } + } + + retry_policy { + grpc_retry_events = [ + "cancelled", + ] + + http_retry_events = [ + "client-error", + "gateway-error", + ] + + max_retries = 3 + + per_retry_timeout { + unit = "ms" + value = 250000 + } + + tcp_retry_events = [ + "connection-error", + ] + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.foo.name + weight = 90 + } + + weighted_target { + virtual_node = aws_appmesh_virtual_node.bar.name + weight = 10 + } + } + } + } +} +`, rName)) +} + +func testAccAwsAppmeshRouteConfig_grpcRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + grpc_route { + match { + method_name = "test" + service_name = "test.local" + + metadata { + name = "X-Testing1" + invert = true + } + + metadata { + name = "X-Testing2" + invert = false + + match { + range { + start = 2 + end = 7 + } + } + } + } + + retry_policy { + grpc_retry_events = [ + "cancelled", + ] + + http_retry_events = [ + "client-error", + "gateway-error", + ] + + max_retries = 3 + + per_retry_timeout { + unit = "ms" + value = 250000 + } + + tcp_retry_events = [ + "connection-error", + ] + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.foo.name + weight = 99 + } + + weighted_target { + virtual_node = aws_appmesh_virtual_node.bar.name + weight = 0 + } + } + } + } +} +`, rName)) +} + +func testAccAwsAppmeshRouteConfig_http2Route(meshName, vrName, vn1Name, vn2Name, rName string) string { + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + http2_route { + match { + prefix = "/" + method = "POST" + scheme = "http" + + header { + name = "X-Testing1" + } + } + + retry_policy { + http_retry_events = [ + "server-error", + ] + + max_retries = 1 + + per_retry_timeout { + unit = "s" + value = 15 + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.foo.name + weight = 100 + } + } + } + } +} +`, rName)) +} + +func testAccAwsAppmeshRouteConfig_http2RouteUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + http2_route { + match { + prefix = "/path" + method = "PUT" + scheme = "https" + + header { + name = "X-Testing1" + invert = true + } + + header { + name = "X-Testing2" + invert = false + + match { + range { + start = 2 + end = 7 + } + } + } + } + + retry_policy { + http_retry_events = [ + "client-error", + "gateway-error", + ] + + max_retries = 3 + + per_retry_timeout { + unit = "ms" + value = 250000 + } + + tcp_retry_events = [ + "connection-error", + ] + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.foo.name + weight = 100 + } + } + } + } +} +`, rName)) } func testAccAppmeshRouteConfig_httpRoute(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -729,7 +1322,7 @@ resource "aws_appmesh_route" "test" { } func testAccAppmeshRouteConfig_httpRouteUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -759,7 +1352,7 @@ resource "aws_appmesh_route" "test" { } func testAccAppmeshRouteConfig_httpRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -789,7 +1382,7 @@ resource "aws_appmesh_route" "test" { } func testAccAppmeshRouteConfig_tcpRoute(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -810,7 +1403,7 @@ resource "aws_appmesh_route" "test" { } func testAccAppmeshRouteConfig_tcpRouteUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -836,7 +1429,7 @@ resource "aws_appmesh_route" "test" { } func testAccAppmeshRouteConfig_tcpRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -862,7 +1455,7 @@ resource "aws_appmesh_route" "test" { } func testAccAppmeshRouteConfigWithTags(meshName, vrName, vn1Name, vn2Name, rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -892,7 +1485,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpHeader(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -923,7 +1516,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpHeaderUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -967,7 +1560,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_routePriority(meshName, vrName, vn1Name, vn2Name, rName string, priority int) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -994,7 +1587,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpRetryPolicy(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -1032,7 +1625,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpRetryPolicyUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, vn1Name, vn2Name), fmt.Sprintf(` + return composeConfig(testAccAppmeshRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id diff --git a/aws/resource_aws_appmesh_test.go b/aws/resource_aws_appmesh_test.go index 2a6563acafe..023035297cf 100644 --- a/aws/resource_aws_appmesh_test.go +++ b/aws/resource_aws_appmesh_test.go @@ -12,11 +12,13 @@ func TestAccAWSAppmesh_serial(t *testing.T) { "tags": testAccAwsAppmeshMesh_tags, }, "Route": { + "grpcRoute": testAccAwsAppmeshRoute_grpcRoute, + "http2Route": testAccAwsAppmeshRoute_http2Route, "httpHeader": testAccAwsAppmeshRoute_httpHeader, "httpRetryPolicy": testAccAwsAppmeshRoute_httpRetryPolicy, "httpRoute": testAccAwsAppmeshRoute_httpRoute, - "tcpRoute": testAccAwsAppmeshRoute_tcpRoute, "routePriority": testAccAwsAppmeshRoute_routePriority, + "tcpRoute": testAccAwsAppmeshRoute_tcpRoute, "tags": testAccAwsAppmeshRoute_tags, }, "VirtualNode": { diff --git a/aws/resource_aws_appmesh_virtual_node.go b/aws/resource_aws_appmesh_virtual_node.go index 74fe9f9f824..81e3c8ff556 100644 --- a/aws/resource_aws_appmesh_virtual_node.go +++ b/aws/resource_aws_appmesh_virtual_node.go @@ -131,16 +131,13 @@ func resourceAwsAppmeshVirtualNode() *schema.Resource { Type: schema.TypeInt, Optional: true, Computed: true, - ValidateFunc: validation.IntBetween(1, 65535), + ValidateFunc: validation.IsPortNumber, }, "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - appmesh.PortProtocolHttp, - appmesh.PortProtocolTcp, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.PortProtocol_Values(), false), }, "timeout_millis": { @@ -168,16 +165,13 @@ func resourceAwsAppmeshVirtualNode() *schema.Resource { "port": { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntBetween(1, 65535), + ValidateFunc: validation.IsPortNumber, }, "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - appmesh.PortProtocolHttp, - appmesh.PortProtocolTcp, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.PortProtocol_Values(), false), }, }, }, diff --git a/aws/resource_aws_appmesh_virtual_node_test.go b/aws/resource_aws_appmesh_virtual_node_test.go index 15c875ff21f..83a1fcc8774 100644 --- a/aws/resource_aws_appmesh_virtual_node_test.go +++ b/aws/resource_aws_appmesh_virtual_node_test.go @@ -214,12 +214,12 @@ func testAccAwsAppmeshVirtualNode_listenerHealthChecks(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.interval_millis", "5000"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.path", "/ping"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.port", "8080"), - resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.protocol", "http2"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.timeout_millis", "2000"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.health_check.0.unhealthy_threshold", "5"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.0.port", "8080"), - resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.0.protocol", "grpc"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.tls.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), @@ -934,11 +934,11 @@ resource "aws_appmesh_virtual_node" "test" { listener { port_mapping { port = 8080 - protocol = "http" + protocol = "grpc" } health_check { - protocol = "http" + protocol = "http2" path = "/ping" healthy_threshold = 3 unhealthy_threshold = 5 diff --git a/aws/resource_aws_appmesh_virtual_router.go b/aws/resource_aws_appmesh_virtual_router.go index e9082ae60c6..888b1ee7b0a 100644 --- a/aws/resource_aws_appmesh_virtual_router.go +++ b/aws/resource_aws_appmesh_virtual_router.go @@ -74,16 +74,13 @@ func resourceAwsAppmeshVirtualRouter() *schema.Resource { "port": { Type: schema.TypeInt, Required: true, - ValidateFunc: validation.IntBetween(1, 65535), + ValidateFunc: validation.IsPortNumber, }, "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - appmesh.PortProtocolHttp, - appmesh.PortProtocolTcp, - }, false), + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.PortProtocol_Values(), false), }, }, }, diff --git a/aws/structure.go b/aws/structure.go index 66167076138..58f3a43e30b 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -5366,183 +5366,357 @@ func expandAppmeshRouteSpec(vSpec []interface{}) *appmesh.RouteSpec { } mSpec := vSpec[0].(map[string]interface{}) + if vGrpcRoute, ok := mSpec["grpc_route"].([]interface{}); ok { + spec.GrpcRoute = expandAppmeshGrpcRoute(vGrpcRoute) + } + + if vHttp2Route, ok := mSpec["http2_route"].([]interface{}); ok { + spec.Http2Route = expandAppmeshHttpRoute(vHttp2Route) + } + + if vHttpRoute, ok := mSpec["http_route"].([]interface{}); ok { + spec.HttpRoute = expandAppmeshHttpRoute(vHttpRoute) + } + if vPriority, ok := mSpec["priority"].(int); ok && vPriority > 0 { spec.Priority = aws.Int64(int64(vPriority)) } - if vHttpRoute, ok := mSpec["http_route"].([]interface{}); ok && len(vHttpRoute) > 0 && vHttpRoute[0] != nil { - mHttpRoute := vHttpRoute[0].(map[string]interface{}) + if vTcpRoute, ok := mSpec["tcp_route"].([]interface{}); ok { + spec.TcpRoute = expandAppmeshTcpRoute(vTcpRoute) + } - spec.HttpRoute = &appmesh.HttpRoute{} + return spec +} - if vHttpRouteAction, ok := mHttpRoute["action"].([]interface{}); ok && len(vHttpRouteAction) > 0 && vHttpRouteAction[0] != nil { - mHttpRouteAction := vHttpRouteAction[0].(map[string]interface{}) +func expandAppmeshGrpcRoute(vGrpcRoute []interface{}) *appmesh.GrpcRoute { + if len(vGrpcRoute) == 0 || vGrpcRoute[0] == nil { + return nil + } - if vWeightedTargets, ok := mHttpRouteAction["weighted_target"].(*schema.Set); ok && vWeightedTargets.Len() > 0 { - weightedTargets := []*appmesh.WeightedTarget{} + mGrpcRoute := vGrpcRoute[0].(map[string]interface{}) - for _, vWeightedTarget := range vWeightedTargets.List() { - weightedTarget := &appmesh.WeightedTarget{} + grpcRoute := &appmesh.GrpcRoute{} - mWeightedTarget := vWeightedTarget.(map[string]interface{}) + if vGrpcRouteAction, ok := mGrpcRoute["action"].([]interface{}); ok && len(vGrpcRouteAction) > 0 && vGrpcRouteAction[0] != nil { + mGrpcRouteAction := vGrpcRouteAction[0].(map[string]interface{}) - if vVirtualNode, ok := mWeightedTarget["virtual_node"].(string); ok && vVirtualNode != "" { - weightedTarget.VirtualNode = aws.String(vVirtualNode) - } - if vWeight, ok := mWeightedTarget["weight"].(int); ok { - weightedTarget.Weight = aws.Int64(int64(vWeight)) - } + if vWeightedTargets, ok := mGrpcRouteAction["weighted_target"].(*schema.Set); ok && vWeightedTargets.Len() > 0 { + weightedTargets := []*appmesh.WeightedTarget{} - weightedTargets = append(weightedTargets, weightedTarget) - } + for _, vWeightedTarget := range vWeightedTargets.List() { + weightedTarget := &appmesh.WeightedTarget{} + + mWeightedTarget := vWeightedTarget.(map[string]interface{}) - spec.HttpRoute.Action = &appmesh.HttpRouteAction{ - WeightedTargets: weightedTargets, + if vVirtualNode, ok := mWeightedTarget["virtual_node"].(string); ok && vVirtualNode != "" { + weightedTarget.VirtualNode = aws.String(vVirtualNode) } + if vWeight, ok := mWeightedTarget["weight"].(int); ok { + weightedTarget.Weight = aws.Int64(int64(vWeight)) + } + + weightedTargets = append(weightedTargets, weightedTarget) + } + + grpcRoute.Action = &appmesh.GrpcRouteAction{ + WeightedTargets: weightedTargets, } } + } - if vHttpRouteMatch, ok := mHttpRoute["match"].([]interface{}); ok && len(vHttpRouteMatch) > 0 && vHttpRouteMatch[0] != nil { - httpRouteMatch := &appmesh.HttpRouteMatch{} + if vGrpcRouteMatch, ok := mGrpcRoute["match"].([]interface{}); ok && len(vGrpcRouteMatch) > 0 && vGrpcRouteMatch[0] != nil { + grpcRouteMatch := &appmesh.GrpcRouteMatch{} - mHttpRouteMatch := vHttpRouteMatch[0].(map[string]interface{}) + mGrpcRouteMatch := vGrpcRouteMatch[0].(map[string]interface{}) - if vMethod, ok := mHttpRouteMatch["method"].(string); ok && vMethod != "" { - httpRouteMatch.Method = aws.String(vMethod) - } - if vPrefix, ok := mHttpRouteMatch["prefix"].(string); ok && vPrefix != "" { - httpRouteMatch.Prefix = aws.String(vPrefix) - } - if vScheme, ok := mHttpRouteMatch["scheme"].(string); ok && vScheme != "" { - httpRouteMatch.Scheme = aws.String(vScheme) - } + if vMethodName, ok := mGrpcRouteMatch["method_name"].(string); ok && vMethodName != "" { + grpcRouteMatch.MethodName = aws.String(vMethodName) + } + if vServiceName, ok := mGrpcRouteMatch["service_name"].(string); ok && vServiceName != "" { + grpcRouteMatch.ServiceName = aws.String(vServiceName) + } + + if vGrpcRouteMetadatas, ok := mGrpcRouteMatch["metadata"].(*schema.Set); ok && vGrpcRouteMetadatas.Len() > 0 { + grpcRouteMetadatas := []*appmesh.GrpcRouteMetadata{} + + for _, vGrpcRouteMetadata := range vGrpcRouteMetadatas.List() { + grpcRouteMetadata := &appmesh.GrpcRouteMetadata{} - if vHttpRouteHeaders, ok := mHttpRouteMatch["header"].(*schema.Set); ok && vHttpRouteHeaders.Len() > 0 { - httpRouteHeaders := []*appmesh.HttpRouteHeader{} + mGrpcRouteMetadata := vGrpcRouteMetadata.(map[string]interface{}) + + if vInvert, ok := mGrpcRouteMetadata["invert"].(bool); ok { + grpcRouteMetadata.Invert = aws.Bool(vInvert) + } + if vName, ok := mGrpcRouteMetadata["name"].(string); ok && vName != "" { + grpcRouteMetadata.Name = aws.String(vName) + } - for _, vHttpRouteHeader := range vHttpRouteHeaders.List() { - httpRouteHeader := &appmesh.HttpRouteHeader{} + if vMatch, ok := mGrpcRouteMetadata["match"].([]interface{}); ok && len(vMatch) > 0 && vMatch[0] != nil { + grpcRouteMetadata.Match = &appmesh.GrpcRouteMetadataMatchMethod{} - mHttpRouteHeader := vHttpRouteHeader.(map[string]interface{}) + mMatch := vMatch[0].(map[string]interface{}) - if vInvert, ok := mHttpRouteHeader["invert"].(bool); ok { - httpRouteHeader.Invert = aws.Bool(vInvert) + if vExact, ok := mMatch["exact"].(string); ok && vExact != "" { + grpcRouteMetadata.Match.Exact = aws.String(vExact) } - if vName, ok := mHttpRouteHeader["name"].(string); ok && vName != "" { - httpRouteHeader.Name = aws.String(vName) + if vPrefix, ok := mMatch["prefix"].(string); ok && vPrefix != "" { + grpcRouteMetadata.Match.Prefix = aws.String(vPrefix) + } + if vRegex, ok := mMatch["regex"].(string); ok && vRegex != "" { + grpcRouteMetadata.Match.Regex = aws.String(vRegex) + } + if vSuffix, ok := mMatch["suffix"].(string); ok && vSuffix != "" { + grpcRouteMetadata.Match.Suffix = aws.String(vSuffix) } - if vMatch, ok := mHttpRouteHeader["match"].([]interface{}); ok && len(vMatch) > 0 && vMatch[0] != nil { - httpRouteHeader.Match = &appmesh.HeaderMatchMethod{} + if vRange, ok := mMatch["range"].([]interface{}); ok && len(vRange) > 0 && vRange[0] != nil { + grpcRouteMetadata.Match.Range = &appmesh.MatchRange{} - mMatch := vMatch[0].(map[string]interface{}) + mRange := vRange[0].(map[string]interface{}) - if vExact, ok := mMatch["exact"].(string); ok && vExact != "" { - httpRouteHeader.Match.Exact = aws.String(vExact) - } - if vPrefix, ok := mMatch["prefix"].(string); ok && vPrefix != "" { - httpRouteHeader.Match.Prefix = aws.String(vPrefix) + if vEnd, ok := mRange["end"].(int); ok && vEnd > 0 { + grpcRouteMetadata.Match.Range.End = aws.Int64(int64(vEnd)) } - if vRegex, ok := mMatch["regex"].(string); ok && vRegex != "" { - httpRouteHeader.Match.Regex = aws.String(vRegex) - } - if vSuffix, ok := mMatch["suffix"].(string); ok && vSuffix != "" { - httpRouteHeader.Match.Suffix = aws.String(vSuffix) + if vStart, ok := mRange["start"].(int); ok && vStart > 0 { + grpcRouteMetadata.Match.Range.Start = aws.Int64(int64(vStart)) } + } + } - if vRange, ok := mMatch["range"].([]interface{}); ok && len(vRange) > 0 && vRange[0] != nil { - httpRouteHeader.Match.Range = &appmesh.MatchRange{} + grpcRouteMetadatas = append(grpcRouteMetadatas, grpcRouteMetadata) + } - mRange := vRange[0].(map[string]interface{}) + grpcRouteMatch.Metadata = grpcRouteMetadatas + } - if vEnd, ok := mRange["end"].(int); ok && vEnd > 0 { - httpRouteHeader.Match.Range.End = aws.Int64(int64(vEnd)) - } - if vStart, ok := mRange["start"].(int); ok && vStart > 0 { - httpRouteHeader.Match.Range.Start = aws.Int64(int64(vStart)) - } - } - } + grpcRoute.Match = grpcRouteMatch + } - httpRouteHeaders = append(httpRouteHeaders, httpRouteHeader) - } + if vGrpcRetryPolicy, ok := mGrpcRoute["retry_policy"].([]interface{}); ok && len(vGrpcRetryPolicy) > 0 && vGrpcRetryPolicy[0] != nil { + grpcRetryPolicy := &appmesh.GrpcRetryPolicy{} - httpRouteMatch.Headers = httpRouteHeaders - } + mGrpcRetryPolicy := vGrpcRetryPolicy[0].(map[string]interface{}) + + if vMaxRetries, ok := mGrpcRetryPolicy["max_retries"].(int); ok && vMaxRetries > 0 { + grpcRetryPolicy.MaxRetries = aws.Int64(int64(vMaxRetries)) + } - spec.HttpRoute.Match = httpRouteMatch + if vGrpcRetryEvents, ok := mGrpcRetryPolicy["grpc_retry_events"].(*schema.Set); ok && vGrpcRetryEvents.Len() > 0 { + grpcRetryPolicy.GrpcRetryEvents = expandStringSet(vGrpcRetryEvents) } - if vHttpRetryPolicy, ok := mHttpRoute["retry_policy"].([]interface{}); ok && len(vHttpRetryPolicy) > 0 && vHttpRetryPolicy[0] != nil { - httpRetryPolicy := &appmesh.HttpRetryPolicy{} + if vHttpRetryEvents, ok := mGrpcRetryPolicy["http_retry_events"].(*schema.Set); ok && vHttpRetryEvents.Len() > 0 { + grpcRetryPolicy.HttpRetryEvents = expandStringSet(vHttpRetryEvents) + } - mHttpRetryPolicy := vHttpRetryPolicy[0].(map[string]interface{}) + if vPerRetryTimeout, ok := mGrpcRetryPolicy["per_retry_timeout"].([]interface{}); ok && len(vPerRetryTimeout) > 0 && vPerRetryTimeout[0] != nil { + perRetryTimeout := &appmesh.Duration{} - if vMaxRetries, ok := mHttpRetryPolicy["max_retries"].(int); ok && vMaxRetries > 0 { - httpRetryPolicy.MaxRetries = aws.Int64(int64(vMaxRetries)) - } + mPerRetryTimeout := vPerRetryTimeout[0].(map[string]interface{}) - if vHttpRetryEvents, ok := mHttpRetryPolicy["http_retry_events"].(*schema.Set); ok && vHttpRetryEvents.Len() > 0 { - httpRetryPolicy.HttpRetryEvents = expandStringSet(vHttpRetryEvents) + if vUnit, ok := mPerRetryTimeout["unit"].(string); ok && vUnit != "" { + perRetryTimeout.Unit = aws.String(vUnit) + } + if vValue, ok := mPerRetryTimeout["value"].(int); ok && vValue > 0 { + perRetryTimeout.Value = aws.Int64(int64(vValue)) } - if vPerRetryTimeout, ok := mHttpRetryPolicy["per_retry_timeout"].([]interface{}); ok && len(vPerRetryTimeout) > 0 && vPerRetryTimeout[0] != nil { - perRetryTimeout := &appmesh.Duration{} + grpcRetryPolicy.PerRetryTimeout = perRetryTimeout + } + + if vTcpRetryEvents, ok := mGrpcRetryPolicy["tcp_retry_events"].(*schema.Set); ok && vTcpRetryEvents.Len() > 0 { + grpcRetryPolicy.TcpRetryEvents = expandStringSet(vTcpRetryEvents) + } + + grpcRoute.RetryPolicy = grpcRetryPolicy + } + + return grpcRoute +} + +func expandAppmeshHttpRoute(vHttpRoute []interface{}) *appmesh.HttpRoute { + if len(vHttpRoute) == 0 || vHttpRoute[0] == nil { + return nil + } + + mHttpRoute := vHttpRoute[0].(map[string]interface{}) + + httpRoute := &appmesh.HttpRoute{} - mPerRetryTimeout := vPerRetryTimeout[0].(map[string]interface{}) + if vHttpRouteAction, ok := mHttpRoute["action"].([]interface{}); ok && len(vHttpRouteAction) > 0 && vHttpRouteAction[0] != nil { + mHttpRouteAction := vHttpRouteAction[0].(map[string]interface{}) - if vUnit, ok := mPerRetryTimeout["unit"].(string); ok && vUnit != "" { - perRetryTimeout.Unit = aws.String(vUnit) + if vWeightedTargets, ok := mHttpRouteAction["weighted_target"].(*schema.Set); ok && vWeightedTargets.Len() > 0 { + weightedTargets := []*appmesh.WeightedTarget{} + + for _, vWeightedTarget := range vWeightedTargets.List() { + weightedTarget := &appmesh.WeightedTarget{} + + mWeightedTarget := vWeightedTarget.(map[string]interface{}) + + if vVirtualNode, ok := mWeightedTarget["virtual_node"].(string); ok && vVirtualNode != "" { + weightedTarget.VirtualNode = aws.String(vVirtualNode) } - if vValue, ok := mPerRetryTimeout["value"].(int); ok && vValue > 0 { - perRetryTimeout.Value = aws.Int64(int64(vValue)) + if vWeight, ok := mWeightedTarget["weight"].(int); ok { + weightedTarget.Weight = aws.Int64(int64(vWeight)) } - httpRetryPolicy.PerRetryTimeout = perRetryTimeout + weightedTargets = append(weightedTargets, weightedTarget) } - if vTcpRetryEvents, ok := mHttpRetryPolicy["tcp_retry_events"].(*schema.Set); ok && vTcpRetryEvents.Len() > 0 { - httpRetryPolicy.TcpRetryEvents = expandStringSet(vTcpRetryEvents) + httpRoute.Action = &appmesh.HttpRouteAction{ + WeightedTargets: weightedTargets, } - - spec.HttpRoute.RetryPolicy = httpRetryPolicy } } - if vTcpRoute, ok := mSpec["tcp_route"].([]interface{}); ok && len(vTcpRoute) > 0 && vTcpRoute[0] != nil { - mTcpRoute := vTcpRoute[0].(map[string]interface{}) + if vHttpRouteMatch, ok := mHttpRoute["match"].([]interface{}); ok && len(vHttpRouteMatch) > 0 && vHttpRouteMatch[0] != nil { + httpRouteMatch := &appmesh.HttpRouteMatch{} + + mHttpRouteMatch := vHttpRouteMatch[0].(map[string]interface{}) + + if vMethod, ok := mHttpRouteMatch["method"].(string); ok && vMethod != "" { + httpRouteMatch.Method = aws.String(vMethod) + } + if vPrefix, ok := mHttpRouteMatch["prefix"].(string); ok && vPrefix != "" { + httpRouteMatch.Prefix = aws.String(vPrefix) + } + if vScheme, ok := mHttpRouteMatch["scheme"].(string); ok && vScheme != "" { + httpRouteMatch.Scheme = aws.String(vScheme) + } - spec.TcpRoute = &appmesh.TcpRoute{} + if vHttpRouteHeaders, ok := mHttpRouteMatch["header"].(*schema.Set); ok && vHttpRouteHeaders.Len() > 0 { + httpRouteHeaders := []*appmesh.HttpRouteHeader{} - if vTcpRouteAction, ok := mTcpRoute["action"].([]interface{}); ok && len(vTcpRouteAction) > 0 && vTcpRouteAction[0] != nil { - mTcpRouteAction := vTcpRouteAction[0].(map[string]interface{}) + for _, vHttpRouteHeader := range vHttpRouteHeaders.List() { + httpRouteHeader := &appmesh.HttpRouteHeader{} - if vWeightedTargets, ok := mTcpRouteAction["weighted_target"].(*schema.Set); ok && vWeightedTargets.Len() > 0 { - weightedTargets := []*appmesh.WeightedTarget{} + mHttpRouteHeader := vHttpRouteHeader.(map[string]interface{}) + + if vInvert, ok := mHttpRouteHeader["invert"].(bool); ok { + httpRouteHeader.Invert = aws.Bool(vInvert) + } + if vName, ok := mHttpRouteHeader["name"].(string); ok && vName != "" { + httpRouteHeader.Name = aws.String(vName) + } - for _, vWeightedTarget := range vWeightedTargets.List() { - weightedTarget := &appmesh.WeightedTarget{} + if vMatch, ok := mHttpRouteHeader["match"].([]interface{}); ok && len(vMatch) > 0 && vMatch[0] != nil { + httpRouteHeader.Match = &appmesh.HeaderMatchMethod{} - mWeightedTarget := vWeightedTarget.(map[string]interface{}) + mMatch := vMatch[0].(map[string]interface{}) - if vVirtualNode, ok := mWeightedTarget["virtual_node"].(string); ok && vVirtualNode != "" { - weightedTarget.VirtualNode = aws.String(vVirtualNode) + if vExact, ok := mMatch["exact"].(string); ok && vExact != "" { + httpRouteHeader.Match.Exact = aws.String(vExact) } - if vWeight, ok := mWeightedTarget["weight"].(int); ok { - weightedTarget.Weight = aws.Int64(int64(vWeight)) + if vPrefix, ok := mMatch["prefix"].(string); ok && vPrefix != "" { + httpRouteHeader.Match.Prefix = aws.String(vPrefix) } + if vRegex, ok := mMatch["regex"].(string); ok && vRegex != "" { + httpRouteHeader.Match.Regex = aws.String(vRegex) + } + if vSuffix, ok := mMatch["suffix"].(string); ok && vSuffix != "" { + httpRouteHeader.Match.Suffix = aws.String(vSuffix) + } + + if vRange, ok := mMatch["range"].([]interface{}); ok && len(vRange) > 0 && vRange[0] != nil { + httpRouteHeader.Match.Range = &appmesh.MatchRange{} - weightedTargets = append(weightedTargets, weightedTarget) + mRange := vRange[0].(map[string]interface{}) + + if vEnd, ok := mRange["end"].(int); ok && vEnd > 0 { + httpRouteHeader.Match.Range.End = aws.Int64(int64(vEnd)) + } + if vStart, ok := mRange["start"].(int); ok && vStart > 0 { + httpRouteHeader.Match.Range.Start = aws.Int64(int64(vStart)) + } + } } - spec.TcpRoute.Action = &appmesh.TcpRouteAction{ - WeightedTargets: weightedTargets, + httpRouteHeaders = append(httpRouteHeaders, httpRouteHeader) + } + + httpRouteMatch.Headers = httpRouteHeaders + } + + httpRoute.Match = httpRouteMatch + } + + if vHttpRetryPolicy, ok := mHttpRoute["retry_policy"].([]interface{}); ok && len(vHttpRetryPolicy) > 0 && vHttpRetryPolicy[0] != nil { + httpRetryPolicy := &appmesh.HttpRetryPolicy{} + + mHttpRetryPolicy := vHttpRetryPolicy[0].(map[string]interface{}) + + if vMaxRetries, ok := mHttpRetryPolicy["max_retries"].(int); ok && vMaxRetries > 0 { + httpRetryPolicy.MaxRetries = aws.Int64(int64(vMaxRetries)) + } + + if vHttpRetryEvents, ok := mHttpRetryPolicy["http_retry_events"].(*schema.Set); ok && vHttpRetryEvents.Len() > 0 { + httpRetryPolicy.HttpRetryEvents = expandStringSet(vHttpRetryEvents) + } + + if vPerRetryTimeout, ok := mHttpRetryPolicy["per_retry_timeout"].([]interface{}); ok && len(vPerRetryTimeout) > 0 && vPerRetryTimeout[0] != nil { + perRetryTimeout := &appmesh.Duration{} + + mPerRetryTimeout := vPerRetryTimeout[0].(map[string]interface{}) + + if vUnit, ok := mPerRetryTimeout["unit"].(string); ok && vUnit != "" { + perRetryTimeout.Unit = aws.String(vUnit) + } + if vValue, ok := mPerRetryTimeout["value"].(int); ok && vValue > 0 { + perRetryTimeout.Value = aws.Int64(int64(vValue)) + } + + httpRetryPolicy.PerRetryTimeout = perRetryTimeout + } + + if vTcpRetryEvents, ok := mHttpRetryPolicy["tcp_retry_events"].(*schema.Set); ok && vTcpRetryEvents.Len() > 0 { + httpRetryPolicy.TcpRetryEvents = expandStringSet(vTcpRetryEvents) + } + + httpRoute.RetryPolicy = httpRetryPolicy + } + + return httpRoute +} + +func expandAppmeshTcpRoute(vTcpRoute []interface{}) *appmesh.TcpRoute { + if len(vTcpRoute) == 0 || vTcpRoute[0] == nil { + return nil + } + + mTcpRoute := vTcpRoute[0].(map[string]interface{}) + + tcpRoute := &appmesh.TcpRoute{} + + if vTcpRouteAction, ok := mTcpRoute["action"].([]interface{}); ok && len(vTcpRouteAction) > 0 && vTcpRouteAction[0] != nil { + mTcpRouteAction := vTcpRouteAction[0].(map[string]interface{}) + + if vWeightedTargets, ok := mTcpRouteAction["weighted_target"].(*schema.Set); ok && vWeightedTargets.Len() > 0 { + weightedTargets := []*appmesh.WeightedTarget{} + + for _, vWeightedTarget := range vWeightedTargets.List() { + weightedTarget := &appmesh.WeightedTarget{} + + mWeightedTarget := vWeightedTarget.(map[string]interface{}) + + if vVirtualNode, ok := mWeightedTarget["virtual_node"].(string); ok && vVirtualNode != "" { + weightedTarget.VirtualNode = aws.String(vVirtualNode) + } + if vWeight, ok := mWeightedTarget["weight"].(int); ok { + weightedTarget.Weight = aws.Int64(int64(vWeight)) } + + weightedTargets = append(weightedTargets, weightedTarget) + } + + tcpRoute.Action = &appmesh.TcpRouteAction{ + WeightedTargets: weightedTargets, } } } - return spec + return tcpRoute } func flattenAppmeshRouteSpec(spec *appmesh.RouteSpec) []interface{} { @@ -5551,125 +5725,229 @@ func flattenAppmeshRouteSpec(spec *appmesh.RouteSpec) []interface{} { } mSpec := map[string]interface{}{ - "priority": int(aws.Int64Value(spec.Priority)), + "grpc_route": flattenAppmeshGrpcRoute(spec.GrpcRoute), + "http2_route": flattenAppmeshHttpRoute(spec.Http2Route), + "http_route": flattenAppmeshHttpRoute(spec.HttpRoute), + "priority": int(aws.Int64Value(spec.Priority)), + "tcp_route": flattenAppmeshTcpRoute(spec.TcpRoute), } - if httpRoute := spec.HttpRoute; httpRoute != nil { - mHttpRoute := map[string]interface{}{} + return []interface{}{mSpec} +} + +func flattenAppmeshGrpcRoute(grpcRoute *appmesh.GrpcRoute) []interface{} { + if grpcRoute == nil { + return []interface{}{} + } - if action := httpRoute.Action; action != nil { - if weightedTargets := action.WeightedTargets; weightedTargets != nil { - vWeightedTargets := []interface{}{} + mGrpcRoute := map[string]interface{}{} - for _, weightedTarget := range weightedTargets { - mWeightedTarget := map[string]interface{}{ - "virtual_node": aws.StringValue(weightedTarget.VirtualNode), - "weight": int(aws.Int64Value(weightedTarget.Weight)), - } + if action := grpcRoute.Action; action != nil { + if weightedTargets := action.WeightedTargets; weightedTargets != nil { + vWeightedTargets := []interface{}{} - vWeightedTargets = append(vWeightedTargets, mWeightedTarget) + for _, weightedTarget := range weightedTargets { + mWeightedTarget := map[string]interface{}{ + "virtual_node": aws.StringValue(weightedTarget.VirtualNode), + "weight": int(aws.Int64Value(weightedTarget.Weight)), } - mHttpRoute["action"] = []interface{}{ - map[string]interface{}{ - "weighted_target": vWeightedTargets, - }, - } + vWeightedTargets = append(vWeightedTargets, mWeightedTarget) + } + + mGrpcRoute["action"] = []interface{}{ + map[string]interface{}{ + "weighted_target": vWeightedTargets, + }, } } + } - if httpRouteMatch := httpRoute.Match; httpRouteMatch != nil { - vHttpRouteHeaders := []interface{}{} + if grpcRouteMatch := grpcRoute.Match; grpcRouteMatch != nil { + vGrpcRouteMetadatas := []interface{}{} - for _, httpRouteHeader := range httpRouteMatch.Headers { - mHttpRouteHeader := map[string]interface{}{ - "invert": aws.BoolValue(httpRouteHeader.Invert), - "name": aws.StringValue(httpRouteHeader.Name), + for _, grpcRouteMetadata := range grpcRouteMatch.Metadata { + mGrpcRouteMetadata := map[string]interface{}{ + "invert": aws.BoolValue(grpcRouteMetadata.Invert), + "name": aws.StringValue(grpcRouteMetadata.Name), + } + + if match := grpcRouteMetadata.Match; match != nil { + mMatch := map[string]interface{}{ + "exact": aws.StringValue(match.Exact), + "prefix": aws.StringValue(match.Prefix), + "regex": aws.StringValue(match.Regex), + "suffix": aws.StringValue(match.Suffix), } - if match := httpRouteHeader.Match; match != nil { - mMatch := map[string]interface{}{ - "exact": aws.StringValue(match.Exact), - "prefix": aws.StringValue(match.Prefix), - "regex": aws.StringValue(match.Regex), - "suffix": aws.StringValue(match.Suffix), + if r := match.Range; r != nil { + mRange := map[string]interface{}{ + "end": int(aws.Int64Value(r.End)), + "start": int(aws.Int64Value(r.Start)), } - if r := match.Range; r != nil { - mRange := map[string]interface{}{ - "end": int(aws.Int64Value(r.End)), - "start": int(aws.Int64Value(r.Start)), - } + mMatch["range"] = []interface{}{mRange} + } - mMatch["range"] = []interface{}{mRange} - } + mGrpcRouteMetadata["match"] = []interface{}{mMatch} + } - mHttpRouteHeader["match"] = []interface{}{mMatch} + vGrpcRouteMetadatas = append(vGrpcRouteMetadatas, mGrpcRouteMetadata) + } + + mGrpcRoute["match"] = []interface{}{ + map[string]interface{}{ + "metadata": vGrpcRouteMetadatas, + "method_name": aws.StringValue(grpcRouteMatch.MethodName), + "service_name": aws.StringValue(grpcRouteMatch.ServiceName), + }, + } + } + + if grpcRetryPolicy := grpcRoute.RetryPolicy; grpcRetryPolicy != nil { + mGrpcRetryPolicy := map[string]interface{}{ + "grpc_retry_events": flattenStringSet(grpcRetryPolicy.GrpcRetryEvents), + "http_retry_events": flattenStringSet(grpcRetryPolicy.HttpRetryEvents), + "max_retries": int(aws.Int64Value(grpcRetryPolicy.MaxRetries)), + "tcp_retry_events": flattenStringSet(grpcRetryPolicy.TcpRetryEvents), + } + + if perRetryTimeout := grpcRetryPolicy.PerRetryTimeout; perRetryTimeout != nil { + mPerRetryTimeout := map[string]interface{}{ + "unit": aws.StringValue(perRetryTimeout.Unit), + "value": int(aws.Int64Value(perRetryTimeout.Value)), + } + + mGrpcRetryPolicy["per_retry_timeout"] = []interface{}{mPerRetryTimeout} + } + + mGrpcRoute["retry_policy"] = []interface{}{mGrpcRetryPolicy} + } + + return []interface{}{mGrpcRoute} +} + +func flattenAppmeshHttpRoute(httpRoute *appmesh.HttpRoute) []interface{} { + if httpRoute == nil { + return []interface{}{} + } + + mHttpRoute := map[string]interface{}{} + + if action := httpRoute.Action; action != nil { + if weightedTargets := action.WeightedTargets; weightedTargets != nil { + vWeightedTargets := []interface{}{} + + for _, weightedTarget := range weightedTargets { + mWeightedTarget := map[string]interface{}{ + "virtual_node": aws.StringValue(weightedTarget.VirtualNode), + "weight": int(aws.Int64Value(weightedTarget.Weight)), } - vHttpRouteHeaders = append(vHttpRouteHeaders, mHttpRouteHeader) + vWeightedTargets = append(vWeightedTargets, mWeightedTarget) } - mHttpRoute["match"] = []interface{}{ + mHttpRoute["action"] = []interface{}{ map[string]interface{}{ - "header": vHttpRouteHeaders, - "method": aws.StringValue(httpRouteMatch.Method), - "prefix": aws.StringValue(httpRouteMatch.Prefix), - "scheme": aws.StringValue(httpRouteMatch.Scheme), + "weighted_target": vWeightedTargets, }, } } + } + + if httpRouteMatch := httpRoute.Match; httpRouteMatch != nil { + vHttpRouteHeaders := []interface{}{} - if httpRetryPolicy := httpRoute.RetryPolicy; httpRetryPolicy != nil { - mHttpRetryPolicy := map[string]interface{}{ - "http_retry_events": flattenStringSet(httpRetryPolicy.HttpRetryEvents), - "max_retries": int(aws.Int64Value(httpRetryPolicy.MaxRetries)), - "tcp_retry_events": flattenStringSet(httpRetryPolicy.TcpRetryEvents), + for _, httpRouteHeader := range httpRouteMatch.Headers { + mHttpRouteHeader := map[string]interface{}{ + "invert": aws.BoolValue(httpRouteHeader.Invert), + "name": aws.StringValue(httpRouteHeader.Name), } - if perRetryTimeout := httpRetryPolicy.PerRetryTimeout; perRetryTimeout != nil { - mPerRetryTimeout := map[string]interface{}{ - "unit": aws.StringValue(perRetryTimeout.Unit), - "value": int(aws.Int64Value(perRetryTimeout.Value)), + if match := httpRouteHeader.Match; match != nil { + mMatch := map[string]interface{}{ + "exact": aws.StringValue(match.Exact), + "prefix": aws.StringValue(match.Prefix), + "regex": aws.StringValue(match.Regex), + "suffix": aws.StringValue(match.Suffix), } - mHttpRetryPolicy["per_retry_timeout"] = []interface{}{mPerRetryTimeout} + if r := match.Range; r != nil { + mRange := map[string]interface{}{ + "end": int(aws.Int64Value(r.End)), + "start": int(aws.Int64Value(r.Start)), + } + + mMatch["range"] = []interface{}{mRange} + } + + mHttpRouteHeader["match"] = []interface{}{mMatch} } - mHttpRoute["retry_policy"] = []interface{}{mHttpRetryPolicy} + vHttpRouteHeaders = append(vHttpRouteHeaders, mHttpRouteHeader) } - mSpec["http_route"] = []interface{}{mHttpRoute} + mHttpRoute["match"] = []interface{}{ + map[string]interface{}{ + "header": vHttpRouteHeaders, + "method": aws.StringValue(httpRouteMatch.Method), + "prefix": aws.StringValue(httpRouteMatch.Prefix), + "scheme": aws.StringValue(httpRouteMatch.Scheme), + }, + } } - if tcpRoute := spec.TcpRoute; tcpRoute != nil { - mTcpRoute := map[string]interface{}{} + if httpRetryPolicy := httpRoute.RetryPolicy; httpRetryPolicy != nil { + mHttpRetryPolicy := map[string]interface{}{ + "http_retry_events": flattenStringSet(httpRetryPolicy.HttpRetryEvents), + "max_retries": int(aws.Int64Value(httpRetryPolicy.MaxRetries)), + "tcp_retry_events": flattenStringSet(httpRetryPolicy.TcpRetryEvents), + } - if action := tcpRoute.Action; action != nil { - if weightedTargets := action.WeightedTargets; weightedTargets != nil { - vWeightedTargets := []interface{}{} + if perRetryTimeout := httpRetryPolicy.PerRetryTimeout; perRetryTimeout != nil { + mPerRetryTimeout := map[string]interface{}{ + "unit": aws.StringValue(perRetryTimeout.Unit), + "value": int(aws.Int64Value(perRetryTimeout.Value)), + } - for _, weightedTarget := range weightedTargets { - mWeightedTarget := map[string]interface{}{ - "virtual_node": aws.StringValue(weightedTarget.VirtualNode), - "weight": int(aws.Int64Value(weightedTarget.Weight)), - } + mHttpRetryPolicy["per_retry_timeout"] = []interface{}{mPerRetryTimeout} + } - vWeightedTargets = append(vWeightedTargets, mWeightedTarget) - } + mHttpRoute["retry_policy"] = []interface{}{mHttpRetryPolicy} + } - mTcpRoute["action"] = []interface{}{ - map[string]interface{}{ - "weighted_target": vWeightedTargets, - }, + return []interface{}{mHttpRoute} +} + +func flattenAppmeshTcpRoute(tcpRoute *appmesh.TcpRoute) []interface{} { + if tcpRoute == nil { + return []interface{}{} + } + + mTcpRoute := map[string]interface{}{} + + if action := tcpRoute.Action; action != nil { + if weightedTargets := action.WeightedTargets; weightedTargets != nil { + vWeightedTargets := []interface{}{} + + for _, weightedTarget := range weightedTargets { + mWeightedTarget := map[string]interface{}{ + "virtual_node": aws.StringValue(weightedTarget.VirtualNode), + "weight": int(aws.Int64Value(weightedTarget.Weight)), } + + vWeightedTargets = append(vWeightedTargets, mWeightedTarget) } - } - mSpec["tcp_route"] = []interface{}{mTcpRoute} + mTcpRoute["action"] = []interface{}{ + map[string]interface{}{ + "weighted_target": vWeightedTargets, + }, + } + } } - return []interface{}{mSpec} + return []interface{}{mTcpRoute} } func expandRoute53ResolverEndpointIpAddresses(vIpAddresses *schema.Set) []*route53resolver.IpAddressRequest { diff --git a/website/docs/r/appmesh_route.html.markdown b/website/docs/r/appmesh_route.html.markdown index 3cf75f3c08c..19fc844b79e 100644 --- a/website/docs/r/appmesh_route.html.markdown +++ b/website/docs/r/appmesh_route.html.markdown @@ -148,12 +148,20 @@ The following arguments are supported: The `spec` object supports the following: +* `grpc_route` - (Optional) The gRPC routing information for the route. +* `http2_route` - (Optional) The HTTP/2 routing information for the route. * `http_route` - (Optional) The HTTP routing information for the route. * `priority` - (Optional) The priority for the route, between `0` and `1000`. Routes are matched based on the specified value, where `0` is the highest priority. * `tcp_route` - (Optional) The TCP routing information for the route. -The `http_route` object supports the following: +The `grpc_route` object supports the following: + +* `action` - (Required) The action to take if a match is determined. +* `match` - (Required) The criteria for determining an gRPC request match. +* `rety_policy` - (Optional) The retry policy. + +The `http2_route` and `http_route` objects supports the following: * `action` - (Required) The action to take if a match is determined. * `match` - (Required) The criteria for determining an HTTP request match. @@ -168,7 +176,37 @@ The `action` object supports the following: * `weighted_target` - (Required) The targets that traffic is routed to when a request matches the route. You can specify one or more targets and their relative weights with which to distribute traffic. -The `http_route`'s `match` object supports the following: +The `grpc_route`'s `match` object supports the following: + +* `metadata` - (Optional) The data to match from the gRPC request. +* `method_name` - (Optional) The method name to match from the request. If you specify a name, you must also specify a `service_name`. +* `service_name` - (Optional) The fully qualified domain name for the service to match from the request. + +The `metadata` object supports the following: + +* `name` - (Required) The name of the route. +* `invert` - (Optional) If `true`, the match is on the opposite of the `match` criteria. Default is `false`. +* `match` - (Optional) The data to match from the request. + +The `metadata`'s `match` object supports the following: + +* `exact` - (Optional) The value sent by the client must match the specified value exactly. +* `prefix` - (Optional) The value sent by the client must begin with the specified characters. +* `range`- (Optional) The object that specifies the range of numbers that the value sent by the client must be included in. +* `regex` - (Optional) The value sent by the client must include the specified characters. +* `suffix` - (Optional) The value sent by the client must end with the specified characters. + +The `grpc_route`'s `retry_policy` object supports the following: + +* `grpc_retry_events` - (Optional) List of gRPC retry events. +Valid values: `cancelled`, `deadline-exceeded`, `internal`, `resource-exhausted`, `unavailable`. +* `http_retry_events` - (Optional) List of HTTP retry events. +Valid values: `client-error` (HTTP status code 409), `gateway-error` (HTTP status codes 502, 503, and 504), `server-error` (HTTP status codes 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, and 511), `stream-error` (retry on refused stream). +* `max_retries` - (Required) The maximum number of retries. +* `per_retry_timeout` - (Required) The per-retry timeout. +* `tcp_retry_events` - (Optional) List of TCP retry events. The only valid value is `connection-error`. + +The `http2_route` and `http_route`'s `match` object supports the following: * `prefix` - (Required) Specifies the path with which to match requests. This parameter must always start with /, which by itself matches all requests to the virtual router service name. @@ -176,7 +214,7 @@ This parameter must always start with /, which by itself matches all requests to * `method` - (Optional) The client request header method to match on. Valid values: `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`, `TRACE`, `PATCH`. * `scheme` - (Optional) The client request header scheme to match on. Valid values: `http`, `https`. -The `retry_policy` object supports the following: +The `http2_route` and `http_route`'s `retry_policy` object supports the following: * `http_retry_events` - (Optional) List of HTTP retry events. Valid values: `client-error` (HTTP status code 409), `gateway-error` (HTTP status codes 502, 503, and 504), `server-error` (HTTP status codes 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, and 511), `stream-error` (retry on refused stream). diff --git a/website/docs/r/appmesh_virtual_node.html.markdown b/website/docs/r/appmesh_virtual_node.html.markdown index 05bce9fcb26..2366dd96db8 100644 --- a/website/docs/r/appmesh_virtual_node.html.markdown +++ b/website/docs/r/appmesh_virtual_node.html.markdown @@ -264,16 +264,16 @@ The `dns` object supports the following: The `port_mapping` object supports the following: * `port` - (Required) The port used for the port mapping. -* `protocol` - (Required) The protocol used for the port mapping. Valid values are `http` and `tcp`. +* `protocol` - (Required) The protocol used for the port mapping. Valid values are `http`, `http2`, `tcp` and `grpc`. The `health_check` object supports the following: * `healthy_threshold` - (Required) The number of consecutive successful health checks that must occur before declaring listener healthy. * `interval_millis`- (Required) The time period in milliseconds between each health check execution. -* `protocol` - (Required) The protocol for the health check request. Valid values are `http` and `tcp`. +* `protocol` - (Required) The protocol for the health check request. Valid values are `http`, `http2`, `tcp` and `grpc`. * `timeout_millis` - (Required) The amount of time to wait when receiving a response from the health check, in milliseconds. * `unhealthy_threshold` - (Required) The number of consecutive failed health checks that must occur before declaring a virtual node unhealthy. -* `path` - (Optional) The destination path for the health check request. This is only required if the specified protocol is `http`. +* `path` - (Optional) The destination path for the health check request. This is only required if the specified protocol is `http` or `http2`. * `port` - (Optional) The destination port for the health check request. This port must match the port defined in the `port_mapping` for the listener. The `tls` object supports the following: diff --git a/website/docs/r/appmesh_virtual_router.html.markdown b/website/docs/r/appmesh_virtual_router.html.markdown index 0e5d0bf89fd..0c494fc5483 100644 --- a/website/docs/r/appmesh_virtual_router.html.markdown +++ b/website/docs/r/appmesh_virtual_router.html.markdown @@ -62,7 +62,7 @@ The `listener` object supports the following: The `port_mapping` object supports the following: * `port` - (Required) The port used for the port mapping. -* `protocol` - (Required) The protocol used for the port mapping. Valid values are `http` and `tcp`. +* `protocol` - (Required) The protocol used for the port mapping. Valid values are `http`,`http2`, `tcp` and `grpc`. ## Attributes Reference