diff --git a/.changelog/25819.txt b/.changelog/25819.txt new file mode 100644 index 000000000000..29a69b3fdcfb --- /dev/null +++ b/.changelog/25819.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_appmesh_gateway_route: Add `http2_route.action.rewrite`, `http2_route.match.hostname`, `http_route.action.rewrite` and `http_route.match.hostname` arguments +``` \ No newline at end of file diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 071d7387d2ff..c279c7a90ecc 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -171,6 +171,67 @@ func ResourceGatewayRoute() *schema.Resource { }, }, }, + "rewrite": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_target_hostname": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"ENABLED", "DISABLED"}, false), + }, + }, + }, + AtLeastOneOf: []string{ + "spec.0.http2_route.0.action.0.rewrite.0.prefix", + "spec.0.http2_route.0.action.0.rewrite.0.hostname", + }, + }, + "prefix": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"ENABLED", "DISABLED"}, false), + ExactlyOneOf: []string{ + "spec.0.http2_route.0.action.0.rewrite.0.prefix.0.default_prefix", + "spec.0.http2_route.0.action.0.rewrite.0.prefix.0.value", + }, + }, + "value": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + ExactlyOneOf: []string{ + "spec.0.http2_route.0.action.0.rewrite.0.prefix.0.default_prefix", + "spec.0.http2_route.0.action.0.rewrite.0.prefix.0.value", + }, + }, + }, + }, + AtLeastOneOf: []string{ + "spec.0.http2_route.0.action.0.rewrite.0.prefix", + "spec.0.http2_route.0.action.0.rewrite.0.hostname", + }, + }, + }, + }, + }, }, }, }, @@ -184,8 +245,42 @@ func ResourceGatewayRoute() *schema.Resource { Schema: map[string]*schema.Schema{ "prefix": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + AtLeastOneOf: []string{ + "spec.0.http2_route.0.match.0.prefix", + "spec.0.http2_route.0.match.0.hostname", + }, + }, + "hostname": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "spec.0.http2_route.0.match.0.hostname.0.exact", + "spec.0.http2_route.0.match.0.hostname.0.suffix", + }, + }, + "suffix": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "spec.0.http2_route.0.match.0.hostname.0.exact", + "spec.0.http2_route.0.match.0.hostname.0.suffix", + }, + }, + }, + }, + AtLeastOneOf: []string{ + "spec.0.http2_route.0.match.0.prefix", + "spec.0.http2_route.0.match.0.hostname", + }, }, }, }, @@ -238,10 +333,70 @@ func ResourceGatewayRoute() *schema.Resource { }, }, }, + "rewrite": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hostname": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_target_hostname": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"ENABLED", "DISABLED"}, false), + }, + }, + }, + AtLeastOneOf: []string{ + "spec.0.http_route.0.action.0.rewrite.0.prefix", + "spec.0.http_route.0.action.0.rewrite.0.hostname", + }, + }, + "prefix": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "default_prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{"ENABLED", "DISABLED"}, false), + ExactlyOneOf: []string{ + "spec.0.http_route.0.action.0.rewrite.0.prefix.0.default_prefix", + "spec.0.http_route.0.action.0.rewrite.0.prefix.0.value", + }, + }, + "value": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + ExactlyOneOf: []string{ + "spec.0.http_route.0.action.0.rewrite.0.prefix.0.default_prefix", + "spec.0.http_route.0.action.0.rewrite.0.prefix.0.value", + }, + }, + }, + }, + AtLeastOneOf: []string{ + "spec.0.http_route.0.action.0.rewrite.0.prefix", + "spec.0.http_route.0.action.0.rewrite.0.hostname", + }, + }, + }, + }, + }, }, }, }, - "match": { Type: schema.TypeList, Required: true, @@ -251,8 +406,42 @@ func ResourceGatewayRoute() *schema.Resource { Schema: map[string]*schema.Schema{ "prefix": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + AtLeastOneOf: []string{ + "spec.0.http_route.0.match.0.prefix", + "spec.0.http_route.0.match.0.hostname", + }, + }, + "hostname": { + Type: schema.TypeList, + Optional: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "spec.0.http_route.0.match.0.hostname.0.exact", + "spec.0.http_route.0.match.0.hostname.0.suffix", + }, + }, + "suffix": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + "spec.0.http_route.0.match.0.hostname.0.exact", + "spec.0.http_route.0.match.0.hostname.0.suffix", + }, + }, + }, + }, + AtLeastOneOf: []string{ + "spec.0.http_route.0.match.0.prefix", + "spec.0.http_route.0.match.0.hostname", + }, }, }, }, @@ -583,6 +772,66 @@ func expandGRPCGatewayRoute(vGrpcRoute []interface{}) *appmesh.GrpcGatewayRoute return route } +func expandHTTPGatewayRouteRewrite(vHttpRouteRewrite []interface{}) *appmesh.HttpGatewayRouteRewrite { + if len(vHttpRouteRewrite) == 0 || vHttpRouteRewrite[0] == nil { + return nil + } + mRouteRewrite := vHttpRouteRewrite[0].(map[string]interface{}) + routeRewrite := &appmesh.HttpGatewayRouteRewrite{} + + if vRouteHostnameRewrite, ok := mRouteRewrite["hostname"].([]interface{}); ok { + mRouteHostnameRewrite := vRouteHostnameRewrite[0].(map[string]interface{}) + routeHostnameRewrite := &appmesh.GatewayRouteHostnameRewrite{} + if vDefaultTargetHostname, ok := mRouteHostnameRewrite["default_target_hostname"].(string); ok && vDefaultTargetHostname != "" { + routeHostnameRewrite.DefaultTargetHostname = aws.String(vDefaultTargetHostname) + } + routeRewrite.Hostname = routeHostnameRewrite + } + + if vRoutePrefixRewrite, ok := mRouteRewrite["prefix"].([]interface{}); ok { + mRoutePrefixRewrite := vRoutePrefixRewrite[0].(map[string]interface{}) + routePrefixRewrite := &appmesh.HttpGatewayRoutePrefixRewrite{} + if vDefaultPrefix, ok := mRoutePrefixRewrite["default_prefix"].(string); ok && vDefaultPrefix != "" { + routePrefixRewrite.DefaultPrefix = aws.String(vDefaultPrefix) + } + if vValue, ok := mRoutePrefixRewrite["value"].(string); ok && vValue != "" { + routePrefixRewrite.Value = aws.String(vValue) + } + routeRewrite.Prefix = routePrefixRewrite + } + + return routeRewrite +} + +func expandHTTPGatewayRouteMatch(vHttpRouteMatch []interface{}) *appmesh.HttpGatewayRouteMatch { + if len(vHttpRouteMatch) == 0 || vHttpRouteMatch[0] == nil { + return nil + } + + routeMatch := &appmesh.HttpGatewayRouteMatch{} + + mRouteMatch := vHttpRouteMatch[0].(map[string]interface{}) + + if vPrefix, ok := mRouteMatch["prefix"].(string); ok && vPrefix != "" { + routeMatch.Prefix = aws.String(vPrefix) + } + + if vHostnameMatch, ok := mRouteMatch["hostname"].([]interface{}); ok && len(vHostnameMatch) > 0 && vHostnameMatch[0] != nil { + hostnameMatch := &appmesh.GatewayRouteHostnameMatch{} + + mHostnameMatch := vHostnameMatch[0].(map[string]interface{}) + if vExact, ok := mHostnameMatch["exact"].(string); ok && vExact != "" { + hostnameMatch.Exact = aws.String(vExact) + } + if vSuffix, ok := mHostnameMatch["suffix"].(string); ok && vSuffix != "" { + hostnameMatch.Suffix = aws.String(vSuffix) + } + routeMatch.Hostname = hostnameMatch + } + + return routeMatch +} + func expandHTTPGatewayRoute(vHttpRoute []interface{}) *appmesh.HttpGatewayRoute { if len(vHttpRoute) == 0 || vHttpRoute[0] == nil { return nil @@ -601,19 +850,15 @@ func expandHTTPGatewayRoute(vHttpRoute []interface{}) *appmesh.HttpGatewayRoute routeAction.Target = expandGatewayRouteTarget(vRouteTarget) } + if vRouteRewrite, ok := mRouteAction["rewrite"].([]interface{}); ok { + routeAction.Rewrite = expandHTTPGatewayRouteRewrite(vRouteRewrite) + } + route.Action = routeAction } if vRouteMatch, ok := mHttpRoute["match"].([]interface{}); ok && len(vRouteMatch) > 0 && vRouteMatch[0] != nil { - routeMatch := &appmesh.HttpGatewayRouteMatch{} - - mRouteMatch := vRouteMatch[0].(map[string]interface{}) - - if vPrefix, ok := mRouteMatch["prefix"].(string); ok && vPrefix != "" { - routeMatch.Prefix = aws.String(vPrefix) - } - - route.Match = routeMatch + route.Match = expandHTTPGatewayRouteMatch(vRouteMatch) } return route @@ -677,6 +922,60 @@ func flattenGRPCGatewayRoute(grpcRoute *appmesh.GrpcGatewayRoute) []interface{} return []interface{}{mGrpcRoute} } +func flattenHTTPGatewayRouteMatch(routeMatch *appmesh.HttpGatewayRouteMatch) []interface{} { + if routeMatch == nil { + return []interface{}{} + } + + mRouteMatch := map[string]interface{}{} + + if routeMatch.Prefix != nil { + mRouteMatch["prefix"] = aws.StringValue(routeMatch.Prefix) + } + + if hostnameMatch := routeMatch.Hostname; hostnameMatch != nil { + + mHostnameMatch := map[string]interface{}{} + if hostnameMatch.Exact != nil { + mHostnameMatch["exact"] = aws.StringValue(hostnameMatch.Exact) + } + if hostnameMatch.Suffix != nil { + mHostnameMatch["suffix"] = aws.StringValue(hostnameMatch.Suffix) + } + + mRouteMatch["hostname"] = []interface{}{mHostnameMatch} + + } + return []interface{}{mRouteMatch} +} + +func flattenHTTPGatewayRouteRewrite(routeRewrite *appmesh.HttpGatewayRouteRewrite) []interface{} { + if routeRewrite == nil { + return []interface{}{} + } + + mRouteRewrite := map[string]interface{}{} + + if rewriteHostname := routeRewrite.Hostname; rewriteHostname != nil { + mRewriteHostname := map[string]interface{}{ + "default_target_hostname": aws.StringValue(rewriteHostname.DefaultTargetHostname), + } + mRouteRewrite["hostname"] = []interface{}{mRewriteHostname} + } + + if rewritePrefix := routeRewrite.Prefix; rewritePrefix != nil { + mRewritePrefix := map[string]interface{}{ + "default_prefix": aws.StringValue(rewritePrefix.DefaultPrefix), + } + if rewritePrefixValue := rewritePrefix.Value; rewritePrefixValue != nil { + mRewritePrefix["value"] = aws.StringValue(rewritePrefix.Value) + } + mRouteRewrite["prefix"] = []interface{}{mRewritePrefix} + } + + return []interface{}{mRouteRewrite} +} + func flattenHTTPGatewayRoute(httpRoute *appmesh.HttpGatewayRoute) []interface{} { if httpRoute == nil { return []interface{}{} @@ -686,18 +985,15 @@ func flattenHTTPGatewayRoute(httpRoute *appmesh.HttpGatewayRoute) []interface{} if routeAction := httpRoute.Action; routeAction != nil { mRouteAction := map[string]interface{}{ - "target": flattenGatewayRouteTarget(routeAction.Target), + "target": flattenGatewayRouteTarget(routeAction.Target), + "rewrite": flattenHTTPGatewayRouteRewrite(routeAction.Rewrite), } mHttpRoute["action"] = []interface{}{mRouteAction} } if routeMatch := httpRoute.Match; routeMatch != nil { - mRouteMatch := map[string]interface{}{ - "prefix": aws.StringValue(routeMatch.Prefix), - } - - mHttpRoute["match"] = []interface{}{mRouteMatch} + mHttpRoute["match"] = flattenHTTPGatewayRouteMatch(routeMatch) } return []interface{}{mHttpRoute} diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index a28627c74605..256c0d799d40 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -223,6 +223,60 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualGateway/%s/gatewayRoute/%s", meshName, vgName, grName)), ), }, + { + Config: testAccGatewayRouteConfig_httpRouteMatchHostname(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "name", grName), + 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.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.target.0.virtual_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.http_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vs1ResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.0.exact", "test.example.com"), + resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualGateway/%s/gatewayRoute/%s", meshName, vgName, grName)), + ), + }, + { + Config: testAccGatewayRouteConfig_httpRouteRewrite(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "name", grName), + 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.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.target.0.virtual_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.http_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vs1ResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.rewrite.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.rewrite.0.hostname.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.rewrite.0.hostname.0.default_target_hostname", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.rewrite.0.prefix.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.rewrite.0.prefix.0.default_prefix", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualGateway/%s/gatewayRoute/%s", meshName, vgName, grName)), + ), + }, { ResourceName: resourceName, ImportStateIdFunc: testAccGatewayRouteImportStateIdFunc(resourceName), @@ -296,6 +350,60 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualGateway/%s/gatewayRoute/%s", meshName, vgName, grName)), ), }, + { + Config: testAccGatewayRouteConfig_http2RouteMatchHostname(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "name", grName), + 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.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.target.0.virtual_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.http2_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vs1ResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.hostname.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.hostname.0.exact", "test.example.com"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualGateway/%s/gatewayRoute/%s", meshName, vgName, grName)), + ), + }, + { + Config: testAccGatewayRouteConfig_http2RouteRewrite(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(resourceName, &v), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "name", grName), + 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.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.target.0.virtual_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.http2_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vs1ResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.rewrite.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.rewrite.0.hostname.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.rewrite.0.hostname.0.default_target_hostname", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.rewrite.0.prefix.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.action.0.rewrite.0.prefix.0.default_prefix", "DISABLED"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualGateway/%s/gatewayRoute/%s", meshName, vgName, grName)), + ), + }, { ResourceName: resourceName, ImportStateIdFunc: testAccGatewayRouteImportStateIdFunc(resourceName), @@ -545,6 +653,68 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_httpRouteMatchHostname(meshName, vgName, grName string) string { + return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName), fmt.Sprintf(` +resource "aws_appmesh_gateway_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.name + virtual_gateway_name = aws_appmesh_virtual_gateway.test.name + + spec { + http_route { + action { + target { + virtual_service { + virtual_service_name = aws_appmesh_virtual_service.test[0].name + } + } + } + + match { + hostname { + exact = "test.example.com" + } + } + } + } +} +`, grName)) +} + +func testAccGatewayRouteConfig_httpRouteRewrite(meshName, vgName, grName string) string { + return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName), fmt.Sprintf(` +resource "aws_appmesh_gateway_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.name + virtual_gateway_name = aws_appmesh_virtual_gateway.test.name + + spec { + http_route { + action { + target { + virtual_service { + virtual_service_name = aws_appmesh_virtual_service.test[0].name + } + } + rewrite { + hostname { + default_target_hostname = "DISABLED" + } + prefix { + default_prefix = "DISABLED" + } + } + } + + match { + prefix = "/" + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_http2Route(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -597,6 +767,68 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_http2RouteMatchHostname(meshName, vgName, grName string) string { + return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName), fmt.Sprintf(` +resource "aws_appmesh_gateway_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.name + virtual_gateway_name = aws_appmesh_virtual_gateway.test.name + + spec { + http2_route { + action { + target { + virtual_service { + virtual_service_name = aws_appmesh_virtual_service.test[0].name + } + } + } + + match { + hostname { + exact = "test.example.com" + } + } + } + } +} +`, grName)) +} + +func testAccGatewayRouteConfig_http2RouteRewrite(meshName, vgName, grName string) string { + return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName), fmt.Sprintf(` +resource "aws_appmesh_gateway_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.name + virtual_gateway_name = aws_appmesh_virtual_gateway.test.name + + spec { + http2_route { + action { + target { + virtual_service { + virtual_service_name = aws_appmesh_virtual_service.test[0].name + } + } + rewrite { + hostname { + default_target_hostname = "DISABLED" + } + prefix { + default_prefix = "DISABLED" + } + } + } + + match { + prefix = "/" + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_tags1(meshName, vgName, grName, tagKey1, tagValue1 string) string { return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { diff --git a/website/docs/r/appmesh_gateway_route.html.markdown b/website/docs/r/appmesh_gateway_route.html.markdown index 26f500e8fc94..00e4037bf8b5 100644 --- a/website/docs/r/appmesh_gateway_route.html.markdown +++ b/website/docs/r/appmesh_gateway_route.html.markdown @@ -74,14 +74,38 @@ The `virtual_service` object supports the following: * `virtual_service_name` - (Required) The name of the virtual service that traffic is routed to. Must be between 1 and 255 characters in length. +The `http_route` and `http2_route`'s `action` object additionally supports the following: + +* `rewrite` - (Optional) The gateway route action to rewrite. + +The `rewrite` object supports the following: + +* `hostname` - (Optional) The host name to rewrite. +* `prefix` - (Optional) The specified beginning characters to rewrite. + +The `hostname` object supports the following: + +* `default_target_hostname` - (Required) The default target host name to write to. Valid values: `ENABLED`, `DISABLED`. + +The `prefix` object supports the following: + +* `default_prefix` - (Optional) The default prefix used to replace the incoming route prefix when rewritten. Valid values: `ENABLED`, `DISABLED`. +* `value` - (Optional) The value used to replace the incoming route prefix when rewritten. + The `grpc_route`'s `match` object supports the following: * `service_name` - (Required) The fully qualified domain name for the service to match from the request. The `http_route` and `http2_route`'s `match` object supports the following: +* `hostname` - (Optional) The host name to match on. * `prefix` - (Required) Specifies the path to match requests with. This parameter must always start with `/`, which by itself matches all requests to the virtual service name. +The `hostname` object supports the following: + +* `exact` - (Optional) The exact host name to match on. +* `suffix` - (Optional) The specified ending characters of the host name to match on. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: