From 45ae3ac1e3b2bf3d05c84d9c71aa7d84f4c079cc Mon Sep 17 00:00:00 2001 From: Ben Murden Date: Tue, 24 Jan 2023 16:52:47 +0900 Subject: [PATCH 01/36] Tests for gateway route target port --- internal/service/appmesh/appmesh_test.go | 21 +- .../service/appmesh/gateway_route_test.go | 449 ++++++++++++++++++ 2 files changed, 461 insertions(+), 9 deletions(-) diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 2af5b8fe82c2..680af96e4041 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -11,15 +11,18 @@ func TestAccAppMesh_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "GatewayRoute": { - "basic": testAccGatewayRoute_basic, - "disappears": testAccGatewayRoute_disappears, - "grpcRoute": testAccGatewayRoute_GRPCRoute, - "grpcRouteWithPort": testAccGatewayRoute_GRPCRouteWithPort, - "httpRoute": testAccGatewayRoute_HTTPRoute, - "httpRouteWithPort": testAccGatewayRoute_HTTPRouteWithPort, - "http2Route": testAccGatewayRoute_HTTP2Route, - "http2RouteWithPort": testAccGatewayRoute_HTTP2RouteWithPort, - "tags": testAccGatewayRoute_Tags, + "basic": testAccGatewayRoute_basic, + "disappears": testAccGatewayRoute_disappears, + "grpcRoute": testAccGatewayRoute_GRPCRoute, + "grpcRouteTargetPort": testAccGatewayRoute_GRPCRouteTargetPort, + "grpcRouteWithPort": testAccGatewayRoute_GRPCRouteWithPort, + "httpRoute": testAccGatewayRoute_HTTPRoute, + "httpRouteTargetPort": testAccGatewayRoute_HTTPRouteTargetPort, + "httpRouteWithPort": testAccGatewayRoute_HTTPRouteWithPort, + "http2Route": testAccGatewayRoute_HTTP2Route, + "http2RouteTargetPort": testAccGatewayRoute_HTTP2RouteTargetPort, + "http2RouteWithPort": testAccGatewayRoute_HTTP2RouteWithPort, + "tags": testAccGatewayRoute_Tags, }, "Mesh": { "basic": testAccMesh_basic, diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index 8f7bb70e9b28..5c61eb4ce9bd 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -240,6 +240,81 @@ func testAccGatewayRoute_GRPCRouteWithPort(t *testing.T) { }) } +func testAccGatewayRoute_GRPCRouteTargetPort(t *testing.T) { + ctx := acctest.Context(t) + var v appmesh.GatewayRouteData + resourceName := "aws_appmesh_gateway_route.test" + vsMultiResourceName := "aws_appmesh_virtual_service.multi_test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + grName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appmesh.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayRouteConfig_grpcRouteTargetPort(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.target.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.target.0.virtual_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.grpc_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vsMultiResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", "multi-test"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), + 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_grpcRouteTargetPortUpdated(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.target.0.port", "8081"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.action.0.target.0.virtual_service.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.grpc_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vsMultiResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", "multi-test"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), + 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), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccGatewayRoute_HTTPRoute(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData @@ -368,6 +443,81 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { }) } +func testAccGatewayRoute_HTTPRouteTargetPort(t *testing.T) { + ctx := acctest.Context(t) + var v appmesh.GatewayRouteData + resourceName := "aws_appmesh_gateway_route.test" + vsMultiResourceName := "aws_appmesh_virtual_service.multi_test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + grName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appmesh.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayRouteConfig_httpRouteTargetPort(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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.port", "8080"), + 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", vsMultiResourceName, "name"), + 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)), + ), + }, + { + Config: testAccGatewayRouteConfig_httpRouteTargetPortUpdated(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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.port", "8081"), + 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", vsMultiResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/users"), + 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), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData @@ -626,6 +776,81 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { }) } +func testAccGatewayRoute_HTTP2RouteTargetPort(t *testing.T) { + ctx := acctest.Context(t) + var v appmesh.GatewayRouteData + resourceName := "aws_appmesh_gateway_route.test" + vsMultiResourceName := "aws_appmesh_virtual_service.multi_test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + grName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appmesh.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayRouteConfig_http2RouteTargetPort(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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.http_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.port", "8080"), + 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", vsMultiResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_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)), + ), + }, + { + Config: testAccGatewayRouteConfig_http2RouteTargetPortUpdated(meshName, vgName, grName), + Check: resource.ComposeTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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.http_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.port", "8081"), + 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", vsMultiResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/users"), + 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), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData @@ -894,6 +1119,50 @@ resource "aws_appmesh_virtual_service" "test" { `, meshName, vgName, protocol) } +func testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vnName string, protocol string) string { + return fmt.Sprintf(` +resource "aws_appmesh_virtual_node" "test" { + name = "%[1]s-multi-listener-vn" + mesh_name = aws_appmesh_mesh.test.name + + spec { + listener { + port_mapping { + port = 8080 + protocol = "%[2]s" + } + } + + listener { + port_mapping { + port = 8081 + protocol = "%[2]s" + } + } + + service_discovery { + dns { + hostname = "serviceb.simpleapp.local" + } + } + } +} + +resource "aws_appmesh_virtual_service" "multi_test" { + name = "%[1]s-multi-listener" + mesh_name = aws_appmesh_mesh.test.name + + spec { + provider { + virtual_node { + virtual_node_name = aws_appmesh_virtual_node.test.name + } + } + } +} +`, vnName, protocol) +} + func testAccGatewayRouteConfig_grpcRoute(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -946,6 +1215,66 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_grpcRouteTargetPort(meshName, vgName, grName string) string { + return acctest.ConfigCompose( + testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), + testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "grpc"), + 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 { + grpc_route { + action { + target { + virtual_service { + virtual_service_name = aws_appmesh_virtual_service.multi_test.name + } + port = 8080 + } + } + + match { + service_name = "multi-test" + } + } + } +} +`, grName)) +} + +func testAccGatewayRouteConfig_grpcRouteTargetPortUpdated(meshName, vgName, grName string) string { + return acctest.ConfigCompose( + testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), + testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "grpc"), + 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 { + grpc_route { + action { + target { + virtual_service { + virtual_service_name = aws_appmesh_virtual_service.multi_test.name + } + port = 8081 + } + } + + match { + service_name = "multi-test" + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_grpcRouteWithPort(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1052,6 +1381,66 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_httpRouteTargetPort(meshName, vgName, grName string) string { + return acctest.ConfigCompose( + testAccGatewayRouteConfigBase(meshName, vgName, "http"), + testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http"), + 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.multi_test.name + } + port = 8080 + } + } + + match { + prefix = "/" + } + } + } +} +`, grName)) +} + +func testAccGatewayRouteConfig_httpRouteTargetPortUpdated(meshName, vgName, grName string) string { + return acctest.ConfigCompose( + testAccGatewayRouteConfigBase(meshName, vgName, "http"), + testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http"), + 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.multi_test.name + } + port = 8081 + } + } + + match { + prefix = "/users" + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_httpRouteWithPort(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1220,6 +1609,66 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_http2RouteTargetPort(meshName, vgName, grName string) string { + return acctest.ConfigCompose( + testAccGatewayRouteConfigBase(meshName, vgName, "http2"), + testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http2"), + 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.multi_test.name + } + port = 8080 + } + } + + match { + prefix = "/" + } + } + } +} +`, grName)) +} + +func testAccGatewayRouteConfig_http2RouteTargetPortUpdated(meshName, vgName, grName string) string { + return acctest.ConfigCompose( + testAccGatewayRouteConfigBase(meshName, vgName, "http2"), + testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http2"), + 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.multi_test.name + } + port = 8081 + } + } + + match { + prefix = "/users" + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_http2RouteWithPort(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { From eacf2e37fc475dd890384bbd04b908c41c4f0e2f Mon Sep 17 00:00:00 2001 From: Ben Murden Date: Tue, 24 Jan 2023 16:53:06 +0900 Subject: [PATCH 02/36] Implement Gateway Route taget port --- internal/service/appmesh/gateway_route.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 71245a670f31..fd44f5c86d4b 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -105,6 +105,11 @@ func ResourceGatewayRoute() *schema.Resource { }, }, }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, }, }, }, @@ -176,6 +181,11 @@ func ResourceGatewayRoute() *schema.Resource { }, }, }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, }, }, }, @@ -343,6 +353,11 @@ func ResourceGatewayRoute() *schema.Resource { }, }, }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, }, }, }, @@ -755,6 +770,10 @@ func expandGatewayRouteTarget(vRouteTarget []interface{}) *appmesh.GatewayRouteT routeTarget.VirtualService = virtualService } + if vPort, ok := mRouteTarget["port"].(int); ok && vPort > 0 { + routeTarget.Port = aws.Int64(int64(vPort)) + } + return routeTarget } @@ -914,7 +933,9 @@ func flattenGatewayRouteTarget(routeTarget *appmesh.GatewayRouteTarget) []interf return []interface{}{} } - mRouteTarget := map[string]interface{}{} + mRouteTarget := map[string]interface{}{ + "port": int(aws.Int64Value(routeTarget.Port)), + } if virtualService := routeTarget.VirtualService; virtualService != nil { mVirtualService := map[string]interface{}{ From c4bc856b2160df67718b7b68ee0a7c6a84226d68 Mon Sep 17 00:00:00 2001 From: Ben Murden Date: Tue, 24 Jan 2023 17:11:29 +0900 Subject: [PATCH 03/36] Fix test HCL indentations --- internal/service/appmesh/gateway_route_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index 5c61eb4ce9bd..8b71934223fd 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -1232,7 +1232,7 @@ resource "aws_appmesh_gateway_route" "test" { virtual_service { virtual_service_name = aws_appmesh_virtual_service.multi_test.name } - port = 8080 + port = 8080 } } @@ -1262,7 +1262,7 @@ resource "aws_appmesh_gateway_route" "test" { virtual_service { virtual_service_name = aws_appmesh_virtual_service.multi_test.name } - port = 8081 + port = 8081 } } @@ -1398,7 +1398,7 @@ resource "aws_appmesh_gateway_route" "test" { virtual_service { virtual_service_name = aws_appmesh_virtual_service.multi_test.name } - port = 8080 + port = 8080 } } @@ -1428,7 +1428,7 @@ resource "aws_appmesh_gateway_route" "test" { virtual_service { virtual_service_name = aws_appmesh_virtual_service.multi_test.name } - port = 8081 + port = 8081 } } @@ -1626,7 +1626,7 @@ resource "aws_appmesh_gateway_route" "test" { virtual_service { virtual_service_name = aws_appmesh_virtual_service.multi_test.name } - port = 8080 + port = 8080 } } @@ -1656,7 +1656,7 @@ resource "aws_appmesh_gateway_route" "test" { virtual_service { virtual_service_name = aws_appmesh_virtual_service.multi_test.name } - port = 8081 + port = 8081 } } From 43916a50fff0cce1962f2fe106db771d3d4e3f21 Mon Sep 17 00:00:00 2001 From: Ben Murden Date: Tue, 24 Jan 2023 17:15:12 +0900 Subject: [PATCH 04/36] Add changelog text --- .changelog/29064.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/29064.txt diff --git a/.changelog/29064.txt b/.changelog/29064.txt new file mode 100644 index 000000000000..5faf6a907c20 --- /dev/null +++ b/.changelog/29064.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_appmesh_gateway_route: Add `port` to `target` block in order to support Virtual Services with multiple listeners. +``` From c27f7f30b5952df3a60bffa9e6ecbece83250f6d Mon Sep 17 00:00:00 2001 From: Ben Murden Date: Tue, 24 Jan 2023 17:22:25 +0900 Subject: [PATCH 05/36] Update documentation for target port --- website/docs/r/appmesh_gateway_route.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/appmesh_gateway_route.html.markdown b/website/docs/r/appmesh_gateway_route.html.markdown index f9059b1669f2..32d24dcb9501 100644 --- a/website/docs/r/appmesh_gateway_route.html.markdown +++ b/website/docs/r/appmesh_gateway_route.html.markdown @@ -68,6 +68,7 @@ The `grpc_route`, `http_route` and `http2_route`'s `action` object supports the The `target` object supports the following: +* `port` - (Optional) The port number that corresponds to the target for Virtual Service provider port. This is required when the provider (router or node) of the Virtual Service has multiple listeners. * `virtual_service` - (Required) Virtual service gateway route target. The `virtual_service` object supports the following: @@ -82,7 +83,6 @@ The `rewrite` object supports the following: * `hostname` - (Optional) Host name to rewrite. * `prefix` - (Optional) Specified beginning characters to rewrite. -* `port` - (Optional) The port number to match from the request. The `hostname` object supports the following: From 3f8be7d10387e61bca45c3700a0495563bc26b82 Mon Sep 17 00:00:00 2001 From: Austin Lowder Date: Mon, 6 Feb 2023 09:58:58 -0600 Subject: [PATCH 06/36] Creating Appmesh Virtual Router Data Source --- internal/provider/provider.go | 1 + .../appmesh/virtual_router_data_source.go | 142 ++++++++++++++++++ .../virtual_router_data_source_test.go | 67 +++++++++ .../d/appmesh_virtual_rouer.html.markdown | 51 +++++++ 4 files changed, 261 insertions(+) create mode 100644 internal/service/appmesh/virtual_router_data_source.go create mode 100644 internal/service/appmesh/virtual_router_data_source_test.go create mode 100644 website/docs/d/appmesh_virtual_rouer.html.markdown diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 36579b551d54..5812a7f0f707 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -441,6 +441,7 @@ func New(ctx context.Context) (*schema.Provider, error) { "aws_appmesh_mesh": appmesh.DataSourceMesh(), "aws_appmesh_virtual_service": appmesh.DataSourceVirtualService(), + "aws_appmesh_virtual_router": appmesh.DataSourceVirtualRouter(), "aws_autoscaling_group": autoscaling.DataSourceGroup(), "aws_autoscaling_groups": autoscaling.DataSourceGroups(), diff --git a/internal/service/appmesh/virtual_router_data_source.go b/internal/service/appmesh/virtual_router_data_source.go new file mode 100644 index 000000000000..b778c013968e --- /dev/null +++ b/internal/service/appmesh/virtual_router_data_source.go @@ -0,0 +1,142 @@ +package appmesh + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" +) + +func DataSourceVirtualRouter() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceVirtualRouterRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + + "mesh_name": { + Type: schema.TypeString, + Required: true, + }, + + "mesh_owner": { + Type: schema.TypeString, + Computed: true, + }, + + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + + "spec": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "listener": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port_mapping": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Computed: true, + }, + + "protocol": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "tags": tftags.TagsSchema(), + }, + } +} + +func dataSourceVirtualRouterRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).AppMeshConn() + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + req := &appmesh.DescribeVirtualRouterInput{ + MeshName: aws.String(d.Get("mesh_name").(string)), + VirtualRouterName: aws.String(d.Get("name").(string)), + } + + if v, ok := d.GetOk("mesh_owner"); ok { + req.MeshOwner = aws.String(v.(string)) + } + + resp, err := conn.DescribeVirtualRouterWithContext(ctx, req) + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router: %s", err) + } + + arn := aws.StringValue(resp.VirtualRouter.Metadata.Arn) + + d.SetId(aws.StringValue(resp.VirtualRouter.VirtualRouterName)) + + d.Set("name", resp.VirtualRouter.VirtualRouterName) + d.Set("mesh_name", resp.VirtualRouter.MeshName) + d.Set("mesh_owner", resp.VirtualRouter.Metadata.MeshOwner) + d.Set("arn", arn) + d.Set("created_date", resp.VirtualRouter.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", resp.VirtualRouter.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("resource_owner", resp.VirtualRouter.Metadata.ResourceOwner) + + err = d.Set("spec", flattenVirtualRouterSpec(resp.VirtualRouter.Spec)) + if err != nil { + return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) + } + + tags, err := ListTags(ctx, conn, arn) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Router (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) + } + + return diags +} \ No newline at end of file diff --git a/internal/service/appmesh/virtual_router_data_source_test.go b/internal/service/appmesh/virtual_router_data_source_test.go new file mode 100644 index 000000000000..200317a5e037 --- /dev/null +++ b/internal/service/appmesh/virtual_router_data_source_test.go @@ -0,0 +1,67 @@ +package appmesh_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/appmesh" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccAppMeshVirtualRouterDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + virtualRouterName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appmesh_virtual_router.test" + dataSourceName := "data.aws_appmesh_virtual_router.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(appmesh.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVirtualRouterDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVirtualRouterDataSourceConfig(meshName, virtualRouterName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_name", dataSourceName, "mesh_name"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.0.port_mapping.0.port", dataSourceName, "spec.0.listener.0.port_mapping.0.port"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.0.port_mapping.0.protocol", dataSourceName, "spec.0.listener.0.port_mapping.0.protocol"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func testAccVirtualRouterDataSourceConfig(meshName string, routerName string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} +resource "aws_appmesh_virtual_router" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } +} +data "aws_appmesh_virtual_router" "test" { + name = aws_appmesh_virtual_router.test.name + mesh_name = aws_appmesh_mesh.test.name +} + `, meshName, routerName) +} \ No newline at end of file diff --git a/website/docs/d/appmesh_virtual_rouer.html.markdown b/website/docs/d/appmesh_virtual_rouer.html.markdown new file mode 100644 index 000000000000..81fa2cf7a4b1 --- /dev/null +++ b/website/docs/d/appmesh_virtual_rouer.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "App Mesh" +layout: "aws" +page_title: "AWS: aws_appmesh_virtual_router" +description: |- + Provides an AWS App Mesh virtual router resource. +--- + +# Data Source: aws_appmesh_virtual_router + +The App Mesh Virtual Router data source allows details of an App Mesh Virtual Service to be retrieved by its name and mesh_name. + +## Example Usage + +```hcl +data "aws_appmesh_virtual_router" "test" { + name = "example-router-name" + mesh_name = "example-mesh-name" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of the virtual router. +* `mesh_name` - (Required) Name of the mesh in which the virtual router exists + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the virtual router. +* `created_date` - Creation date of the virtual router. +* `last_updated_date` - Last update date of the virtual router. +* `resource_owner` - Resource owner's AWS account ID. +* `spec` - Virtual routers specification. +* `tags` - Map of tags. + +### Spec + +* `listener` - The listener assigned to the virtual router + +### Listener + +* `port_mapping` - The port mapping of the listener + +### Port_Mapping + +* `port` - Port number the listener is listening on. +* `protocol` - Protocol the listener is listening for. \ No newline at end of file From cf6ae2441f3915dcfd798888497fcfee05b466a5 Mon Sep 17 00:00:00 2001 From: Austin Lowder Date: Tue, 7 Feb 2023 08:46:14 -0600 Subject: [PATCH 07/36] Adding Changelog --- .changelog/26908.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/26908.txt diff --git a/.changelog/26908.txt b/.changelog/26908.txt new file mode 100644 index 000000000000..8cbba3e0f96e --- /dev/null +++ b/.changelog/26908.txt @@ -0,0 +1,3 @@ +``release-note:new-data-datasource +aws_appmesh_virtual_router +``` \ No newline at end of file From 3a181ad6d3977502734f83f9464bbc7dfb64412d Mon Sep 17 00:00:00 2001 From: Austin Lowder Date: Thu, 9 Feb 2023 12:51:25 -0600 Subject: [PATCH 08/36] Updates to pass linting and fmt testing --- internal/service/appmesh/virtual_router_data_source.go | 2 +- internal/service/appmesh/virtual_router_data_source_test.go | 4 ++-- ...uer.html.markdown => appmesh_virtual_router.html.markdown} | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) rename website/docs/d/{appmesh_virtual_rouer.html.markdown => appmesh_virtual_router.html.markdown} (95%) diff --git a/internal/service/appmesh/virtual_router_data_source.go b/internal/service/appmesh/virtual_router_data_source.go index b778c013968e..2bf802c285df 100644 --- a/internal/service/appmesh/virtual_router_data_source.go +++ b/internal/service/appmesh/virtual_router_data_source.go @@ -139,4 +139,4 @@ func dataSourceVirtualRouterRead(ctx context.Context, d *schema.ResourceData, me } return diags -} \ No newline at end of file +} diff --git a/internal/service/appmesh/virtual_router_data_source_test.go b/internal/service/appmesh/virtual_router_data_source_test.go index 200317a5e037..8ed4d8fb6415 100644 --- a/internal/service/appmesh/virtual_router_data_source_test.go +++ b/internal/service/appmesh/virtual_router_data_source_test.go @@ -63,5 +63,5 @@ data "aws_appmesh_virtual_router" "test" { name = aws_appmesh_virtual_router.test.name mesh_name = aws_appmesh_mesh.test.name } - `, meshName, routerName) -} \ No newline at end of file +`, meshName, routerName) +} diff --git a/website/docs/d/appmesh_virtual_rouer.html.markdown b/website/docs/d/appmesh_virtual_router.html.markdown similarity index 95% rename from website/docs/d/appmesh_virtual_rouer.html.markdown rename to website/docs/d/appmesh_virtual_router.html.markdown index 81fa2cf7a4b1..e1cea9f5f377 100644 --- a/website/docs/d/appmesh_virtual_rouer.html.markdown +++ b/website/docs/d/appmesh_virtual_router.html.markdown @@ -48,4 +48,4 @@ In addition to all arguments above, the following attributes are exported: ### Port_Mapping * `port` - Port number the listener is listening on. -* `protocol` - Protocol the listener is listening for. \ No newline at end of file +* `protocol` - Protocol the listener is listening for. From 1ae3d0ffb639f82867a580e9a38dc6d757c1b42a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 11:43:26 -0400 Subject: [PATCH 09/36] r/aws_appmesh_virtual_router: Alphabetize attributes. --- internal/service/appmesh/virtual_router.go | 125 ++++++++++----------- 1 file changed, 60 insertions(+), 65 deletions(-) diff --git a/internal/service/appmesh/virtual_router.go b/internal/service/appmesh/virtual_router.go index 7334f0fe54ea..66ba88ae17e7 100644 --- a/internal/service/appmesh/virtual_router.go +++ b/internal/service/appmesh/virtual_router.go @@ -19,6 +19,7 @@ import ( tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKResource("aws_appmesh_virtual_router") @@ -38,20 +39,24 @@ func ResourceVirtualRouter() *schema.Resource { MigrateState: resourceVirtualRouterMigrateState, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, }, - "mesh_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "mesh_owner": { Type: schema.TypeString, Optional: true, @@ -59,39 +64,55 @@ func ResourceVirtualRouter() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidAccountID, }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + "spec": resourceVirtualRouterSpecSchema(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + }, - "spec": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "listener": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port_mapping": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IsPortNumber, - }, - - "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.PortProtocol_Values(), false), - }, - }, + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceVirtualRouterSpecSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "listener": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port_mapping": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumber, + }, + "protocol": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.PortProtocol_Values(), false), }, }, }, @@ -100,33 +121,7 @@ func ResourceVirtualRouter() *schema.Resource { }, }, }, - - "arn": { - Type: schema.TypeString, - Computed: true, - }, - - "created_date": { - Type: schema.TypeString, - Computed: true, - }, - - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - - "resource_owner": { - Type: schema.TypeString, - Computed: true, - }, - - "tags": tftags.TagsSchema(), - - "tags_all": tftags.TagsSchemaComputed(), }, - - CustomizeDiff: verify.SetTagsDiff, } } From fd47b31b6d6086fec32ba7a117c24cdca486bdad Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 11:47:55 -0400 Subject: [PATCH 10/36] r/aws_appmesh_virtual_router: Tidy up resource Create, Update and Delete. --- internal/service/appmesh/virtual_router.go | 34 ++++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/internal/service/appmesh/virtual_router.go b/internal/service/appmesh/virtual_router.go index 66ba88ae17e7..fde41f703b28 100644 --- a/internal/service/appmesh/virtual_router.go +++ b/internal/service/appmesh/virtual_router.go @@ -131,23 +131,25 @@ func resourceVirtualRouterCreate(ctx context.Context, d *schema.ResourceData, me defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) - req := &appmesh.CreateVirtualRouterInput{ + name := d.Get("name").(string) + input := &appmesh.CreateVirtualRouterInput{ MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualRouterName: aws.String(d.Get("name").(string)), Spec: expandVirtualRouterSpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), + VirtualRouterName: aws.String(name), } + if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) + input.MeshOwner = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating App Mesh virtual router: %#v", req) - resp, err := conn.CreateVirtualRouterWithContext(ctx, req) + output, err := conn.CreateVirtualRouterWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh virtual router: %s", err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Virtual Router (%s): %s", name, err) } - d.SetId(aws.StringValue(resp.VirtualRouter.Metadata.Uid)) + d.SetId(aws.StringValue(output.VirtualRouter.Metadata.Uid)) return append(diags, resourceVirtualRouterRead(ctx, d, meta)...) } @@ -250,29 +252,29 @@ func resourceVirtualRouterUpdate(ctx context.Context, d *schema.ResourceData, me conn := meta.(*conns.AWSClient).AppMeshConn() if d.HasChange("spec") { - _, v := d.GetChange("spec") - req := &appmesh.UpdateVirtualRouterInput{ + input := &appmesh.UpdateVirtualRouterInput{ MeshName: aws.String(d.Get("mesh_name").(string)), + Spec: expandVirtualRouterSpec(d.Get("spec").([]interface{})), VirtualRouterName: aws.String(d.Get("name").(string)), - Spec: expandVirtualRouterSpec(v.([]interface{})), } + if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) + input.MeshOwner = aws.String(v.(string)) } - log.Printf("[DEBUG] Updating App Mesh virtual router: %#v", req) - _, err := conn.UpdateVirtualRouterWithContext(ctx, req) + _, err := conn.UpdateVirtualRouterWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh virtual router: %s", err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Virtual Router (%s): %s", d.Id(), err) } } - arn := d.Get("arn").(string) if d.HasChange("tags_all") { + arn := d.Get("arn").(string) o, n := d.GetChange("tags_all") if err := UpdateTags(ctx, conn, arn, o, n); err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh virtual router (%s) tags: %s", arn, err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Virtual Router (%s) tags: %s", arn, err) } } From 4c25fde88d0c68a74b9b86c055626e5f0862b7a8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 11:55:41 -0400 Subject: [PATCH 11/36] r/aws_appmesh_virtual_router: Tidy up resource Read. --- internal/service/appmesh/virtual_router.go | 130 ++++++++++----------- 1 file changed, 64 insertions(+), 66 deletions(-) diff --git a/internal/service/appmesh/virtual_router.go b/internal/service/appmesh/virtual_router.go index fde41f703b28..d26f8444d1a5 100644 --- a/internal/service/appmesh/virtual_router.go +++ b/internal/service/appmesh/virtual_router.go @@ -160,77 +160,38 @@ func resourceVirtualRouterRead(ctx context.Context, d *schema.ResourceData, meta defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeVirtualRouterInput{ - MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualRouterName: aws.String(d.Get("name").(string)), - } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } - - var resp *appmesh.DescribeVirtualRouterOutput - - err := resource.RetryContext(ctx, propagationTimeout, func() *resource.RetryError { - var err error - - resp, err = conn.DescribeVirtualRouterWithContext(ctx, req) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) + outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, propagationTimeout, func() (interface{}, error) { + return FindVirtualRouterByThreePartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("name").(string)) + }, d.IsNewResource()) - if tfresource.TimedOut(err) { - resp, err = conn.DescribeVirtualRouterWithContext(ctx, req) - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] App Mesh Virtual Router (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router (%s): %s", d.Id(), err) } - if resp == nil || resp.VirtualRouter == nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router: empty response") - } + vr := outputRaw.(*appmesh.VirtualRouterData) - if aws.StringValue(resp.VirtualRouter.Status.Status) == appmesh.VirtualRouterStatusCodeDeleted { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router: %s after creation", aws.StringValue(resp.VirtualRouter.Status.Status)) - } - - log.Printf("[WARN] App Mesh Virtual Router (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } - - arn := aws.StringValue(resp.VirtualRouter.Metadata.Arn) - d.Set("name", resp.VirtualRouter.VirtualRouterName) - d.Set("mesh_name", resp.VirtualRouter.MeshName) - d.Set("mesh_owner", resp.VirtualRouter.Metadata.MeshOwner) + arn := aws.StringValue(vr.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.VirtualRouter.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.VirtualRouter.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("resource_owner", resp.VirtualRouter.Metadata.ResourceOwner) - err = d.Set("spec", flattenVirtualRouterSpec(resp.VirtualRouter.Spec)) - if err != nil { + d.Set("created_date", vr.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", vr.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", vr.MeshName) + d.Set("mesh_owner", vr.Metadata.MeshOwner) + d.Set("name", vr.VirtualRouterName) + d.Set("resource_owner", vr.Metadata.ResourceOwner) + if err := d.Set("spec", flattenVirtualRouterSpec(vr.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh virtual router (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Router (%s): %s", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -314,28 +275,65 @@ func resourceVirtualRouterImport(ctx context.Context, d *schema.ResourceData, me return []*schema.ResourceData{}, fmt.Errorf("wrong format of import ID (%s), use: 'mesh-name/virtual-router-name'", d.Id()) } - mesh := parts[0] + conn := meta.(*conns.AWSClient).AppMeshConn() + meshName := parts[0] name := parts[1] - log.Printf("[DEBUG] Importing App Mesh virtual router %s from mesh %s", name, mesh) - conn := meta.(*conns.AWSClient).AppMeshConn() + vr, err := FindVirtualRouterByThreePartKey(ctx, conn, meshName, "", name) - req := &appmesh.DescribeVirtualRouterInput{ - MeshName: aws.String(mesh), + if err != nil { + return nil, err + } + + d.SetId(aws.StringValue(vr.Metadata.Uid)) + d.Set("mesh_name", vr.MeshName) + d.Set("name", vr.VirtualRouterName) + + return []*schema.ResourceData{d}, nil +} + +func FindVirtualRouterByThreePartKey(ctx context.Context, conn *appmesh.AppMesh, meshName, meshOwner, name string) (*appmesh.VirtualRouterData, error) { + input := &appmesh.DescribeVirtualRouterInput{ + MeshName: aws.String(meshName), VirtualRouterName: aws.String(name), } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) + if meshOwner != "" { + input.MeshOwner = aws.String(meshOwner) } - resp, err := conn.DescribeVirtualRouterWithContext(ctx, req) + output, err := findVirtualRouter(ctx, conn, input) + if err != nil { return nil, err } - d.SetId(aws.StringValue(resp.VirtualRouter.Metadata.Uid)) - d.Set("name", resp.VirtualRouter.VirtualRouterName) - d.Set("mesh_name", resp.VirtualRouter.MeshName) + if status := aws.StringValue(output.Status.Status); status == appmesh.VirtualRouterStatusCodeDeleted { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } - return []*schema.ResourceData{d}, nil + return output, nil +} + +func findVirtualRouter(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.DescribeVirtualRouterInput) (*appmesh.VirtualRouterData, error) { + output, err := conn.DescribeVirtualRouterWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.VirtualRouter == nil || output.VirtualRouter.Metadata == nil || output.VirtualRouter.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.VirtualRouter, nil } From b71b24bb7f2ff4102eb2afd5c5745725e5b42edf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:03:51 -0400 Subject: [PATCH 12/36] r/aws_appmesh_virtual_router: Tidy up acceptance tests. --- .../service/appmesh/virtual_router_test.go | 111 +++++++++++------- 1 file changed, 66 insertions(+), 45 deletions(-) diff --git a/internal/service/appmesh/virtual_router_test.go b/internal/service/appmesh/virtual_router_test.go index aa9f236c92c0..a7082d5cb6f7 100644 --- a/internal/service/appmesh/virtual_router_test.go +++ b/internal/service/appmesh/virtual_router_test.go @@ -5,15 +5,14 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/appmesh" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func testAccVirtualRouter_basic(t *testing.T) { @@ -31,7 +30,7 @@ func testAccVirtualRouter_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVirtualRouterConfig_basic(meshName, vrName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), resource.TestCheckResourceAttr(resourceName, "name", vrName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -45,11 +44,12 @@ func testAccVirtualRouter_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s", meshName, vrName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccVirtualRouterConfig_updated(meshName, vrName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), resource.TestCheckResourceAttr(resourceName, "name", vrName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -59,6 +59,7 @@ func testAccVirtualRouter_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.0.port", "8081"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.0.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -86,7 +87,7 @@ func testAccVirtualRouter_multiListener(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVirtualRouterConfig_multiListener(meshName, vrName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), resource.TestCheckResourceAttr(resourceName, "name", vrName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -103,11 +104,12 @@ func testAccVirtualRouter_multiListener(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s", meshName, vrName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccVirtualRouterConfig_multiListenerUpdated(meshName, vrName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), resource.TestCheckResourceAttr(resourceName, "name", vrName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -123,6 +125,7 @@ func testAccVirtualRouter_multiListener(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2.port_mapping.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2.port_mapping.0.port", "8080"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2.port_mapping.0.protocol", "grpc"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -149,43 +152,36 @@ func testAccVirtualRouter_tags(t *testing.T) { CheckDestroy: testAccCheckVirtualRouterDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVirtualRouterConfig_tags(meshName, vrName, "foo", "bar", "good", "bad"), + Config: testAccVirtualRouterConfig_tags1(meshName, vrName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr( - resourceName, "tags.foo", "bar"), - resource.TestCheckResourceAttr( - resourceName, "tags.good", "bad"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1"), ), }, { - Config: testAccVirtualRouterConfig_tags(meshName, vrName, "foo2", "bar", "good", "bad2"), + ResourceName: resourceName, + ImportStateId: fmt.Sprintf("%s/%s", meshName, vrName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccVirtualRouterConfig_tags2(meshName, vrName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr( - resourceName, "tags.foo2", "bar"), - resource.TestCheckResourceAttr( - resourceName, "tags.good", "bad2"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - Config: testAccVirtualRouterConfig_basic(meshName, vrName), + Config: testAccVirtualRouterConfig_tags1(meshName, vrName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualRouterExists(ctx, resourceName, &vr), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, - { - ResourceName: resourceName, - ImportStateId: fmt.Sprintf("%s/%s", meshName, vrName), - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -214,6 +210,7 @@ func testAccVirtualRouter_disappears(t *testing.T) { }, }) } + func testAccCheckVirtualRouterDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppMeshConn() @@ -223,44 +220,42 @@ func testAccCheckVirtualRouterDestroy(ctx context.Context) resource.TestCheckFun continue } - _, err := conn.DescribeVirtualRouterWithContext(ctx, &appmesh.DescribeVirtualRouterInput{ - MeshName: aws.String(rs.Primary.Attributes["mesh_name"]), - VirtualRouterName: aws.String(rs.Primary.Attributes["name"]), - }) - if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + _, err := tfappmesh.FindVirtualRouterByThreePartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["name"]) + + if tfresource.NotFound(err) { continue } + if err != nil { return err } - return fmt.Errorf("still exist.") + + return fmt.Errorf("App Mesh Virtual Router %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckVirtualRouterExists(ctx context.Context, name string, v *appmesh.VirtualRouterData) resource.TestCheckFunc { +func testAccCheckVirtualRouterExists(ctx context.Context, n string, v *appmesh.VirtualRouterData) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppMeshConn() - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", name) + return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") + return fmt.Errorf("No App Mesh Virtual Router ID is set") } - resp, err := conn.DescribeVirtualRouterWithContext(ctx, &appmesh.DescribeVirtualRouterInput{ - MeshName: aws.String(rs.Primary.Attributes["mesh_name"]), - VirtualRouterName: aws.String(rs.Primary.Attributes["name"]), - }) + output, err := tfappmesh.FindVirtualRouterByThreePartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["name"]) + if err != nil { return err } - *v = *resp.VirtualRouter + *v = *output return nil } @@ -372,7 +367,33 @@ resource "aws_appmesh_virtual_router" "test" { `, meshName, vrName) } -func testAccVirtualRouterConfig_tags(meshName, vrName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { +func testAccVirtualRouterConfig_tags1(meshName, vrName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_router" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } + + tags = { + %[3]s = %[4]q + } +} +`, meshName, vrName, tagKey1, tagValue1) +} + +func testAccVirtualRouterConfig_tags2(meshName, vrName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q From 904192a9cedf02445d69af94c2714bbcedd78cae Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:13:46 -0400 Subject: [PATCH 13/36] Correct CHANGELOG entry. --- .changelog/26908.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/26908.txt b/.changelog/26908.txt index 8cbba3e0f96e..eca713fef7df 100644 --- a/.changelog/26908.txt +++ b/.changelog/26908.txt @@ -1,3 +1,3 @@ -``release-note:new-data-datasource +``release-note:new-data-source aws_appmesh_virtual_router ``` \ No newline at end of file From 5b24de5af49fcd550317069633ea64c038fbd1e7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:15:40 -0400 Subject: [PATCH 14/36] Use 'resource.ComposeAggregateTestCheckFunc'. --- internal/service/appmesh/mesh_data_source_test.go | 4 ++-- internal/service/appmesh/route_data_source_test.go | 8 ++++---- .../service/appmesh/virtual_service_data_source_test.go | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/service/appmesh/mesh_data_source_test.go b/internal/service/appmesh/mesh_data_source_test.go index 77eeb121ba3a..ab83ef909ace 100644 --- a/internal/service/appmesh/mesh_data_source_test.go +++ b/internal/service/appmesh/mesh_data_source_test.go @@ -83,7 +83,7 @@ func testAccMeshDataSource_specAndTagsSet(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccMeshDataSourceConfig_specAndTagsSet(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), @@ -117,7 +117,7 @@ func testAccMeshDataSource_shared(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccMeshDataSourceConfig_shared(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), diff --git a/internal/service/appmesh/route_data_source_test.go b/internal/service/appmesh/route_data_source_test.go index 91033bd5a5f6..cf4e7c654f5e 100644 --- a/internal/service/appmesh/route_data_source_test.go +++ b/internal/service/appmesh/route_data_source_test.go @@ -26,7 +26,7 @@ func testAccRouteDataSource_http2Route(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteDataSourceConfig_http2Route(meshName, vrName, vnName, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), @@ -64,7 +64,7 @@ func testAccRouteDataSource_httpRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteDataSourceConfig_httpRoute(meshName, vrName, vnName, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), @@ -103,7 +103,7 @@ func testAccRouteDataSource_grpcRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteDataSourceConfig_grpcRoute(meshName, vrName, vnName, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), @@ -142,7 +142,7 @@ func testAccRouteDataSource_tcpRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteDataSourceConfig_tcpRoute(meshName, vrName, vnName, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), diff --git a/internal/service/appmesh/virtual_service_data_source_test.go b/internal/service/appmesh/virtual_service_data_source_test.go index 555bfc04cd55..5c8867802d32 100644 --- a/internal/service/appmesh/virtual_service_data_source_test.go +++ b/internal/service/appmesh/virtual_service_data_source_test.go @@ -24,7 +24,7 @@ func testAccVirtualServiceDataSource_virtualNode(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVirtualServiceDataSourceConfig_virtualNode(rName, vsName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), @@ -58,7 +58,7 @@ func testAccVirtualServiceDataSource_virtualRouter(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVirtualServiceDataSourceConfig_virtualRouter(rName, vsName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), From 8224a2f45271cd5c52d8586a292c4df8e431456e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:20:05 -0400 Subject: [PATCH 15/36] d/aws_appmesh_virtual_router: Tidy up. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^VirtualRouter$$' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^VirtualRouter$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/VirtualRouter === RUN TestAccAppMesh_serial/VirtualRouter/basic === RUN TestAccAppMesh_serial/VirtualRouter/disappears === RUN TestAccAppMesh_serial/VirtualRouter/multiListener === RUN TestAccAppMesh_serial/VirtualRouter/tags === RUN TestAccAppMesh_serial/VirtualRouter/dataSourceBasic --- PASS: TestAccAppMesh_serial (116.06s) --- PASS: TestAccAppMesh_serial/VirtualRouter (116.06s) --- PASS: TestAccAppMesh_serial/VirtualRouter/basic (27.54s) --- PASS: TestAccAppMesh_serial/VirtualRouter/disappears (12.68s) --- PASS: TestAccAppMesh_serial/VirtualRouter/multiListener (26.02s) --- PASS: TestAccAppMesh_serial/VirtualRouter/tags (35.88s) --- PASS: TestAccAppMesh_serial/VirtualRouter/dataSourceBasic (13.94s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 121.285s --- internal/service/appmesh/appmesh_test.go | 9 +- .../appmesh/virtual_router_data_source.go | 96 ++++++------------- .../virtual_router_data_source_test.go | 48 ++++++---- 3 files changed, 61 insertions(+), 92 deletions(-) diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 7e010878b7a1..ee598cb4edae 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -92,10 +92,11 @@ func TestAccAppMesh_serial(t *testing.T) { "dataSourceBasic": testAccVirtualNodeDataSource_basic, }, "VirtualRouter": { - "basic": testAccVirtualRouter_basic, - "disappears": testAccVirtualRouter_disappears, - "multiListener": testAccVirtualRouter_multiListener, - "tags": testAccVirtualRouter_tags, + "basic": testAccVirtualRouter_basic, + "disappears": testAccVirtualRouter_disappears, + "multiListener": testAccVirtualRouter_multiListener, + "tags": testAccVirtualRouter_tags, + "dataSourceBasic": testAccVirtualRouterDataSource_basic, }, "VirtualService": { "disappears": testAccVirtualService_disappears, diff --git a/internal/service/appmesh/virtual_router_data_source.go b/internal/service/appmesh/virtual_router_data_source.go index 80a08c9cc294..3f45574aeef7 100644 --- a/internal/service/appmesh/virtual_router_data_source.go +++ b/internal/service/appmesh/virtual_router_data_source.go @@ -5,12 +5,12 @@ import ( "time" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/appmesh" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKDataSource("aws_appmesh_virtual_router") @@ -23,72 +23,33 @@ func DataSourceVirtualRouter() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "created_date": { Type: schema.TypeString, Computed: true, }, - "last_updated_date": { Type: schema.TypeString, Computed: true, }, - "mesh_name": { Type: schema.TypeString, Required: true, }, - "mesh_owner": { Type: schema.TypeString, + Optional: true, Computed: true, }, - "name": { Type: schema.TypeString, Required: true, }, - "resource_owner": { Type: schema.TypeString, Computed: true, }, - - "spec": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "listener": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port_mapping": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Computed: true, - }, - - "protocol": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - - "tags": tftags.TagsSchema(), + "spec": dataSourcePropertyFromResourceProperty(resourceVirtualRouterSpecSchema()), + names.AttrTags: tftags.TagsSchemaComputed(), }, } } @@ -98,41 +59,38 @@ func dataSourceVirtualRouterRead(ctx context.Context, d *schema.ResourceData, me conn := meta.(*conns.AWSClient).AppMeshConn() ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeVirtualRouterInput{ - MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualRouterName: aws.String(d.Get("name").(string)), - } + virtualRouterName := d.Get("name").(string) + vr, err := FindVirtualRouterByThreePartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), virtualRouterName) - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } - - resp, err := conn.DescribeVirtualRouterWithContext(ctx, req) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Router (%s): %s", virtualRouterName, err) } - arn := aws.StringValue(resp.VirtualRouter.Metadata.Arn) - - d.SetId(aws.StringValue(resp.VirtualRouter.VirtualRouterName)) - - d.Set("name", resp.VirtualRouter.VirtualRouterName) - d.Set("mesh_name", resp.VirtualRouter.MeshName) - d.Set("mesh_owner", resp.VirtualRouter.Metadata.MeshOwner) + d.SetId(aws.StringValue(vr.VirtualRouterName)) + arn := aws.StringValue(vr.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.VirtualRouter.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.VirtualRouter.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("resource_owner", resp.VirtualRouter.Metadata.ResourceOwner) - - err = d.Set("spec", flattenVirtualRouterSpec(resp.VirtualRouter.Spec)) - if err != nil { + d.Set("created_date", vr.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", vr.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", vr.MeshName) + meshOwner := aws.StringValue(vr.Metadata.MeshOwner) + d.Set("mesh_owner", meshOwner) + d.Set("name", vr.VirtualRouterName) + d.Set("resource_owner", vr.Metadata.ResourceOwner) + if err := d.Set("spec", flattenVirtualRouterSpec(vr.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } - tags, err := ListTags(ctx, conn, arn) + // https://docs.aws.amazon.com/app-mesh/latest/userguide/sharing.html#sharing-permissions + // Owners and consumers can list tags and can tag/untag resources in a mesh that the account created. + // They can't list tags and tag/untag resources in a mesh that aren't created by the account. + var tags tftags.KeyValueTags - if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Router (%s): %s", arn, err) + if meshOwner == meta.(*conns.AWSClient).AccountID { + tags, err = ListTags(ctx, conn, arn) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Router (%s): %s", arn, err) + } } if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { diff --git a/internal/service/appmesh/virtual_router_data_source_test.go b/internal/service/appmesh/virtual_router_data_source_test.go index 32d0beda2ac2..b3eecadf5556 100644 --- a/internal/service/appmesh/virtual_router_data_source_test.go +++ b/internal/service/appmesh/virtual_router_data_source_test.go @@ -10,14 +10,14 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" ) -func TestAccAppMeshVirtualRouterDataSource_basic(t *testing.T) { +func testAccVirtualRouterDataSource_basic(t *testing.T) { ctx := acctest.Context(t) virtualRouterName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_appmesh_virtual_router.test" dataSourceName := "data.aws_appmesh_virtual_router.test" - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, @@ -25,7 +25,7 @@ func TestAccAppMeshVirtualRouterDataSource_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVirtualRouterDataSourceConfig(meshName, virtualRouterName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), @@ -33,35 +33,45 @@ func TestAccAppMeshVirtualRouterDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.#", dataSourceName, "spec.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.#", dataSourceName, "spec.0.listener.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.0.port_mapping.#", dataSourceName, "spec.0.listener.0.port_mapping.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.0.port_mapping.0.port", dataSourceName, "spec.0.listener.0.port_mapping.0.port"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.0.port_mapping.0.protocol", dataSourceName, "spec.0.listener.0.port_mapping.0.protocol"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, }) } -func testAccVirtualRouterDataSourceConfig(meshName string, routerName string) string { +func testAccVirtualRouterDataSourceConfig(meshName, vrName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { - name = %[1]q + name = %[1]q } + resource "aws_appmesh_virtual_router" "test" { - name = %[2]q - mesh_name = aws_appmesh_mesh.test.id - spec { - listener { - port_mapping { - port = 8080 - protocol = "http" - } - } - } + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } + + tags = { + Name = %[2]q + } } + data "aws_appmesh_virtual_router" "test" { - name = aws_appmesh_virtual_router.test.name - mesh_name = aws_appmesh_mesh.test.name + name = aws_appmesh_virtual_router.test.name + mesh_name = aws_appmesh_mesh.test.name } -`, meshName, routerName) +`, meshName, vrName) } From e1882031ee58977a3c33e759daecd8d8cb4ae020 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:23:06 -0400 Subject: [PATCH 16/36] d/aws_appmesh_virtual_router: Update documentation. --- .../docs/d/appmesh_virtual_router.html.markdown | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/website/docs/d/appmesh_virtual_router.html.markdown b/website/docs/d/appmesh_virtual_router.html.markdown index e1cea9f5f377..6f6166db5319 100644 --- a/website/docs/d/appmesh_virtual_router.html.markdown +++ b/website/docs/d/appmesh_virtual_router.html.markdown @@ -34,18 +34,5 @@ In addition to all arguments above, the following attributes are exported: * `created_date` - Creation date of the virtual router. * `last_updated_date` - Last update date of the virtual router. * `resource_owner` - Resource owner's AWS account ID. -* `spec` - Virtual routers specification. +* `spec` - Virtual routers specification. See the [`aws_appmesh_virtual_router`](/docs/providers/aws/r/appmesh_virtual_router.html#spec) resource for details. * `tags` - Map of tags. - -### Spec - -* `listener` - The listener assigned to the virtual router - -### Listener - -* `port_mapping` - The port mapping of the listener - -### Port_Mapping - -* `port` - Port number the listener is listening on. -* `protocol` - Protocol the listener is listening for. From 4582bee5f4d8d01304900d89f5d993750da4bbba Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:29:44 -0400 Subject: [PATCH 17/36] r/aws_appmesh_gateway_route: Alphabetize attributes. --- internal/service/appmesh/gateway_route.go | 775 +++++++++++----------- 1 file changed, 383 insertions(+), 392 deletions(-) diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 0d882c29680f..a21428f8c0ef 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -20,6 +20,7 @@ import ( tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKResource("aws_appmesh_gateway_route") @@ -35,20 +36,24 @@ func ResourceGatewayRoute() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, }, - "mesh_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "mesh_owner": { Type: schema.TypeString, Optional: true, @@ -56,469 +61,455 @@ func ResourceGatewayRoute() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidAccountID, }, - + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + "spec": resourceGatewayRouteSpecSchema(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), "virtual_gateway_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 255), }, + }, - "spec": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "grpc_route": { - 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{ - "target": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceGatewayRouteSpecSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grpc_route": { + 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{ + "target": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_service": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_service_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, }, }, }, }, }, - - "match": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "service_name": { - Type: schema.TypeString, - Required: true, - }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - }, + }, + }, + "match": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "service_name": { + Type: schema.TypeString, + Required: true, }, }, }, }, - ExactlyOneOf: []string{ - "spec.0.grpc_route", - "spec.0.http2_route", - "spec.0.http_route", - }, }, - - "http2_route": { - 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{ - "target": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + }, + ExactlyOneOf: []string{ + "spec.0.grpc_route", + "spec.0.http2_route", + "spec.0.http_route", + }, + }, + "http_route": { + 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{ + "target": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_service": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_service_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, }, }, - "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", + }, + }, + "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), }, }, - "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.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", }, }, - AtLeastOneOf: []string{ - "spec.0.http2_route.0.action.0.rewrite.0.prefix", - "spec.0.http2_route.0.action.0.rewrite.0.hostname", + "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, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "prefix": { - Type: schema.TypeString, - 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", - }, - }, + }, + }, + "match": { + Type: schema.TypeList, + Required: 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{ + "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", }, }, - AtLeastOneOf: []string{ - "spec.0.http2_route.0.match.0.prefix", - "spec.0.http2_route.0.match.0.hostname", + "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", + }, }, }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, + }, + AtLeastOneOf: []string{ + "spec.0.http_route.0.match.0.prefix", + "spec.0.http_route.0.match.0.hostname", + }, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "prefix": { + Type: schema.TypeString, + 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", }, }, }, }, }, - ExactlyOneOf: []string{ - "spec.0.grpc_route", - "spec.0.http2_route", - "spec.0.http_route", - }, }, - - "http_route": { - 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{ - "target": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + }, + ExactlyOneOf: []string{ + "spec.0.grpc_route", + "spec.0.http2_route", + "spec.0.http_route", + }, + }, + "http2_route": { + 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{ + "target": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_service": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_service_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, }, }, - "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", + }, + }, + "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), }, }, - "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.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", }, }, - AtLeastOneOf: []string{ - "spec.0.http_route.0.action.0.rewrite.0.prefix", - "spec.0.http_route.0.action.0.rewrite.0.hostname", + "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", + }, }, }, }, }, }, - "match": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "prefix": { - Type: schema.TypeString, - 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", - }, - }, + }, + }, + "match": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "prefix": { + Type: schema.TypeString, + 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", }, }, - AtLeastOneOf: []string{ - "spec.0.http_route.0.match.0.prefix", - "spec.0.http_route.0.match.0.hostname", + "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", + }, }, }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, + AtLeastOneOf: []string{ + "spec.0.http2_route.0.match.0.prefix", + "spec.0.http2_route.0.match.0.hostname", + }, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, }, }, }, }, - ExactlyOneOf: []string{ - "spec.0.grpc_route", - "spec.0.http2_route", - "spec.0.http_route", - }, }, }, + ExactlyOneOf: []string{ + "spec.0.grpc_route", + "spec.0.http2_route", + "spec.0.http_route", + }, }, }, - - "arn": { - Type: schema.TypeString, - Computed: true, - }, - - "created_date": { - Type: schema.TypeString, - Computed: true, - }, - - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - - "resource_owner": { - Type: schema.TypeString, - Computed: true, - }, - - "tags": tftags.TagsSchema(), - - "tags_all": tftags.TagsSchemaComputed(), }, - - CustomizeDiff: verify.SetTagsDiff, } } From 16f919ba0dae21304f023291734fe3e2e4a40c27 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:34:13 -0400 Subject: [PATCH 18/36] r/aws_appmesh_gateway_route: Tidy up resource Create, Update and Delete. --- internal/service/appmesh/gateway_route.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index a21428f8c0ef..b8e5b37f57f6 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -519,22 +519,23 @@ func resourceGatewayRouteCreate(ctx context.Context, d *schema.ResourceData, met defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) + name := d.Get("name").(string) input := &appmesh.CreateGatewayRouteInput{ - GatewayRouteName: aws.String(d.Get("name").(string)), + GatewayRouteName: aws.String(name), MeshName: aws.String(d.Get("mesh_name").(string)), Spec: expandGatewayRouteSpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), VirtualGatewayName: aws.String(d.Get("virtual_gateway_name").(string)), } + if v, ok := d.GetOk("mesh_owner"); ok { input.MeshOwner = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating App Mesh gateway route: %s", input) output, err := conn.CreateGatewayRouteWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh gateway route: %s", err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Gateway Route (%s): %s", name, err) } d.SetId(aws.StringValue(output.GatewayRoute.Metadata.Uid)) @@ -645,24 +646,24 @@ func resourceGatewayRouteUpdate(ctx context.Context, d *schema.ResourceData, met Spec: expandGatewayRouteSpec(d.Get("spec").([]interface{})), VirtualGatewayName: aws.String(d.Get("virtual_gateway_name").(string)), } + if v, ok := d.GetOk("mesh_owner"); ok { input.MeshOwner = aws.String(v.(string)) } - log.Printf("[DEBUG] Updating App Mesh gateway route: %s", input) _, err := conn.UpdateGatewayRouteWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh gateway route (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Gateway Route (%s): %s", d.Id(), err) } } - arn := d.Get("arn").(string) if d.HasChange("tags_all") { + arn := d.Get("arn").(string) o, n := d.GetChange("tags_all") if err := UpdateTags(ctx, conn, arn, o, n); err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh gateway route (%s) tags: %s", arn, err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Gateway Route (%s) tags: %s", arn, err) } } From 01e67d4c68cfb71c798201a7b106844382e44196 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 12:39:42 -0400 Subject: [PATCH 19/36] r/aws_appmesh_gateway_route: Tidy up resource Read. --- internal/service/appmesh/gateway_route.go | 110 ++++++++++++---------- 1 file changed, 59 insertions(+), 51 deletions(-) diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index b8e5b37f57f6..263249aa561a 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -549,57 +549,21 @@ func resourceGatewayRouteRead(ctx context.Context, d *schema.ResourceData, meta defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - var gatewayRoute *appmesh.GatewayRouteData + outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, propagationTimeout, func() (interface{}, error) { + return FindGatewayRouteByFourPartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("virtual_gateway_name").(string), d.Get("name").(string)) + }, d.IsNewResource()) - err := resource.RetryContext(ctx, propagationTimeout, func() *resource.RetryError { - var err error - - gatewayRoute, err = FindGatewayRoute(ctx, conn, d.Get("mesh_name").(string), d.Get("virtual_gateway_name").(string), d.Get("name").(string), d.Get("mesh_owner").(string)) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return nil - }) - - if tfresource.TimedOut(err) { - gatewayRoute, err = FindGatewayRoute(ctx, conn, d.Get("mesh_name").(string), d.Get("virtual_gateway_name").(string), d.Get("name").(string), d.Get("mesh_owner").(string)) - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] App Mesh Gateway Route (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Gateway Route: %s", err) - } - - if gatewayRoute == nil { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Gateway Route: not found after creation") - } - - log.Printf("[WARN] App Mesh Gateway Route (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags + return sdkdiag.AppendErrorf(diags, "reading App Mesh Gateway Route (%s): %s", d.Id(), err) } - if aws.StringValue(gatewayRoute.Status.Status) == appmesh.GatewayRouteStatusCodeDeleted { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Gateway Route: %s after creation", aws.StringValue(gatewayRoute.Status.Status)) - } - - log.Printf("[WARN] App Mesh Gateway Route (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } + gatewayRoute := outputRaw.(*appmesh.GatewayRouteData) arn := aws.StringValue(gatewayRoute.Metadata.Arn) d.Set("arn", arn) @@ -609,8 +573,7 @@ func resourceGatewayRouteRead(ctx context.Context, d *schema.ResourceData, meta d.Set("mesh_owner", gatewayRoute.Metadata.MeshOwner) d.Set("name", gatewayRoute.GatewayRouteName) d.Set("resource_owner", gatewayRoute.Metadata.ResourceOwner) - err = d.Set("spec", flattenGatewayRouteSpec(gatewayRoute.Spec)) - if err != nil { + if err := d.Set("spec", flattenGatewayRouteSpec(gatewayRoute.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } d.Set("virtual_gateway_name", gatewayRoute.VirtualGatewayName) @@ -618,7 +581,7 @@ func resourceGatewayRouteRead(ctx context.Context, d *schema.ResourceData, meta tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh gateway route (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Gateway Route (%s): %s", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -704,14 +667,12 @@ func resourceGatewayRouteImport(ctx context.Context, d *schema.ResourceData, met return []*schema.ResourceData{}, fmt.Errorf("wrong format of import ID (%s), use: 'mesh-name/virtual-gateway-name/gateway-route-name'", d.Id()) } - mesh := parts[0] - vgName := parts[1] - name := parts[2] - log.Printf("[DEBUG] Importing App Mesh gateway route %s from mesh %s/virtual gateway %s ", name, mesh, vgName) - conn := meta.(*conns.AWSClient).AppMeshConn() + meshName := parts[0] + virtualGatewayName := parts[1] + name := parts[2] - gatewayRoute, err := FindGatewayRoute(ctx, conn, mesh, vgName, name, "") + gatewayRoute, err := FindGatewayRouteByFourPartKey(ctx, conn, meshName, "", virtualGatewayName, name) if err != nil { return nil, err @@ -725,6 +686,53 @@ func resourceGatewayRouteImport(ctx context.Context, d *schema.ResourceData, met return []*schema.ResourceData{d}, nil } +func FindGatewayRouteByFourPartKey(ctx context.Context, conn *appmesh.AppMesh, meshName, meshOwner, virtualGatewayName, name string) (*appmesh.GatewayRouteData, error) { + input := &appmesh.DescribeGatewayRouteInput{ + GatewayRouteName: aws.String(name), + MeshName: aws.String(meshName), + VirtualGatewayName: aws.String(virtualGatewayName), + } + if meshOwner != "" { + input.MeshOwner = aws.String(meshOwner) + } + + output, err := findGatewayRoute(ctx, conn, input) + + if err != nil { + return nil, err + } + + if status := aws.StringValue(output.Status.Status); status == appmesh.GatewayRouteStatusCodeDeleted { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + return output, nil +} + +func findGatewayRoute(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.DescribeGatewayRouteInput) (*appmesh.GatewayRouteData, error) { + output, err := conn.DescribeGatewayRouteWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.GatewayRoute == nil || output.GatewayRoute.Metadata == nil || output.GatewayRoute.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.GatewayRoute, nil +} + func expandGatewayRouteSpec(vSpec []interface{}) *appmesh.GatewayRouteSpec { if len(vSpec) == 0 || vSpec[0] == nil { return nil From af8869f7011f9f6fa50afeee43dc57535d3b5f3f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 13:40:43 -0400 Subject: [PATCH 20/36] r/aws_appmesh_gateway_route: Tidy up acceptance tests. --- internal/service/appmesh/appmesh_test.go | 2 +- internal/service/appmesh/find.go | 32 ---- .../service/appmesh/gateway_route_test.go | 157 +++++++++++------- 3 files changed, 95 insertions(+), 96 deletions(-) delete mode 100644 internal/service/appmesh/find.go diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index ee598cb4edae..9164e01bfda0 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -22,7 +22,7 @@ func TestAccAppMesh_serial(t *testing.T) { "http2Route": testAccGatewayRoute_HTTP2Route, "http2RouteTargetPort": testAccGatewayRoute_HTTP2RouteTargetPort, "http2RouteWithPort": testAccGatewayRoute_HTTP2RouteWithPort, - "tags": testAccGatewayRoute_Tags, + "tags": testAccGatewayRoute_tags, }, "Mesh": { "basic": testAccMesh_basic, diff --git a/internal/service/appmesh/find.go b/internal/service/appmesh/find.go deleted file mode 100644 index 34d40766c8f3..000000000000 --- a/internal/service/appmesh/find.go +++ /dev/null @@ -1,32 +0,0 @@ -package appmesh - -import ( - "context" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/appmesh" -) - -// FindGatewayRoute returns the gateway route corresponding to the specified mesh name, virtual gateway name, gateway route name and optional mesh owner. -// Returns an error if no gateway route is found. -func FindGatewayRoute(ctx context.Context, conn *appmesh.AppMesh, meshName, virtualGatewayName, gatewayRouteName, meshOwner string) (*appmesh.GatewayRouteData, error) { - input := &appmesh.DescribeGatewayRouteInput{ - GatewayRouteName: aws.String(gatewayRouteName), - MeshName: aws.String(meshName), - VirtualGatewayName: aws.String(virtualGatewayName), - } - if meshOwner != "" { - input.MeshOwner = aws.String(meshOwner) - } - - output, err := conn.DescribeGatewayRouteWithContext(ctx, input) - if err != nil { - return nil, err - } - - if output == nil { - return nil, nil - } - - return output.GatewayRoute, nil -} diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index 7384a14e998d..79d950e0cc73 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -6,13 +6,13 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/appmesh" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func testAccGatewayRoute_basic(t *testing.T) { @@ -32,7 +32,7 @@ func testAccGatewayRoute_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_httpRoute(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -52,6 +52,7 @@ func testAccGatewayRoute_basic(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -108,7 +109,7 @@ func testAccGatewayRoute_GRPCRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_grpcRoute(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -128,11 +129,12 @@ func testAccGatewayRoute_GRPCRoute(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_grpcRouteUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -152,6 +154,7 @@ func testAccGatewayRoute_GRPCRoute(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -182,7 +185,7 @@ func testAccGatewayRoute_GRPCRouteWithPort(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_grpcRouteWithPort(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -203,11 +206,12 @@ func testAccGatewayRoute_GRPCRouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_grpcRouteWithPortUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -228,6 +232,7 @@ func testAccGatewayRoute_GRPCRouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -257,7 +262,7 @@ func testAccGatewayRoute_GRPCRouteTargetPort(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_grpcRouteTargetPort(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -278,11 +283,12 @@ func testAccGatewayRoute_GRPCRouteTargetPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_grpcRouteTargetPortUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -303,6 +309,7 @@ func testAccGatewayRoute_GRPCRouteTargetPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -333,7 +340,7 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_httpRoute(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -353,11 +360,12 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -377,11 +385,12 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteMatchHostname(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -402,11 +411,12 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteRewrite(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -431,6 +441,7 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -460,7 +471,7 @@ func testAccGatewayRoute_HTTPRouteTargetPort(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_httpRouteTargetPort(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -481,11 +492,12 @@ func testAccGatewayRoute_HTTPRouteTargetPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteTargetPortUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -506,6 +518,7 @@ func testAccGatewayRoute_HTTPRouteTargetPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -536,7 +549,7 @@ func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_httpRouteWithPort(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -557,11 +570,12 @@ func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteWithPortUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -582,11 +596,12 @@ func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteMatchHostname(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -607,11 +622,12 @@ func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_httpRouteRewrite(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -636,6 +652,7 @@ func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -666,7 +683,7 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_http2Route(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -686,11 +703,12 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -710,11 +728,12 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteMatchHostname(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -735,11 +754,12 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteRewrite(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -764,6 +784,7 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -793,7 +814,7 @@ func testAccGatewayRoute_HTTP2RouteTargetPort(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_http2RouteTargetPort(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -814,11 +835,12 @@ func testAccGatewayRoute_HTTP2RouteTargetPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteTargetPortUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -839,6 +861,7 @@ func testAccGatewayRoute_HTTP2RouteTargetPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -869,7 +892,7 @@ func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccGatewayRouteConfig_http2RouteWithPort(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -890,11 +913,12 @@ func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteWithPortUpdated(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -915,11 +939,12 @@ func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteMatchHostname(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -940,11 +965,12 @@ func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { Config: testAccGatewayRouteConfig_http2RouteRewrite(meshName, vgName, grName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckGatewayRouteExists(ctx, resourceName, &v), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), @@ -969,6 +995,7 @@ func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { @@ -981,7 +1008,7 @@ func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { }) } -func testAccGatewayRoute_Tags(t *testing.T) { +func testAccGatewayRoute_tags(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -1050,45 +1077,49 @@ func testAccCheckGatewayRouteDestroy(ctx context.Context) resource.TestCheckFunc continue } - _, err := tfappmesh.FindGatewayRoute(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["virtual_gateway_name"], rs.Primary.Attributes["name"], rs.Primary.Attributes["mesh_owner"]) - if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + _, err := tfappmesh.FindGatewayRouteByFourPartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["virtual_gateway_name"], rs.Primary.Attributes["name"]) + + if tfresource.NotFound(err) { continue } + if err != nil { return err } - return fmt.Errorf("App Mesh gateway route still exists: %s", rs.Primary.ID) + + return fmt.Errorf("App Mesh Gateway Route %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckGatewayRouteExists(ctx context.Context, name string, v *appmesh.GatewayRouteData) resource.TestCheckFunc { +func testAccCheckGatewayRouteExists(ctx context.Context, n string, v *appmesh.GatewayRouteData) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppMeshConn() - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", name) + return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No App Mesh gateway route ID is set") + return fmt.Errorf("No App Mesh Gateway Route ID is set") } - out, err := tfappmesh.FindGatewayRoute(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["virtual_gateway_name"], rs.Primary.Attributes["name"], rs.Primary.Attributes["mesh_owner"]) + output, err := tfappmesh.FindGatewayRouteByFourPartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["virtual_gateway_name"], rs.Primary.Attributes["name"]) + if err != nil { return err } - *v = *out + *v = *output return nil } } -func testAccGatewayRouteConfigBase(meshName, vgName, protocol string) string { +func testAccGatewayRouteConfig_base(meshName, vgName, protocol string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q @@ -1164,7 +1195,7 @@ resource "aws_appmesh_virtual_service" "multi_test" { } func testAccGatewayRouteConfig_grpcRoute(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1190,7 +1221,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_grpcRouteUpdated(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1217,7 +1248,7 @@ resource "aws_appmesh_gateway_route" "test" { func testAccGatewayRouteConfig_grpcRouteTargetPort(meshName, vgName, grName string) string { return acctest.ConfigCompose( - testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), + testAccGatewayRouteConfig_base(meshName, vgName, "grpc"), testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1247,7 +1278,7 @@ resource "aws_appmesh_gateway_route" "test" { func testAccGatewayRouteConfig_grpcRouteTargetPortUpdated(meshName, vgName, grName string) string { return acctest.ConfigCompose( - testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), + testAccGatewayRouteConfig_base(meshName, vgName, "grpc"), testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1276,7 +1307,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_grpcRouteWithPort(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1303,7 +1334,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_grpcRouteWithPortUpdated(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "grpc"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "grpc"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1330,7 +1361,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_httpRoute(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1356,7 +1387,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_httpRouteUpdated(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1383,7 +1414,7 @@ resource "aws_appmesh_gateway_route" "test" { func testAccGatewayRouteConfig_httpRouteTargetPort(meshName, vgName, grName string) string { return acctest.ConfigCompose( - testAccGatewayRouteConfigBase(meshName, vgName, "http"), + testAccGatewayRouteConfig_base(meshName, vgName, "http"), testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1413,7 +1444,7 @@ resource "aws_appmesh_gateway_route" "test" { func testAccGatewayRouteConfig_httpRouteTargetPortUpdated(meshName, vgName, grName string) string { return acctest.ConfigCompose( - testAccGatewayRouteConfigBase(meshName, vgName, "http"), + testAccGatewayRouteConfig_base(meshName, vgName, "http"), testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1442,7 +1473,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_httpRouteWithPort(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1469,7 +1500,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_httpRouteWithPortUpdated(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1496,7 +1527,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_httpRouteMatchHostname(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1524,7 +1555,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_httpRouteRewrite(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1558,7 +1589,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_http2Route(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1584,7 +1615,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_http2RouteUpdated(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1611,7 +1642,7 @@ resource "aws_appmesh_gateway_route" "test" { func testAccGatewayRouteConfig_http2RouteTargetPort(meshName, vgName, grName string) string { return acctest.ConfigCompose( - testAccGatewayRouteConfigBase(meshName, vgName, "http2"), + testAccGatewayRouteConfig_base(meshName, vgName, "http2"), testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1641,7 +1672,7 @@ resource "aws_appmesh_gateway_route" "test" { func testAccGatewayRouteConfig_http2RouteTargetPortUpdated(meshName, vgName, grName string) string { return acctest.ConfigCompose( - testAccGatewayRouteConfigBase(meshName, vgName, "http2"), + testAccGatewayRouteConfig_base(meshName, vgName, "http2"), testAccGatewayRouteConfig_ServiceNodeMultipleListeners(vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { @@ -1670,7 +1701,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_http2RouteWithPort(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1697,7 +1728,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_http2RouteWithPortUpdated(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1724,7 +1755,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_http2RouteMatchHostname(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1752,7 +1783,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_http2RouteRewrite(meshName, vgName, grName string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http2"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1786,7 +1817,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_tags1(meshName, vgName, grName, tagKey1, tagValue1 string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name @@ -1816,7 +1847,7 @@ resource "aws_appmesh_gateway_route" "test" { } func testAccGatewayRouteConfig_tags2(meshName, vgName, grName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(testAccGatewayRouteConfigBase(meshName, vgName, "http"), fmt.Sprintf(` + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.name From 83635c490a33a2b7f1a8a44626f0fbdd085deb0e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 13:41:13 -0400 Subject: [PATCH 21/36] d/aws_appmesh_route: Cosmetics. --- internal/service/appmesh/route_data_source.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/appmesh/route_data_source.go b/internal/service/appmesh/route_data_source.go index ee089ae6807c..5bd357fee0de 100644 --- a/internal/service/appmesh/route_data_source.go +++ b/internal/service/appmesh/route_data_source.go @@ -48,12 +48,12 @@ func DataSourceRoute() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "spec": dataSourcePropertyFromResourceProperty(resourceRouteSpecSchema()), + names.AttrTags: tftags.TagsSchemaComputed(), "virtual_router_name": { Type: schema.TypeString, Required: true, }, - "spec": dataSourcePropertyFromResourceProperty(resourceRouteSpecSchema()), - names.AttrTags: tftags.TagsSchemaComputed(), }, } } From c9098e3746406376cdc329c2064af716c689008c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 13:57:55 -0400 Subject: [PATCH 22/36] d/aws_appmesh_gateway_route: New data source. --- .changelog/29064.txt | 4 + internal/service/appmesh/appmesh_test.go | 19 +-- .../appmesh/gateway_route_data_source.go | 106 +++++++++++++++++ .../appmesh/gateway_route_data_source_test.go | 108 ++++++++++++++++++ .../service/appmesh/gateway_route_test.go | 18 +-- .../service/appmesh/service_package_gen.go | 4 + .../d/appmesh_gateway_route.html.markdown | 41 +++++++ website/docs/d/appmesh_mesh.html.markdown | 2 +- website/docs/d/appmesh_route.html.markdown | 2 +- .../d/appmesh_virtual_router.html.markdown | 2 +- .../d/appmesh_virtual_service.html.markdown | 2 +- 11 files changed, 286 insertions(+), 22 deletions(-) create mode 100644 internal/service/appmesh/gateway_route_data_source.go create mode 100644 internal/service/appmesh/gateway_route_data_source_test.go create mode 100644 website/docs/d/appmesh_gateway_route.html.markdown diff --git a/.changelog/29064.txt b/.changelog/29064.txt index 5faf6a907c20..cae8510c4566 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -1,3 +1,7 @@ ```release-note:enhancement resource/aws_appmesh_gateway_route: Add `port` to `target` block in order to support Virtual Services with multiple listeners. ``` + +```release-note:new-data-source +aws_appmesh_gateway_route +``` \ No newline at end of file diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 9164e01bfda0..be9845527722 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -13,16 +13,17 @@ func TestAccAppMesh_serial(t *testing.T) { "GatewayRoute": { "basic": testAccGatewayRoute_basic, "disappears": testAccGatewayRoute_disappears, - "grpcRoute": testAccGatewayRoute_GRPCRoute, - "grpcRouteTargetPort": testAccGatewayRoute_GRPCRouteTargetPort, - "grpcRouteWithPort": testAccGatewayRoute_GRPCRouteWithPort, - "httpRoute": testAccGatewayRoute_HTTPRoute, - "httpRouteTargetPort": testAccGatewayRoute_HTTPRouteTargetPort, - "httpRouteWithPort": testAccGatewayRoute_HTTPRouteWithPort, - "http2Route": testAccGatewayRoute_HTTP2Route, - "http2RouteTargetPort": testAccGatewayRoute_HTTP2RouteTargetPort, - "http2RouteWithPort": testAccGatewayRoute_HTTP2RouteWithPort, + "grpcRoute": testAccGatewayRoute_grpcRoute, + "grpcRouteTargetPort": testAccGatewayRoute_grpcRouteTargetPort, + "grpcRouteWithPort": testAccGatewayRoute_grpcRouteWithPort, + "httpRoute": testAccGatewayRoute_httpRoute, + "httpRouteTargetPort": testAccGatewayRoute_httpRouteTargetPort, + "httpRouteWithPort": testAccGatewayRoute_httpRouteWithPort, + "http2Route": testAccGatewayRoute_http2Route, + "http2RouteTargetPort": testAccGatewayRoute_http2RouteTargetPort, + "http2RouteWithPort": testAccGatewayRoute_http2RouteWithPort, "tags": testAccGatewayRoute_tags, + "dataSourceBasic": testAccGatewayRouteDataSource_basic, }, "Mesh": { "basic": testAccMesh_basic, diff --git a/internal/service/appmesh/gateway_route_data_source.go b/internal/service/appmesh/gateway_route_data_source.go new file mode 100644 index 000000000000..f1490031b612 --- /dev/null +++ b/internal/service/appmesh/gateway_route_data_source.go @@ -0,0 +1,106 @@ +package appmesh + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKDataSource("aws_appmesh_gateway_route") +func DataSourceGatewayRoute() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceGatewayRouteRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + "mesh_name": { + Type: schema.TypeString, + Required: true, + }, + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + "spec": dataSourcePropertyFromResourceProperty(resourceGatewayRouteSpecSchema()), + names.AttrTags: tftags.TagsSchemaComputed(), + "virtual_gateway_name": { + Type: schema.TypeString, + Required: true, + }, + }, + } +} + +func dataSourceGatewayRouteRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).AppMeshConn() + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + gatewayRouteName := d.Get("name").(string) + gatewayRoute, err := FindGatewayRouteByFourPartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("virtual_gateway_name").(string), gatewayRouteName) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading App Mesh Gateway Route (%s): %s", gatewayRouteName, err) + } + + d.SetId(aws.StringValue(gatewayRoute.GatewayRouteName)) + arn := aws.StringValue(gatewayRoute.Metadata.Arn) + d.Set("arn", arn) + d.Set("created_date", gatewayRoute.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", gatewayRoute.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", gatewayRoute.MeshName) + meshOwner := aws.StringValue(gatewayRoute.Metadata.MeshOwner) + d.Set("mesh_owner", meshOwner) + d.Set("name", gatewayRoute.GatewayRouteName) + d.Set("resource_owner", gatewayRoute.Metadata.ResourceOwner) + if err := d.Set("spec", flattenGatewayRouteSpec(gatewayRoute.Spec)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) + } + d.Set("virtual_gateway_name", gatewayRoute.VirtualGatewayName) + + // https://docs.aws.amazon.com/app-mesh/latest/userguide/sharing.html#sharing-permissions + // Owners and consumers can list tags and can tag/untag resources in a mesh that the account created. + // They can't list tags and tag/untag resources in a mesh that aren't created by the account. + var tags tftags.KeyValueTags + + if meshOwner == meta.(*conns.AWSClient).AccountID { + tags, err = ListTags(ctx, conn, arn) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Gateway Route (%s): %s", arn, err) + } + } + + if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) + } + + return diags +} diff --git a/internal/service/appmesh/gateway_route_data_source_test.go b/internal/service/appmesh/gateway_route_data_source_test.go new file mode 100644 index 000000000000..6480f56f2965 --- /dev/null +++ b/internal/service/appmesh/gateway_route_data_source_test.go @@ -0,0 +1,108 @@ +package appmesh_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/appmesh" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func testAccGatewayRouteDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + resourceName := "aws_appmesh_route.test" + dataSourceName := "data.aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vsName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + gwRouteName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccGatewayRouteDataSourceConfig_basic(meshName, vgName, vsName, gwRouteName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_name", dataSourceName, "mesh_name"), + resource.TestCheckResourceAttrPair(resourceName, "virtual_router_name", dataSourceName, "virtual_router_name"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.#", dataSourceName, "spec.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.grpc_route.#", dataSourceName, "spec.0.grpc_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.http_route.#", dataSourceName, "spec.0.http_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.http2_route.#", dataSourceName, "spec.0.http2_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), + ), + }, + }, + }) +} + +func testAccGatewayRouteDataSourceConfig_basic(meshName, vgName, vsName, gwRouteName string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_gateway" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } +} + +resource "aws_appmesh_virtual_service" "test" { + name = %[3]q + mesh_name = aws_appmesh_mesh.test.name + + spec {} +} + +resource "aws_appmesh_gateway_route" "test" { + name = %[4]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.name + } + } + } + + match { + prefix = "/" + } + } + } + + tags = { + Name = %[4]q + } +} + +data "aws_appmesh_gateway_route" "test" { + name = aws_appmesh_gateway_route.test.name + mesh_name = aws_appmesh_gateway_route.test.mesh_name + virtual_gateway_name = aws_appmesh_gateway_route.test.virtual_gateway_name +} +`, meshName, vgName, vsName, gwRouteName) +} diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index 79d950e0cc73..b8376a7f5c07 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -91,7 +91,7 @@ func testAccGatewayRoute_disappears(t *testing.T) { }) } -func testAccGatewayRoute_GRPCRoute(t *testing.T) { +func testAccGatewayRoute_grpcRoute(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -167,7 +167,7 @@ func testAccGatewayRoute_GRPCRoute(t *testing.T) { }) } -func testAccGatewayRoute_GRPCRouteWithPort(t *testing.T) { +func testAccGatewayRoute_grpcRouteWithPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -245,7 +245,7 @@ func testAccGatewayRoute_GRPCRouteWithPort(t *testing.T) { }) } -func testAccGatewayRoute_GRPCRouteTargetPort(t *testing.T) { +func testAccGatewayRoute_grpcRouteTargetPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -322,7 +322,7 @@ func testAccGatewayRoute_GRPCRouteTargetPort(t *testing.T) { }) } -func testAccGatewayRoute_HTTPRoute(t *testing.T) { +func testAccGatewayRoute_httpRoute(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -454,7 +454,7 @@ func testAccGatewayRoute_HTTPRoute(t *testing.T) { }) } -func testAccGatewayRoute_HTTPRouteTargetPort(t *testing.T) { +func testAccGatewayRoute_httpRouteTargetPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -531,7 +531,7 @@ func testAccGatewayRoute_HTTPRouteTargetPort(t *testing.T) { }) } -func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { +func testAccGatewayRoute_httpRouteWithPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -665,7 +665,7 @@ func testAccGatewayRoute_HTTPRouteWithPort(t *testing.T) { }) } -func testAccGatewayRoute_HTTP2Route(t *testing.T) { +func testAccGatewayRoute_http2Route(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -797,7 +797,7 @@ func testAccGatewayRoute_HTTP2Route(t *testing.T) { }) } -func testAccGatewayRoute_HTTP2RouteTargetPort(t *testing.T) { +func testAccGatewayRoute_http2RouteTargetPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" @@ -874,7 +874,7 @@ func testAccGatewayRoute_HTTP2RouteTargetPort(t *testing.T) { }) } -func testAccGatewayRoute_HTTP2RouteWithPort(t *testing.T) { +func testAccGatewayRoute_http2RouteWithPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData resourceName := "aws_appmesh_gateway_route.test" diff --git a/internal/service/appmesh/service_package_gen.go b/internal/service/appmesh/service_package_gen.go index 1791c2ac2d40..75a1cfc81929 100644 --- a/internal/service/appmesh/service_package_gen.go +++ b/internal/service/appmesh/service_package_gen.go @@ -21,6 +21,10 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePackageSDKDataSource { return []*types.ServicePackageSDKDataSource{ + { + Factory: DataSourceGatewayRoute, + TypeName: "aws_appmesh_gateway_route", + }, { Factory: DataSourceMesh, TypeName: "aws_appmesh_mesh", diff --git a/website/docs/d/appmesh_gateway_route.html.markdown b/website/docs/d/appmesh_gateway_route.html.markdown new file mode 100644 index 000000000000..ae6d8ce1be48 --- /dev/null +++ b/website/docs/d/appmesh_gateway_route.html.markdown @@ -0,0 +1,41 @@ +--- +subcategory: "App Mesh" +layout: "aws" +page_title: "AWS: aws_appmesh_gateway_route" +description: |- + Terraform data source for managing an AWS App Mesh Gateway Route. +--- + +# Data Source: aws_appmesh_gateway_route + +The App Mesh Gateway Route data source allows details of an App Mesh Gateway Route to be retrieved by its name, mesh_name, virtual_gateway_name, and optionally the mesh_owner. + +## Example Usage + +```hcl +data "aws_appmesh_gateway_route" "test" { + name = "test-route" + mesh_name = "test-mesh" + virtual_gateway_name = "test-gateway" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of the gateway route. +* `mesh_name` - (Required) Name of the service mesh in which the virtual gateway exists. +* `virtual_gateway_name` - (Required) Name of the virtual gateway in which the route exists. +* `mesh_owner` - (Optional) AWS account ID of the service mesh's owner. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the gateway route. +* `created_date` - Creation date of the gateway route. +* `last_updated_date` - Last update date of the gateway route. +* `resource_owner` - Resource owner's AWS account ID. +* `spec` - Gateway route specification. See the [`aws_appmesh_gateway_route`](/docs/providers/aws/r/appmesh_gateway_route.html#spec) resource for details. +* `tags` - Map of tags. diff --git a/website/docs/d/appmesh_mesh.html.markdown b/website/docs/d/appmesh_mesh.html.markdown index 926435558424..1a05c2b7a6de 100644 --- a/website/docs/d/appmesh_mesh.html.markdown +++ b/website/docs/d/appmesh_mesh.html.markdown @@ -3,7 +3,7 @@ subcategory: "App Mesh" layout: "aws" page_title: "AWS: aws_appmesh_mesh" description: |- - Provides details about an App Mesh Mesh service mesh resource. + Terraform data source for managing an AWS App Mesh Mesh. --- # Data Source: aws_appmesh_mesh diff --git a/website/docs/d/appmesh_route.html.markdown b/website/docs/d/appmesh_route.html.markdown index b19a366aadb7..1c5ee0d9afea 100644 --- a/website/docs/d/appmesh_route.html.markdown +++ b/website/docs/d/appmesh_route.html.markdown @@ -3,7 +3,7 @@ subcategory: "App Mesh" layout: "aws" page_title: "AWS: aws_appmesh_route" description: |- - Provides an AWS App Mesh route resource. + Terraform data source for managing an AWS App Mesh Route. --- # Data Source: aws_appmesh_route diff --git a/website/docs/d/appmesh_virtual_router.html.markdown b/website/docs/d/appmesh_virtual_router.html.markdown index 6f6166db5319..090c43be60e9 100644 --- a/website/docs/d/appmesh_virtual_router.html.markdown +++ b/website/docs/d/appmesh_virtual_router.html.markdown @@ -3,7 +3,7 @@ subcategory: "App Mesh" layout: "aws" page_title: "AWS: aws_appmesh_virtual_router" description: |- - Provides an AWS App Mesh virtual router resource. + Terraform data source for managing an AWS App Mesh Virtual Router. --- # Data Source: aws_appmesh_virtual_router diff --git a/website/docs/d/appmesh_virtual_service.html.markdown b/website/docs/d/appmesh_virtual_service.html.markdown index 749948352151..afdcbb45e5be 100644 --- a/website/docs/d/appmesh_virtual_service.html.markdown +++ b/website/docs/d/appmesh_virtual_service.html.markdown @@ -3,7 +3,7 @@ subcategory: "App Mesh" layout: "aws" page_title: "AWS: aws_appmesh_virtual_service" description: |- - Provides an AWS App Mesh virtual service resource. + Terraform data source for managing an AWS App Mesh Virtual Service. --- # Data Source: aws_appmesh_virtual_service From 360df73760d3c71d807e40cd4f382ffac063db06 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 14:01:15 -0400 Subject: [PATCH 23/36] Tweak CHANGELOG entry. --- .changelog/29064.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index cae8510c4566..ba2783ec5528 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -1,5 +1,5 @@ ```release-note:enhancement -resource/aws_appmesh_gateway_route: Add `port` to `target` block in order to support Virtual Services with multiple listeners. +resource/aws_appmesh_gateway_route: Add `port` to the `grpc_route.action.target`, `http_route.action.target` and `http2_route.action.target` configuration blocks to support Virtual Services with multiple listeners ``` ```release-note:new-data-source From 22ed63259c7ea7f2ec1fd60c4ae638bc6212f834 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 14:30:17 -0400 Subject: [PATCH 24/36] Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^GatewayRoute$$' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^GatewayRoute$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/GatewayRoute === RUN TestAccAppMesh_serial/GatewayRoute/basic === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/tags === RUN TestAccAppMesh_serial/GatewayRoute/dataSourceBasic === RUN TestAccAppMesh_serial/GatewayRoute/disappears === RUN TestAccAppMesh_serial/GatewayRoute/grpcRoute === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRoute === RUN TestAccAppMesh_serial/GatewayRoute/http2Route === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort --- PASS: TestAccAppMesh_serial (425.11s) --- PASS: TestAccAppMesh_serial/GatewayRoute (425.11s) --- PASS: TestAccAppMesh_serial/GatewayRoute/basic (17.38s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort (29.21s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort (29.89s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort (49.58s) --- PASS: TestAccAppMesh_serial/GatewayRoute/tags (39.81s) --- PASS: TestAccAppMesh_serial/GatewayRoute/dataSourceBasic (15.33s) --- PASS: TestAccAppMesh_serial/GatewayRoute/disappears (13.64s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRoute (28.18s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort (27.62s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRoute (49.60s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2Route (50.79s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort (29.98s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort (50.86s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 440.219s --- internal/service/appmesh/gateway_route_data_source_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/appmesh/gateway_route_data_source_test.go b/internal/service/appmesh/gateway_route_data_source_test.go index 6480f56f2965..8b58d4ee90f9 100644 --- a/internal/service/appmesh/gateway_route_data_source_test.go +++ b/internal/service/appmesh/gateway_route_data_source_test.go @@ -12,8 +12,8 @@ import ( func testAccGatewayRouteDataSource_basic(t *testing.T) { ctx := acctest.Context(t) - resourceName := "aws_appmesh_route.test" - dataSourceName := "data.aws_appmesh_route.test" + resourceName := "aws_appmesh_gateway_route.test" + dataSourceName := "data.aws_appmesh_gateway_route.test" meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) vsName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) From e2e43c33151a541aac495a42c33e1506c376d1a3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 14:35:50 -0400 Subject: [PATCH 25/36] Fix terrafmt error. --- internal/service/appmesh/virtual_router_data_source_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appmesh/virtual_router_data_source_test.go b/internal/service/appmesh/virtual_router_data_source_test.go index b3eecadf5556..665f2e73f449 100644 --- a/internal/service/appmesh/virtual_router_data_source_test.go +++ b/internal/service/appmesh/virtual_router_data_source_test.go @@ -70,7 +70,7 @@ resource "aws_appmesh_virtual_router" "test" { } data "aws_appmesh_virtual_router" "test" { - name = aws_appmesh_virtual_router.test.name + name = aws_appmesh_virtual_router.test.name mesh_name = aws_appmesh_mesh.test.name } `, meshName, vrName) From 73912de8738de9b69ccb0a5d0f38c0a9077d2652 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 14:36:36 -0400 Subject: [PATCH 26/36] Fix terrafmt error in documentation. --- website/docs/d/appmesh_virtual_router.html.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/docs/d/appmesh_virtual_router.html.markdown b/website/docs/d/appmesh_virtual_router.html.markdown index 090c43be60e9..36a830de7f2c 100644 --- a/website/docs/d/appmesh_virtual_router.html.markdown +++ b/website/docs/d/appmesh_virtual_router.html.markdown @@ -14,8 +14,8 @@ The App Mesh Virtual Router data source allows details of an App Mesh Virtual Se ```hcl data "aws_appmesh_virtual_router" "test" { - name = "example-router-name" - mesh_name = "example-mesh-name" + name = "example-router-name" + mesh_name = "example-mesh-name" } ``` From 126c4bf59df22be304b804ff8bc6a2a1d2292860 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 15:11:38 -0400 Subject: [PATCH 27/36] r/aws_appmesh_gateway_route: Add 'spec.priority'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^GatewayRoute$$' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^GatewayRoute$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/GatewayRoute === RUN TestAccAppMesh_serial/GatewayRoute/disappears === RUN TestAccAppMesh_serial/GatewayRoute/grpcRoute === RUN TestAccAppMesh_serial/GatewayRoute/http2Route === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/tags === RUN TestAccAppMesh_serial/GatewayRoute/basic === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRoute === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/dataSourceBasic --- PASS: TestAccAppMesh_serial (446.31s) --- PASS: TestAccAppMesh_serial/GatewayRoute (446.30s) --- PASS: TestAccAppMesh_serial/GatewayRoute/disappears (15.53s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRoute (28.03s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2Route (51.30s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort (50.73s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort (34.87s) --- PASS: TestAccAppMesh_serial/GatewayRoute/tags (39.06s) --- PASS: TestAccAppMesh_serial/GatewayRoute/basic (16.65s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort (35.25s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort (27.60s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRoute (51.72s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort (29.25s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort (50.87s) --- PASS: TestAccAppMesh_serial/GatewayRoute/dataSourceBasic (15.44s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 452.662s --- .changelog/29064.txt | 6 +++++- internal/service/appmesh/gateway_route.go | 10 ++++++++++ .../service/appmesh/gateway_route_data_source_test.go | 1 + internal/service/appmesh/gateway_route_test.go | 7 +++++++ website/docs/r/appmesh_gateway_route.html.markdown | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index ba2783ec5528..a6266159ea8b 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -1,7 +1,11 @@ ```release-note:enhancement -resource/aws_appmesh_gateway_route: Add `port` to the `grpc_route.action.target`, `http_route.action.target` and `http2_route.action.target` configuration blocks to support Virtual Services with multiple listeners +resource/aws_appmesh_gateway_route: Add `port` to the `spec.grpc_route.action.target`, `spec.http_route.action.target` and `spec.http2_route.action.target` configuration blocks to support Virtual Services with multiple listeners ``` ```release-note:new-data-source aws_appmesh_gateway_route +``` + +```release-note:enhancement +resource/aws_appmesh_gateway_route: Add `priority` to the `spec` configuration block ``` \ No newline at end of file diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 263249aa561a..387c8e291162 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -508,6 +508,11 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { "spec.0.http_route", }, }, + "priority": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 1000), + }, }, }, } @@ -754,6 +759,10 @@ func expandGatewayRouteSpec(vSpec []interface{}) *appmesh.GatewayRouteSpec { spec.HttpRoute = expandHTTPGatewayRoute(vHttpRoute) } + if vPriority, ok := mSpec["priority"].(int); ok && vPriority > 0 { + spec.Priority = aws.Int64(int64(vPriority)) + } + return spec } @@ -931,6 +940,7 @@ func flattenGatewayRouteSpec(spec *appmesh.GatewayRouteSpec) []interface{} { "grpc_route": flattenGRPCGatewayRoute(spec.GrpcRoute), "http2_route": flattenHTTPGatewayRoute(spec.Http2Route), "http_route": flattenHTTPGatewayRoute(spec.HttpRoute), + "priority": int(aws.Int64Value(spec.Priority)), } return []interface{}{mSpec} diff --git a/internal/service/appmesh/gateway_route_data_source_test.go b/internal/service/appmesh/gateway_route_data_source_test.go index 8b58d4ee90f9..b51f7723e0bf 100644 --- a/internal/service/appmesh/gateway_route_data_source_test.go +++ b/internal/service/appmesh/gateway_route_data_source_test.go @@ -39,6 +39,7 @@ func testAccGatewayRouteDataSource_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "spec.0.grpc_route.#", dataSourceName, "spec.0.grpc_route.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.http_route.#", dataSourceName, "spec.0.http_route.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.http2_route.#", dataSourceName, "spec.0.http2_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.priority", dataSourceName, "spec.0.priority"), resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index b8376a7f5c07..0b17214fe7ef 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -47,6 +47,7 @@ func testAccGatewayRoute_basic(t *testing.T) { resource.TestCheckResourceAttrPair(resourceName, "spec.0.http_route.0.action.0.target.0.virtual_service.0.virtual_service_name", vsResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), @@ -124,6 +125,7 @@ func testAccGatewayRoute_grpcRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", "test1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "7"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), @@ -149,6 +151,7 @@ func testAccGatewayRoute_grpcRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.grpc_route.0.match.0.service_name", "test2"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "77"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), @@ -1215,6 +1218,8 @@ resource "aws_appmesh_gateway_route" "test" { service_name = "test1" } } + + priority = 7 } } `, grName)) @@ -1241,6 +1246,8 @@ resource "aws_appmesh_gateway_route" "test" { service_name = "test2" } } + + priority = 77 } } `, grName)) diff --git a/website/docs/r/appmesh_gateway_route.html.markdown b/website/docs/r/appmesh_gateway_route.html.markdown index 32d24dcb9501..6f999fc22396 100644 --- a/website/docs/r/appmesh_gateway_route.html.markdown +++ b/website/docs/r/appmesh_gateway_route.html.markdown @@ -56,6 +56,7 @@ The `spec` object supports the following: * `grpc_route` - (Optional) Specification of a gRPC gateway route. * `http_route` - (Optional) Specification of an HTTP gateway route. * `http2_route` - (Optional) Specification of an HTTP/2 gateway route. +* `priority` - (Optional) Priority for the gateway route, between `0` and `1000`. The `grpc_route`, `http_route` and `http2_route` objects supports the following: From 14f7eec3232608ab0d7ccff171a825de7196a697 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 24 Mar 2023 16:20:14 -0400 Subject: [PATCH 28/36] r/aws_appmesh_virtual_node: Add 'spec.service_discovery.dns.ip_preference' and 'spec.service_discovery.dns.response_type'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^VirtualNode$$/listenerConnectionPool' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^VirtualNode$/listenerConnectionPool -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/VirtualNode === RUN TestAccAppMesh_serial/VirtualNode/listenerConnectionPool --- PASS: TestAccAppMesh_serial (28.52s) --- PASS: TestAccAppMesh_serial/VirtualNode (28.52s) --- PASS: TestAccAppMesh_serial/VirtualNode/listenerConnectionPool (28.52s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 34.002s --- .changelog/29064.txt | 4 ++++ internal/service/appmesh/flex.go | 12 +++++++++++- internal/service/appmesh/virtual_node.go | 10 ++++++++++ internal/service/appmesh/virtual_node_test.go | 8 +++++++- website/docs/r/appmesh_virtual_node.html.markdown | 2 ++ 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index a6266159ea8b..fc1a699a9a5e 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -8,4 +8,8 @@ aws_appmesh_gateway_route ```release-note:enhancement resource/aws_appmesh_gateway_route: Add `priority` to the `spec` configuration block +``` + +```release-note:enhancement +resource/aws_appmesh_virtual_node: Add `ip_preference` and `response_type` to the `spec.service_discovery.dns` configuration block ``` \ No newline at end of file diff --git a/internal/service/appmesh/flex.go b/internal/service/appmesh/flex.go index 3a8e56c53670..9bf643a5d554 100644 --- a/internal/service/appmesh/flex.go +++ b/internal/service/appmesh/flex.go @@ -1055,6 +1055,14 @@ func expandVirtualNodeSpec(vSpec []interface{}) *appmesh.VirtualNodeSpec { dns.Hostname = aws.String(vHostname) } + if vIPPreference, ok := mDns["ip_preference"].(string); ok && vIPPreference != "" { + dns.IpPreference = aws.String(vIPPreference) + } + + if vResponseType, ok := mDns["response_type"].(string); ok && vResponseType != "" { + dns.ResponseType = aws.String(vResponseType) + } + serviceDiscovery.Dns = dns } @@ -1804,7 +1812,9 @@ func flattenVirtualNodeSpec(spec *appmesh.VirtualNodeSpec) []interface{} { if dns := serviceDiscovery.Dns; dns != nil { mServiceDiscovery["dns"] = []interface{}{ map[string]interface{}{ - "hostname": aws.StringValue(dns.Hostname), + "hostname": aws.StringValue(dns.Hostname), + "ip_preference": aws.StringValue(dns.IpPreference), + "response_type": aws.StringValue(dns.ResponseType), }, } } diff --git a/internal/service/appmesh/virtual_node.go b/internal/service/appmesh/virtual_node.go index fd6134653eaa..8e28e21599ee 100644 --- a/internal/service/appmesh/virtual_node.go +++ b/internal/service/appmesh/virtual_node.go @@ -946,6 +946,16 @@ func resourceVirtualNodeSpecSchema() *schema.Schema { Required: true, ValidateFunc: validation.NoZeroValues, }, + "ip_preference": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(appmesh.IpPreference_Values(), false), + }, + "response_type": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(appmesh.DnsResponseType_Values(), false), + }, }, }, }, diff --git a/internal/service/appmesh/virtual_node_test.go b/internal/service/appmesh/virtual_node_test.go index ee95cfdb6737..edf11e7c4379 100644 --- a/internal/service/appmesh/virtual_node_test.go +++ b/internal/service/appmesh/virtual_node_test.go @@ -539,6 +539,8 @@ func testAccVirtualNode_listenerConnectionPool(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.ip_preference", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.response_type", ""), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), @@ -574,6 +576,8 @@ func testAccVirtualNode_listenerConnectionPool(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.ip_preference", "IPv4_ONLY"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.response_type", "ENDPOINTS"), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), @@ -1890,7 +1894,9 @@ resource "aws_appmesh_virtual_node" "test" { service_discovery { dns { - hostname = "serviceb.simpleapp.local" + hostname = "serviceb.simpleapp.local" + ip_preference = "IPv4_ONLY" + response_type = "ENDPOINTS" } } } diff --git a/website/docs/r/appmesh_virtual_node.html.markdown b/website/docs/r/appmesh_virtual_node.html.markdown index 69cc6a24ebe2..d859cf66000b 100644 --- a/website/docs/r/appmesh_virtual_node.html.markdown +++ b/website/docs/r/appmesh_virtual_node.html.markdown @@ -303,6 +303,8 @@ Use the [`aws_service_discovery_http_namespace`](/docs/providers/aws/r/service_d The `dns` object supports the following: * `hostname` - (Required) DNS host name for your virtual node. +* `ip_preference` - (Optional) The preferred IP version that this virtual node uses. Valid values: `IPv6_PREFERRED`, `IPv4_PREFERRED`, `IPv4_ONLY`, `IPv6_ONLY`. +* `response_type` - (Optional) The DNS response type for the virtual node. Valid values: `LOADBALANCER`, `ENDPOINTS`. The `port_mapping` object supports the following: From 5199edfcef620966138645999e1477845988fa0d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 13:44:20 -0400 Subject: [PATCH 29/36] r/aws_appmesh_route: Add 'spec.http_route.match.query_parameter' and 'spec.http2_route.match.query_parameter'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Route$$/httpRouteWithQueryParameterMatch' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^Route$/httpRouteWithQueryParameterMatch -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Route === RUN TestAccAppMesh_serial/Route/httpRouteWithQueryParameterMatch --- PASS: TestAccAppMesh_serial (17.59s) --- PASS: TestAccAppMesh_serial/Route (17.59s) --- PASS: TestAccAppMesh_serial/Route/httpRouteWithQueryParameterMatch (17.59s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 22.860s --- .changelog/29064.txt | 4 + internal/service/appmesh/appmesh_test.go | 45 ++--- internal/service/appmesh/flex.go | 57 ++++++- internal/service/appmesh/route.go | 29 ++++ internal/service/appmesh/route_test.go | 181 ++++++++++++++++----- website/docs/r/appmesh_route.html.markdown | 10 ++ 6 files changed, 259 insertions(+), 67 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index fc1a699a9a5e..142f1fcee971 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -12,4 +12,8 @@ resource/aws_appmesh_gateway_route: Add `priority` to the `spec` configuration b ```release-note:enhancement resource/aws_appmesh_virtual_node: Add `ip_preference` and `response_type` to the `spec.service_discovery.dns` configuration block +``` + +```release-note:enhancement +resource/aws_appmesh_gateway_route: Add `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks ``` \ No newline at end of file diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index be9845527722..3dd1c791b7f5 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -36,28 +36,29 @@ func TestAccAppMesh_serial(t *testing.T) { "dataSourceShared": testAccMeshDataSource_shared, }, "Route": { - "disappears": testAccRoute_disappears, - "grpcRoute": testAccRoute_grpcRoute, - "grpcRouteWithPortMatch": testAccRoute_grpcRouteWithPortMatch, - "grpcRouteEmptyMatch": testAccRoute_grpcRouteEmptyMatch, - "grpcRouteTimeout": testAccRoute_grpcRouteTimeout, - "http2Route": testAccRoute_http2Route, - "http2RouteWithPortMatch": testAccRoute_http2RouteWithPortMatch, - "http2RouteTimeout": testAccRoute_http2RouteTimeout, - "httpHeader": testAccRoute_httpHeader, - "httpRetryPolicy": testAccRoute_httpRetryPolicy, - "httpRoute": testAccRoute_httpRoute, - "httpRouteWithPortMatch": testAccRoute_httpRouteWithPortMatch, - "httpRouteTimeout": testAccRoute_httpRouteTimeout, - "routePriority": testAccRoute_routePriority, - "tcpRoute": testAccRoute_tcpRoute, - "tcpRouteWithPortMatch": testAccRoute_tcpRouteWithPortMatch, - "tcpRouteTimeout": testAccRoute_tcpRouteTimeout, - "tags": testAccRoute_tags, - "dataSourceHTTP2Route": testAccRouteDataSource_http2Route, - "dataSourceHTTPRoute": testAccRouteDataSource_httpRoute, - "dataSourceGRPCRoute": testAccRouteDataSource_grpcRoute, - "dataSourceTCPRoute": testAccRouteDataSource_tcpRoute, + "disappears": testAccRoute_disappears, + "grpcRoute": testAccRoute_grpcRoute, + "grpcRouteWithPortMatch": testAccRoute_grpcRouteWithPortMatch, + "grpcRouteEmptyMatch": testAccRoute_grpcRouteEmptyMatch, + "grpcRouteTimeout": testAccRoute_grpcRouteTimeout, + "http2Route": testAccRoute_http2Route, + "http2RouteWithPortMatch": testAccRoute_http2RouteWithPortMatch, + "http2RouteTimeout": testAccRoute_http2RouteTimeout, + "httpHeader": testAccRoute_httpHeader, + "httpRetryPolicy": testAccRoute_httpRetryPolicy, + "httpRoute": testAccRoute_httpRoute, + "httpRouteWithPortMatch": testAccRoute_httpRouteWithPortMatch, + "httpRouteWithQueryParameterMatch": testAccRoute_httpRouteWithQueryParameterMatch, + "httpRouteTimeout": testAccRoute_httpRouteTimeout, + "routePriority": testAccRoute_routePriority, + "tcpRoute": testAccRoute_tcpRoute, + "tcpRouteWithPortMatch": testAccRoute_tcpRouteWithPortMatch, + "tcpRouteTimeout": testAccRoute_tcpRouteTimeout, + "tags": testAccRoute_tags, + "dataSourceHTTP2Route": testAccRouteDataSource_http2Route, + "dataSourceHTTPRoute": testAccRouteDataSource_httpRoute, + "dataSourceGRPCRoute": testAccRouteDataSource_grpcRoute, + "dataSourceTCPRoute": testAccRouteDataSource_tcpRoute, }, "VirtualGateway": { "basic": testAccVirtualGateway_basic, diff --git a/internal/service/appmesh/flex.go b/internal/service/appmesh/flex.go index 9bf643a5d554..798666c93b76 100644 --- a/internal/service/appmesh/flex.go +++ b/internal/service/appmesh/flex.go @@ -445,6 +445,34 @@ func expandHTTPRoute(vHttpRoute []interface{}) *appmesh.HttpRoute { httpRouteMatch.Headers = httpRouteHeaders } + if vHttpRouteQueryParameters, ok := mHttpRouteMatch["query_parameter"].(*schema.Set); ok && vHttpRouteQueryParameters.Len() > 0 { + httpRouteQueryParameters := []*appmesh.HttpQueryParameter{} + + for _, vHttpRouteQueryParameter := range vHttpRouteQueryParameters.List() { + httpRouteQueryParameter := &appmesh.HttpQueryParameter{} + + mHttpRouteQueryParameter := vHttpRouteQueryParameter.(map[string]interface{}) + + if vName, ok := mHttpRouteQueryParameter["name"].(string); ok && vName != "" { + httpRouteQueryParameter.Name = aws.String(vName) + } + + if vMatch, ok := mHttpRouteQueryParameter["match"].([]interface{}); ok && len(vMatch) > 0 && vMatch[0] != nil { + httpRouteQueryParameter.Match = &appmesh.QueryParameterMatch{} + + mMatch := vMatch[0].(map[string]interface{}) + + if vExact, ok := mMatch["exact"].(string); ok && vExact != "" { + httpRouteQueryParameter.Match.Exact = aws.String(vExact) + } + } + + httpRouteQueryParameters = append(httpRouteQueryParameters, httpRouteQueryParameter) + } + + httpRouteMatch.QueryParameters = httpRouteQueryParameters + } + httpRoute.Match = httpRouteMatch } @@ -1414,13 +1442,32 @@ func flattenHTTPRoute(httpRoute *appmesh.HttpRoute) []interface{} { vHttpRouteHeaders = append(vHttpRouteHeaders, mHttpRouteHeader) } + vHttpRouteQueryParameters := []interface{}{} + + for _, httpRouteQueryParameter := range httpRouteMatch.QueryParameters { + mHttpRouteQueryParameter := map[string]interface{}{ + "name": aws.StringValue(httpRouteQueryParameter.Name), + } + + if match := httpRouteQueryParameter.Match; match != nil { + mMatch := map[string]interface{}{ + "exact": aws.StringValue(match.Exact), + } + + mHttpRouteQueryParameter["match"] = []interface{}{mMatch} + } + + vHttpRouteQueryParameters = append(vHttpRouteQueryParameters, mHttpRouteQueryParameter) + } + mHttpRoute["match"] = []interface{}{ map[string]interface{}{ - "header": vHttpRouteHeaders, - "method": aws.StringValue(httpRouteMatch.Method), - "prefix": aws.StringValue(httpRouteMatch.Prefix), - "scheme": aws.StringValue(httpRouteMatch.Scheme), - "port": int(aws.Int64Value(httpRouteMatch.Port)), + "header": vHttpRouteHeaders, + "method": aws.StringValue(httpRouteMatch.Method), + "prefix": aws.StringValue(httpRouteMatch.Prefix), + "scheme": aws.StringValue(httpRouteMatch.Scheme), + "port": int(aws.Int64Value(httpRouteMatch.Port)), + "query_parameter": vHttpRouteQueryParameters, }, } } diff --git a/internal/service/appmesh/route.go b/internal/service/appmesh/route.go index a76898e809a9..769cbbdc0004 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -221,6 +221,35 @@ func resourceRouteSpecSchema() *schema.Schema { Required: true, ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), }, + "query_parameter": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "scheme": { Type: schema.TypeString, Optional: true, diff --git a/internal/service/appmesh/route_test.go b/internal/service/appmesh/route_test.go index db806a819189..68a632d338d5 100644 --- a/internal/service/appmesh/route_test.go +++ b/internal/service/appmesh/route_test.go @@ -33,7 +33,7 @@ func testAccRoute_grpcRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_grpcRoute(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -76,7 +76,7 @@ func testAccRoute_grpcRoute(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -128,7 +128,7 @@ func testAccRoute_grpcRoute(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -180,7 +180,7 @@ func testAccRoute_grpcRoute(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteWithMaxRetriesZero(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -249,7 +249,7 @@ func testAccRoute_grpcRouteWithPortMatch(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_grpcRouteWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -294,7 +294,7 @@ func testAccRoute_grpcRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -349,7 +349,7 @@ func testAccRoute_grpcRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -401,7 +401,7 @@ func testAccRoute_grpcRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteWithMaxRetriesZero(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -470,7 +470,7 @@ func testAccRoute_grpcRouteTimeout(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_grpcRouteWithTimeout(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -506,7 +506,7 @@ func testAccRoute_grpcRouteTimeout(t *testing.T) { }, { Config: testAccRouteConfig_grpcRouteWithTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -570,7 +570,7 @@ func testAccRoute_grpcRouteEmptyMatch(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_grpcRouteWithEmptyMatch(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -624,7 +624,7 @@ func testAccRoute_http2Route(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_http2Route(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -665,7 +665,7 @@ func testAccRoute_http2Route(t *testing.T) { }, { Config: testAccRouteConfig_http2RouteUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -742,7 +742,7 @@ func testAccRoute_http2RouteWithPortMatch(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_http2RouteWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -785,7 +785,7 @@ func testAccRoute_http2RouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_http2RouteWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -864,7 +864,7 @@ func testAccRoute_http2RouteTimeout(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_http2RouteWithTimeout(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -902,7 +902,7 @@ func testAccRoute_http2RouteTimeout(t *testing.T) { }, { Config: testAccRouteConfig_http2RouteWithTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -968,7 +968,7 @@ func testAccRoute_httpRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_http(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -984,6 +984,7 @@ func testAccRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.method", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.timeout.#", "0"), @@ -998,7 +999,7 @@ func testAccRoute_httpRoute(t *testing.T) { }, { Config: testAccRouteConfig_httpUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1014,6 +1015,7 @@ func testAccRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.method", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/path"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.timeout.#", "0"), @@ -1028,7 +1030,7 @@ func testAccRoute_httpRoute(t *testing.T) { }, { Config: testAccRouteConfig_httpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1042,6 +1044,7 @@ func testAccRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.method", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/path"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.timeout.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), @@ -1080,7 +1083,7 @@ func testAccRoute_httpRouteWithPortMatch(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_httpWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1112,7 +1115,7 @@ func testAccRoute_httpRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_httpWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1145,7 +1148,7 @@ func testAccRoute_httpRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_httpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1179,6 +1182,70 @@ func testAccRoute_httpRouteWithPortMatch(t *testing.T) { }) } +func testAccRoute_httpRouteWithQueryParameterMatch(t *testing.T) { + ctx := acctest.Context(t) + var r appmesh.RouteData + resourceName := "aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vrName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vn1Name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vn2Name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRouteConfig_httpWithQueryParameterMatch(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRouteExists(ctx, resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + acctest.CheckResourceAttrAccountID(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"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.0.weighted_target.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.method", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.http_route.0.match.0.query_parameter.*", map[string]string{ + "match.#": "1", + "match.0.exact": "xact", + "name": "param1", + }), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.timeout.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "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"), + acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccRoute_httpRouteTimeout(t *testing.T) { ctx := acctest.Context(t) var r appmesh.RouteData @@ -1197,7 +1264,7 @@ func testAccRoute_httpRouteTimeout(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_httpTimeout(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1231,7 +1298,7 @@ func testAccRoute_httpRouteTimeout(t *testing.T) { }, { Config: testAccRouteConfig_httpTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1293,7 +1360,7 @@ func testAccRoute_tcpRoute(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_tcp(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1317,7 +1384,7 @@ func testAccRoute_tcpRoute(t *testing.T) { }, { Config: testAccRouteConfig_tcpUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1341,7 +1408,7 @@ func testAccRoute_tcpRoute(t *testing.T) { }, { Config: testAccRouteConfig_tcpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1388,7 +1455,7 @@ func testAccRoute_tcpRouteWithPortMatch(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_tcpWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1415,7 +1482,7 @@ func testAccRoute_tcpRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_tcpWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1443,7 +1510,7 @@ func testAccRoute_tcpRouteWithPortMatch(t *testing.T) { }, { Config: testAccRouteConfig_tcpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1490,7 +1557,7 @@ func testAccRoute_tcpRouteTimeout(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_tcpTimeout(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1517,7 +1584,7 @@ func testAccRoute_tcpRouteTimeout(t *testing.T) { }, { Config: testAccRouteConfig_tcpTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1621,7 +1688,7 @@ func testAccRoute_httpHeader(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_httpHeader(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1654,7 +1721,7 @@ func testAccRoute_httpHeader(t *testing.T) { }, { Config: testAccRouteConfig_httpHeaderUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1721,7 +1788,7 @@ func testAccRoute_routePriority(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_routePriority(meshName, vrName, vn1Name, vn2Name, rName, 42), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1750,7 +1817,7 @@ func testAccRoute_routePriority(t *testing.T) { }, { Config: testAccRouteConfig_routePriority(meshName, vrName, vn1Name, vn2Name, rName, 1000), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1805,7 +1872,7 @@ func testAccRoute_httpRetryPolicy(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccRouteConfig_httpRetryPolicy(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1840,7 +1907,7 @@ func testAccRoute_httpRetryPolicy(t *testing.T) { }, { Config: testAccRouteConfig_httpMaxRetriesZero(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -1875,7 +1942,7 @@ func testAccRoute_httpRetryPolicy(t *testing.T) { }, { Config: testAccRouteConfig_httpRetryPolicyUpdated(meshName, vrName, vn1Name, vn2Name, rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), @@ -2926,6 +2993,40 @@ resource "aws_appmesh_route" "test" { `, rName)) } +func testAccRouteConfig_httpWithQueryParameterMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "http", 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 { + http_route { + match { + prefix = "/" + + query_parameter { + name = "param1" + + match { + exact = "xact" + } + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test1.name + weight = 100 + port = 8080 + } + } + } + } +} +`, rName)) +} + func testAccRouteConfig_httpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { diff --git a/website/docs/r/appmesh_route.html.markdown b/website/docs/r/appmesh_route.html.markdown index 5ddd74220ca1..f8926419d2fb 100644 --- a/website/docs/r/appmesh_route.html.markdown +++ b/website/docs/r/appmesh_route.html.markdown @@ -237,8 +237,18 @@ This parameter must always start with /, which by itself matches all requests to * `port`- (Optional) The port number to match from the request. * `header` - (Optional) Client request headers to match on. * `method` - (Optional) Client request header method to match on. Valid values: `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`, `TRACE`, `PATCH`. +* `query_parameter` - (Optional) Client request query parameters to match on. * `scheme` - (Optional) Client request header scheme to match on. Valid values: `http`, `https`. +The `match`'s `query_parameter` object supports the following: + +* `name` - (Required) Name for the query parameter that will be matched on. +* `match` - (Optional) The query parameter to match on. + +The `query_parameter`'s `match` object supports the following: + +* `exact` - (Optional) The exact query parameter to match on. + The `http2_route` and `http_route`'s `retry_policy` object supports the following: * `http_retry_events` - (Optional) List of HTTP retry events. From 91bda96ef69058563f822d8c1ba4cbeef6b3c849 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 14:07:24 -0400 Subject: [PATCH 30/36] r/aws_appmesh_route: Add 'spec.http_route.match.path' and 'spec.http2_route.match.path'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Route$$/http2RouteWithPathMatch' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^Route$/http2RouteWithPathMatch -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Route === RUN TestAccAppMesh_serial/Route/http2RouteWithPathMatch --- PASS: TestAccAppMesh_serial (17.61s) --- PASS: TestAccAppMesh_serial/Route (17.61s) --- PASS: TestAccAppMesh_serial/Route/http2RouteWithPathMatch (17.61s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 23.855s --- .changelog/29064.txt | 6 +- internal/service/appmesh/appmesh_test.go | 1 + internal/service/appmesh/flex.go | 38 +++++-- internal/service/appmesh/route.go | 22 +++- internal/service/appmesh/route_test.go | 116 +++++++++++++++++++++ website/docs/r/appmesh_route.html.markdown | 8 +- 6 files changed, 182 insertions(+), 9 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index 142f1fcee971..cb12dd90d407 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -15,5 +15,9 @@ resource/aws_appmesh_virtual_node: Add `ip_preference` and `response_type` to th ``` ```release-note:enhancement -resource/aws_appmesh_gateway_route: Add `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks +resource/aws_appmesh_gateway_route: Add `path` and `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks +``` + +```release-note:enhancement +resource/aws_appmesh_gateway_route: `spec.http_route.match.prefix` and `spec.http2_route.match.prefix` are Optional ``` \ No newline at end of file diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 3dd1c791b7f5..9b6d211cb017 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -42,6 +42,7 @@ func TestAccAppMesh_serial(t *testing.T) { "grpcRouteEmptyMatch": testAccRoute_grpcRouteEmptyMatch, "grpcRouteTimeout": testAccRoute_grpcRouteTimeout, "http2Route": testAccRoute_http2Route, + "http2RouteWithPathMatch": testAccRoute_http2RouteWithPathMatch, "http2RouteWithPortMatch": testAccRoute_http2RouteWithPortMatch, "http2RouteTimeout": testAccRoute_http2RouteTimeout, "httpHeader": testAccRoute_httpHeader, diff --git a/internal/service/appmesh/flex.go b/internal/service/appmesh/flex.go index 798666c93b76..6c6c45600828 100644 --- a/internal/service/appmesh/flex.go +++ b/internal/service/appmesh/flex.go @@ -381,6 +381,9 @@ func expandHTTPRoute(vHttpRoute []interface{}) *appmesh.HttpRoute { if vMethod, ok := mHttpRouteMatch["method"].(string); ok && vMethod != "" { httpRouteMatch.Method = aws.String(vMethod) } + if vPort, ok := mHttpRouteMatch["port"].(int); ok && vPort > 0 { + httpRouteMatch.Port = aws.Int64(int64(vPort)) + } if vPrefix, ok := mHttpRouteMatch["prefix"].(string); ok && vPrefix != "" { httpRouteMatch.Prefix = aws.String(vPrefix) } @@ -388,10 +391,6 @@ func expandHTTPRoute(vHttpRoute []interface{}) *appmesh.HttpRoute { httpRouteMatch.Scheme = aws.String(vScheme) } - if vPort, ok := mHttpRouteMatch["port"].(int); ok && vPort > 0 { - httpRouteMatch.Port = aws.Int64(int64(vPort)) - } - if vHttpRouteHeaders, ok := mHttpRouteMatch["header"].(*schema.Set); ok && vHttpRouteHeaders.Len() > 0 { httpRouteHeaders := []*appmesh.HttpRouteHeader{} @@ -445,6 +444,21 @@ func expandHTTPRoute(vHttpRoute []interface{}) *appmesh.HttpRoute { httpRouteMatch.Headers = httpRouteHeaders } + if vHttpRoutePath, ok := mHttpRouteMatch["path"].([]interface{}); ok && len(vHttpRoutePath) > 0 && vHttpRoutePath[0] != nil { + httpRoutePath := &appmesh.HttpPathMatch{} + + mHttpRoutePath := vHttpRoutePath[0].(map[string]interface{}) + + if vExact, ok := mHttpRoutePath["exact"].(string); ok && vExact != "" { + httpRoutePath.Exact = aws.String(vExact) + } + if vRegex, ok := mHttpRoutePath["regex"].(string); ok && vRegex != "" { + httpRoutePath.Regex = aws.String(vRegex) + } + + httpRouteMatch.Path = httpRoutePath + } + if vHttpRouteQueryParameters, ok := mHttpRouteMatch["query_parameter"].(*schema.Set); ok && vHttpRouteQueryParameters.Len() > 0 { httpRouteQueryParameters := []*appmesh.HttpQueryParameter{} @@ -1442,6 +1456,17 @@ func flattenHTTPRoute(httpRoute *appmesh.HttpRoute) []interface{} { vHttpRouteHeaders = append(vHttpRouteHeaders, mHttpRouteHeader) } + vHttpRoutePath := []interface{}{} + + if httpRoutePath := httpRouteMatch.Path; httpRoutePath != nil { + mHttpRoutePath := map[string]interface{}{ + "exact": aws.StringValue(httpRoutePath.Exact), + "regex": aws.StringValue(httpRoutePath.Regex), + } + + vHttpRoutePath = []interface{}{mHttpRoutePath} + } + vHttpRouteQueryParameters := []interface{}{} for _, httpRouteQueryParameter := range httpRouteMatch.QueryParameters { @@ -1464,10 +1489,11 @@ func flattenHTTPRoute(httpRoute *appmesh.HttpRoute) []interface{} { map[string]interface{}{ "header": vHttpRouteHeaders, "method": aws.StringValue(httpRouteMatch.Method), - "prefix": aws.StringValue(httpRouteMatch.Prefix), - "scheme": aws.StringValue(httpRouteMatch.Scheme), + "path": vHttpRoutePath, "port": int(aws.Int64Value(httpRouteMatch.Port)), + "prefix": aws.StringValue(httpRouteMatch.Prefix), "query_parameter": vHttpRouteQueryParameters, + "scheme": aws.StringValue(httpRouteMatch.Scheme), }, } } diff --git a/internal/service/appmesh/route.go b/internal/service/appmesh/route.go index 769cbbdc0004..1d1175c5e2ac 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -211,6 +211,26 @@ func resourceRouteSpecSchema() *schema.Schema { Optional: true, ValidateFunc: validation.StringInSlice(appmesh.HttpMethod_Values(), false), }, + "path": { + 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), + }, + "regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, "port": { Type: schema.TypeInt, Optional: true, @@ -218,7 +238,7 @@ func resourceRouteSpecSchema() *schema.Schema { }, "prefix": { Type: schema.TypeString, - Required: true, + Optional: true, ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), }, "query_parameter": { diff --git a/internal/service/appmesh/route_test.go b/internal/service/appmesh/route_test.go index 68a632d338d5..e047eb708624 100644 --- a/internal/service/appmesh/route_test.go +++ b/internal/service/appmesh/route_test.go @@ -643,7 +643,10 @@ func testAccRoute_http2Route(t *testing.T) { "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.path.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.query_parameter.#", "0"), 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"), @@ -724,6 +727,73 @@ func testAccRoute_http2Route(t *testing.T) { }) } +func testAccRoute_http2RouteWithPathMatch(t *testing.T) { + ctx := acctest.Context(t) + var r appmesh.RouteData + resourceName := "aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vrName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vn1Name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vn2Name := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRouteConfig_http2RouteWithPathMatch(meshName, vrName, vn1Name, vn2Name, rName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRouteExists(ctx, resourceName, &r), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + acctest.CheckResourceAttrAccountID(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.action.0.weighted_target.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + 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.match.0.path.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.0.exact", "/test"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.0.regex", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.query_parameter.#", "0"), + 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"), + resource.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.http2_route.0.timeout.#", "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"), + acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", meshName, vrName, rName)), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccRoute_http2RouteWithPortMatch(t *testing.T) { ctx := acctest.Context(t) var r appmesh.RouteData @@ -983,6 +1053,8 @@ func testAccRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.method", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), @@ -2689,6 +2761,50 @@ resource "aws_appmesh_route" "test" { `, rName)) } +func testAccRouteConfig_http2RouteWithPathMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { + return acctest.ConfigCompose(testAccRouteConfig_base(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 { + method = "POST" + scheme = "http" + + path { + exact = "/test" + } + } + + 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.test1.name + weight = 100 + port = 8080 + } + } + } + } +} +`, rName)) +} + func testAccRouteConfig_http2RouteWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { diff --git a/website/docs/r/appmesh_route.html.markdown b/website/docs/r/appmesh_route.html.markdown index f8926419d2fb..24ce6a290265 100644 --- a/website/docs/r/appmesh_route.html.markdown +++ b/website/docs/r/appmesh_route.html.markdown @@ -232,14 +232,20 @@ The `idle` and `per_request` objects support the following: The `http2_route` and `http_route`'s `match` object supports the following: -* `prefix` - (Required) Path with which to match requests. +* `prefix` - (Optional) Path with which to match requests. This parameter must always start with /, which by itself matches all requests to the virtual router service name. * `port`- (Optional) The port number to match from the request. * `header` - (Optional) Client request headers to match on. * `method` - (Optional) Client request header method to match on. Valid values: `GET`, `HEAD`, `POST`, `PUT`, `DELETE`, `CONNECT`, `OPTIONS`, `TRACE`, `PATCH`. +* `path` - (Optional) Client request path to match on. * `query_parameter` - (Optional) Client request query parameters to match on. * `scheme` - (Optional) Client request header scheme to match on. Valid values: `http`, `https`. +The `match`'s `path` object supports the following: + +* `exact` - (Optional) The exact path to match on. +* `regex` - (Optional) The regex used to match the path. + The `match`'s `query_parameter` object supports the following: * `name` - (Required) Name for the query parameter that will be matched on. From 7a4af684eea90b9dcae1f2e0b7bc8dbc93dfdd47 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 14:17:25 -0400 Subject: [PATCH 31/36] Fix terrafmt error. --- internal/service/appmesh/route_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/appmesh/route_test.go b/internal/service/appmesh/route_test.go index e047eb708624..05e73f7fc32c 100644 --- a/internal/service/appmesh/route_test.go +++ b/internal/service/appmesh/route_test.go @@ -2776,7 +2776,7 @@ resource "aws_appmesh_route" "test" { path { exact = "/test" - } + } } retry_policy { From 2c077b393a45e775c3fa7e2dc7810195ba51c7ea Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 16:07:30 -0400 Subject: [PATCH 32/36] r/aws_appmesh_gateway_route: Dedup 'spec.http_route' and 'spec.http2_route' schemde definitions. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^GatewayRoute$$' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^GatewayRoute$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/GatewayRoute === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/http2Route === RUN TestAccAppMesh_serial/GatewayRoute/basic === RUN TestAccAppMesh_serial/GatewayRoute/grpcRoute === RUN TestAccAppMesh_serial/GatewayRoute/httpRoute === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/tags === RUN TestAccAppMesh_serial/GatewayRoute/dataSourceBasic === RUN TestAccAppMesh_serial/GatewayRoute/disappears === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort --- PASS: TestAccAppMesh_serial (421.97s) --- PASS: TestAccAppMesh_serial/GatewayRoute (421.97s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort (28.22s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort (28.26s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2Route (48.69s) --- PASS: TestAccAppMesh_serial/GatewayRoute/basic (16.20s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRoute (29.48s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRoute (49.35s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort (49.31s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort (28.67s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort (48.85s) --- PASS: TestAccAppMesh_serial/GatewayRoute/tags (37.70s) --- PASS: TestAccAppMesh_serial/GatewayRoute/dataSourceBasic (14.74s) --- PASS: TestAccAppMesh_serial/GatewayRoute/disappears (13.72s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort (28.79s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 427.109s --- internal/service/appmesh/gateway_route.go | 476 +++++++--------------- 1 file changed, 156 insertions(+), 320 deletions(-) diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 387c8e291162..3d7d43a78cb4 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -87,52 +87,45 @@ func ResourceGatewayRoute() *schema.Resource { } func resourceGatewayRouteSpecSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "grpc_route": { - 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{ - "target": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "virtual_service": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + // httpRouteSchema returns the schema for `http_route` and `http2_route` attributes. + httpRouteSchema := func(attrName string) *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{ + "target": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_service": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_service_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, }, @@ -140,205 +133,142 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { }, }, }, - }, - "match": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "service_name": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - }, - }, - }, - ExactlyOneOf: []string{ - "spec.0.grpc_route", - "spec.0.http2_route", - "spec.0.http_route", - }, - }, - "http_route": { - 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{ - "target": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "virtual_service": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_service_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + "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{ + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.prefix", attrName), + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.hostname", attrName), + }, }, - }, - "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), - }, + "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{ + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.prefix.0.default_prefix", attrName), + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.prefix.0.value", attrName), }, }, - 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", - }, - }, + "value": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + ExactlyOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.prefix.0.default_prefix", attrName), + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.prefix.0.value", attrName), }, }, - AtLeastOneOf: []string{ - "spec.0.http_route.0.action.0.rewrite.0.prefix", - "spec.0.http_route.0.action.0.rewrite.0.hostname", - }, }, }, + AtLeastOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.prefix", attrName), + fmt.Sprintf("spec.0.%s.0.action.0.rewrite.0.hostname", attrName), + }, }, }, }, }, }, - "match": { - Type: schema.TypeList, - Required: 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{ - "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", - }, - }, + }, + }, + "match": { + Type: schema.TypeList, + Required: 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{ + "exact": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.match.0.hostname.0.exact", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.hostname.0.suffix", attrName), }, }, - AtLeastOneOf: []string{ - "spec.0.http_route.0.match.0.prefix", - "spec.0.http_route.0.match.0.hostname", - }, - }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "prefix": { - Type: schema.TypeString, - 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", + "suffix": { + Type: schema.TypeString, + Optional: true, + ExactlyOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.match.0.hostname.0.exact", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.hostname.0.suffix", attrName), + }, }, }, }, + AtLeastOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.match.0.prefix", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.hostname", attrName), + }, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + AtLeastOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.match.0.prefix", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.hostname", attrName), + }, }, }, }, }, - ExactlyOneOf: []string{ - "spec.0.grpc_route", - "spec.0.http2_route", - "spec.0.http_route", - }, }, - "http2_route": { + }, + ExactlyOneOf: []string{ + "spec.0.grpc_route", + "spec.0.http2_route", + "spec.0.http_route", + }, + } + } + + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grpc_route": { Type: schema.TypeList, Optional: true, MinItems: 0, @@ -382,67 +312,6 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { }, }, }, - "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", - }, - }, - }, - }, - }, }, }, }, @@ -453,50 +322,15 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ - "prefix": { - Type: schema.TypeString, - 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", - }, - }, "port": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IsPortNumber, }, + "service_name": { + Type: schema.TypeString, + Required: true, + }, }, }, }, @@ -508,6 +342,8 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { "spec.0.http_route", }, }, + "http_route": httpRouteSchema("http_route"), + "http2_route": httpRouteSchema("http2_route"), "priority": { Type: schema.TypeInt, Optional: true, From 58030453b78daa455340a94b94d6ca444c935747 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 16:58:00 -0400 Subject: [PATCH 33/36] r/aws_appmesh_gateway_route: Add 'header' to the 'spec.http_route.match' and 'spec.http2_route.match' configuration blocks. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^GatewayRoute$$' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^GatewayRoute$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/GatewayRoute === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRoute === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/basic === RUN TestAccAppMesh_serial/GatewayRoute/disappears === RUN TestAccAppMesh_serial/GatewayRoute/grpcRoute === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort === RUN TestAccAppMesh_serial/GatewayRoute/http2Route === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort === RUN TestAccAppMesh_serial/GatewayRoute/tags === RUN TestAccAppMesh_serial/GatewayRoute/dataSourceBasic --- PASS: TestAccAppMesh_serial (380.84s) --- PASS: TestAccAppMesh_serial/GatewayRoute (380.84s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteTargetPort (31.09s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRouteWithPort (27.97s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRoute (48.76s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteWithPort (48.66s) --- PASS: TestAccAppMesh_serial/GatewayRoute/basic (16.19s) --- PASS: TestAccAppMesh_serial/GatewayRoute/disappears (13.47s) --- PASS: TestAccAppMesh_serial/GatewayRoute/grpcRoute (26.99s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteTargetPort (28.28s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteWithPort (49.30s) --- FAIL: TestAccAppMesh_serial/GatewayRoute/http2Route (8.56s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteTargetPort (28.82s) --- PASS: TestAccAppMesh_serial/GatewayRoute/tags (37.95s) --- PASS: TestAccAppMesh_serial/GatewayRoute/dataSourceBasic (14.80s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 386.291s --- .changelog/29064.txt | 8 +- internal/service/appmesh/gateway_route.go | 190 ++++++++++++++++-- .../service/appmesh/gateway_route_test.go | 54 +++++ .../r/appmesh_gateway_route.html.markdown | 21 ++ 4 files changed, 254 insertions(+), 19 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index cb12dd90d407..ea08e3cc45e7 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -15,9 +15,13 @@ resource/aws_appmesh_virtual_node: Add `ip_preference` and `response_type` to th ``` ```release-note:enhancement -resource/aws_appmesh_gateway_route: Add `path` and `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks +resource/aws_appmesh_route: Add `path` and `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks ``` ```release-note:enhancement -resource/aws_appmesh_gateway_route: `spec.http_route.match.prefix` and `spec.http2_route.match.prefix` are Optional +resource/aws_appmesh_route: `spec.http_route.match.prefix` and `spec.http2_route.match.prefix` are Optional +``` + +```release-note:enhancement +resource/aws_appmesh_gateway_route: Add `header` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks ``` \ No newline at end of file diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 3d7d43a78cb4..8f052efac997 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -204,6 +204,74 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { 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), + }, + }, + }, + }, "hostname": { Type: schema.TypeList, Optional: true, @@ -710,28 +778,82 @@ func expandHTTPGatewayRouteMatch(vHttpRouteMatch []interface{}) *appmesh.HttpGat mRouteMatch := vHttpRouteMatch[0].(map[string]interface{}) + if vPort, ok := mRouteMatch["port"].(int); ok && vPort > 0 { + routeMatch.Port = aws.Int64(int64(vPort)) + } + 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 { + if vHeaders, ok := mRouteMatch["header"].(*schema.Set); ok && vHeaders.Len() > 0 { + headers := []*appmesh.HttpGatewayRouteHeader{} + + for _, vHeader := range vHeaders.List() { + header := &appmesh.HttpGatewayRouteHeader{} + + mHeader := vHeader.(map[string]interface{}) + + if vInvert, ok := mHeader["invert"].(bool); ok { + header.Invert = aws.Bool(vInvert) + } + if vName, ok := mHeader["name"].(string); ok && vName != "" { + header.Name = aws.String(vName) + } + + if vMatch, ok := mHeader["match"].([]interface{}); ok && len(vMatch) > 0 && vMatch[0] != nil { + header.Match = &appmesh.HeaderMatchMethod{} + + mMatch := vMatch[0].(map[string]interface{}) + + if vExact, ok := mMatch["exact"].(string); ok && vExact != "" { + header.Match.Exact = aws.String(vExact) + } + if vPrefix, ok := mMatch["prefix"].(string); ok && vPrefix != "" { + header.Match.Prefix = aws.String(vPrefix) + } + if vRegex, ok := mMatch["regex"].(string); ok && vRegex != "" { + header.Match.Regex = aws.String(vRegex) + } + if vSuffix, ok := mMatch["suffix"].(string); ok && vSuffix != "" { + header.Match.Suffix = aws.String(vSuffix) + } + + if vRange, ok := mMatch["range"].([]interface{}); ok && len(vRange) > 0 && vRange[0] != nil { + header.Match.Range = &appmesh.MatchRange{} + + mRange := vRange[0].(map[string]interface{}) + + if vEnd, ok := mRange["end"].(int); ok && vEnd > 0 { + header.Match.Range.End = aws.Int64(int64(vEnd)) + } + if vStart, ok := mRange["start"].(int); ok && vStart > 0 { + header.Match.Range.Start = aws.Int64(int64(vStart)) + } + } + } + + headers = append(headers, header) + } + + routeMatch.Headers = headers + } + + if vHostname, ok := mRouteMatch["hostname"].([]interface{}); ok && len(vHostname) > 0 && vHostname[0] != nil { hostnameMatch := &appmesh.GatewayRouteHostnameMatch{} - mHostnameMatch := vHostnameMatch[0].(map[string]interface{}) - if vExact, ok := mHostnameMatch["exact"].(string); ok && vExact != "" { + mHostname := vHostname[0].(map[string]interface{}) + + if vExact, ok := mHostname["exact"].(string); ok && vExact != "" { hostnameMatch.Exact = aws.String(vExact) } - if vSuffix, ok := mHostnameMatch["suffix"].(string); ok && vSuffix != "" { + if vSuffix, ok := mHostname["suffix"].(string); ok && vSuffix != "" { hostnameMatch.Suffix = aws.String(vSuffix) } routeMatch.Hostname = hostnameMatch } - if vPort, ok := mRouteMatch["port"].(int); ok && vPort > 0 { - routeMatch.Port = aws.Int64(int64(vPort)) - } - return routeMatch } @@ -838,24 +960,58 @@ func flattenHTTPGatewayRouteMatch(routeMatch *appmesh.HttpGatewayRouteMatch) []i mRouteMatch := map[string]interface{}{} + if routeMatch.Port != nil { + mRouteMatch["port"] = int(aws.Int64Value(routeMatch.Port)) + } + 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) + vHeaders := []interface{}{} + + for _, header := range routeMatch.Headers { + mHeader := map[string]interface{}{ + "invert": aws.BoolValue(header.Invert), + "name": aws.StringValue(header.Name), } - if hostnameMatch.Suffix != nil { - mHostnameMatch["suffix"] = aws.StringValue(hostnameMatch.Suffix) + + if match := header.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)), + } + + mMatch["range"] = []interface{}{mRange} + } + + mHeader["match"] = []interface{}{mMatch} } - mRouteMatch["hostname"] = []interface{}{mHostnameMatch} + vHeaders = append(vHeaders, mHeader) } - if routeMatch.Port != nil { - mRouteMatch["port"] = int(aws.Int64Value(routeMatch.Port)) + mRouteMatch["header"] = vHeaders + + if hostname := routeMatch.Hostname; hostname != nil { + mHostname := map[string]interface{}{} + + if hostname.Exact != nil { + mHostname["exact"] = aws.StringValue(hostname.Exact) + } + if hostname.Suffix != nil { + mHostname["suffix"] = aws.StringValue(hostname.Suffix) + } + + mRouteMatch["hostname"] = []interface{}{mHostname} } return []interface{}{mRouteMatch} diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index 0b17214fe7ef..ce8acb4c90a1 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -46,6 +46,9 @@ func testAccGatewayRoute_basic(t *testing.T) { 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", vsResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), @@ -357,6 +360,9 @@ func testAccGatewayRoute_httpRoute(t *testing.T) { 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.header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), @@ -382,6 +388,9 @@ func testAccGatewayRoute_httpRoute(t *testing.T) { 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", vs2ResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/users"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), @@ -699,6 +708,14 @@ func testAccGatewayRoute_http2Route(t *testing.T) { 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.header.#", "1"), + resource.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.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), 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), @@ -724,6 +741,22 @@ func testAccGatewayRoute_http2Route(t *testing.T) { 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", vs2ResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.header.#", "2"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.http2_route.0.match.0.header.*", map[string]string{ + "invert": "true", + "match.#": "0", + "name": "X-Testing1", + }), + resource.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.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/users"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), @@ -1614,6 +1647,10 @@ resource "aws_appmesh_gateway_route" "test" { match { prefix = "/" + + header { + name = "X-Testing1" + } } } } @@ -1640,6 +1677,23 @@ resource "aws_appmesh_gateway_route" "test" { match { prefix = "/users" + + header { + name = "X-Testing1" + invert = true + } + + header { + name = "X-Testing2" + invert = false + + match { + range { + start = 2 + end = 7 + } + } + } } } } diff --git a/website/docs/r/appmesh_gateway_route.html.markdown b/website/docs/r/appmesh_gateway_route.html.markdown index 6f999fc22396..63bac0c23d06 100644 --- a/website/docs/r/appmesh_gateway_route.html.markdown +++ b/website/docs/r/appmesh_gateway_route.html.markdown @@ -101,10 +101,31 @@ The `grpc_route`'s `match` object supports the following: The `http_route` and `http2_route`'s `match` object supports the following: +* `header` - (Optional) Client request headers to match on. * `hostname` - (Optional) Host name to match on. * `prefix` - (Required) Path to match requests with. This parameter must always start with `/`, which by itself matches all requests to the virtual service name. * `port` - (Optional) The port number to match from the request. +The `header` object supports the following: + +* `name` - (Required) Name for the HTTP header in the client request that will be matched on. +* `invert` - (Optional) If `true`, the match is on the opposite of the `match` method and value. Default is `false`. +* `match` - (Optional) Method and value to match the header value sent with a request. Specify one match method. + +The `header`'s `match` object supports the following: + +* `exact` - (Optional) Header value sent by the client must match the specified value exactly. +* `prefix` - (Optional) Header value sent by the client must begin with the specified characters. +* `port`- (Optional) The port number to match from the request. +* `range`- (Optional) Object that specifies the range of numbers that the header value sent by the client must be included in. +* `regex` - (Optional) Header value sent by the client must include the specified characters. +* `suffix` - (Optional) Header value sent by the client must end with the specified characters. + +The `range` object supports the following: + +* `end` - (Required) End of the range. +* `start` - (Requited) Start of the range. + The `hostname` object supports the following: * `exact` - (Optional) Exact host name to match on. From 3f8b5d0eb413ae07496f854714eef773a66d3666 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 17:19:36 -0400 Subject: [PATCH 34/36] r/aws_appmesh_gateway_route: Add 'path' to the 'spec.http_route.match' and 'spec.http2_route.match' configuration blocks. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^GatewayRoute$$/httpRouteWithPath' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^GatewayRoute$/httpRouteWithPath -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/GatewayRoute === RUN TestAccAppMesh_serial/GatewayRoute/httpRouteWithPath --- PASS: TestAccAppMesh_serial (17.27s) --- PASS: TestAccAppMesh_serial/GatewayRoute (17.27s) --- PASS: TestAccAppMesh_serial/GatewayRoute/httpRouteWithPath (17.27s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 22.386s --- .changelog/29064.txt | 4 +- internal/service/appmesh/appmesh_test.go | 1 + internal/service/appmesh/gateway_route.go | 55 ++++++++++++ .../service/appmesh/gateway_route_test.go | 89 +++++++++++++++++++ .../r/appmesh_gateway_route.html.markdown | 8 +- 5 files changed, 154 insertions(+), 3 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index ea08e3cc45e7..d98d70536649 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -23,5 +23,5 @@ resource/aws_appmesh_route: `spec.http_route.match.prefix` and `spec.http2_route ``` ```release-note:enhancement -resource/aws_appmesh_gateway_route: Add `header` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks -``` \ No newline at end of file +resource/aws_appmesh_gateway_route: Add `header` and `path` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks +``` diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 9b6d211cb017..4356f19d5460 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -18,6 +18,7 @@ func TestAccAppMesh_serial(t *testing.T) { "grpcRouteWithPort": testAccGatewayRoute_grpcRouteWithPort, "httpRoute": testAccGatewayRoute_httpRoute, "httpRouteTargetPort": testAccGatewayRoute_httpRouteTargetPort, + "httpRouteWithPath": testAccGatewayRoute_httpRouteWithPath, "httpRouteWithPort": testAccGatewayRoute_httpRouteWithPort, "http2Route": testAccGatewayRoute_http2Route, "http2RouteTargetPort": testAccGatewayRoute_http2RouteTargetPort, diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 8f052efac997..1fa7865c7e5e 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -298,8 +298,34 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { }, }, AtLeastOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.match.0.hostname", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.path", attrName), fmt.Sprintf("spec.0.%s.0.match.0.prefix", attrName), + }, + }, + "path": { + 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), + }, + "regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + AtLeastOneOf: []string{ + fmt.Sprintf("spec.0.%s.0.match.0.path", attrName), fmt.Sprintf("spec.0.%s.0.match.0.hostname", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.prefix", attrName), }, }, "port": { @@ -314,6 +340,7 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { AtLeastOneOf: []string{ fmt.Sprintf("spec.0.%s.0.match.0.prefix", attrName), fmt.Sprintf("spec.0.%s.0.match.0.hostname", attrName), + fmt.Sprintf("spec.0.%s.0.match.0.path", attrName), }, }, }, @@ -854,6 +881,21 @@ func expandHTTPGatewayRouteMatch(vHttpRouteMatch []interface{}) *appmesh.HttpGat routeMatch.Hostname = hostnameMatch } + if vPath, ok := mRouteMatch["path"].([]interface{}); ok && len(vPath) > 0 && vPath[0] != nil { + pathMatch := &appmesh.HttpPathMatch{} + + mHostname := vPath[0].(map[string]interface{}) + + if vExact, ok := mHostname["exact"].(string); ok && vExact != "" { + pathMatch.Exact = aws.String(vExact) + } + if vRegex, ok := mHostname["regex"].(string); ok && vRegex != "" { + pathMatch.Regex = aws.String(vRegex) + } + + routeMatch.Path = pathMatch + } + return routeMatch } @@ -1014,6 +1056,19 @@ func flattenHTTPGatewayRouteMatch(routeMatch *appmesh.HttpGatewayRouteMatch) []i mRouteMatch["hostname"] = []interface{}{mHostname} } + if path := routeMatch.Path; path != nil { + mPath := map[string]interface{}{} + + if path.Exact != nil { + mPath["exact"] = aws.StringValue(path.Exact) + } + if path.Regex != nil { + mPath["regex"] = aws.StringValue(path.Regex) + } + + mRouteMatch["path"] = []interface{}{mPath} + } + return []interface{}{mRouteMatch} } diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index ce8acb4c90a1..79a9996640dd 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -48,6 +48,7 @@ func testAccGatewayRoute_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), @@ -362,6 +363,7 @@ func testAccGatewayRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), @@ -390,6 +392,7 @@ func testAccGatewayRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/users"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), @@ -543,6 +546,62 @@ func testAccGatewayRoute_httpRouteTargetPort(t *testing.T) { }) } +func testAccGatewayRoute_httpRouteWithPath(t *testing.T) { + ctx := acctest.Context(t) + var v appmesh.GatewayRouteData + resourceName := "aws_appmesh_gateway_route.test" + vsResourceName := "aws_appmesh_virtual_service.test.0" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + grName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayRouteConfig_httpRouteWithPath(meshName, vgName, grName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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", vsResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.0.exact", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.0.regex", "/.*"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), + 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccGatewayRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccGatewayRoute_httpRouteWithPort(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData @@ -715,6 +774,7 @@ func testAccGatewayRoute_http2Route(t *testing.T) { "name": "X-Testing1", }), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), @@ -756,6 +816,7 @@ func testAccGatewayRoute_http2Route(t *testing.T) { "name": "X-Testing2", }), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/users"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), @@ -1512,6 +1573,34 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_httpRouteWithPath(meshName, vgName, grName string) string { + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), 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 { + path { + regex = "/.*" + } + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_httpRouteWithPort(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http"), 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 63bac0c23d06..0bec4de35828 100644 --- a/website/docs/r/appmesh_gateway_route.html.markdown +++ b/website/docs/r/appmesh_gateway_route.html.markdown @@ -103,8 +103,9 @@ The `http_route` and `http2_route`'s `match` object supports the following: * `header` - (Optional) Client request headers to match on. * `hostname` - (Optional) Host name to match on. -* `prefix` - (Required) Path to match requests with. This parameter must always start with `/`, which by itself matches all requests to the virtual service name. +* `path` - (Optional) Client request path to match on. * `port` - (Optional) The port number to match from the request. +* `prefix` - (Optional) Path to match requests with. This parameter must always start with `/`, which by itself matches all requests to the virtual service name. The `header` object supports the following: @@ -131,6 +132,11 @@ The `hostname` object supports the following: * `exact` - (Optional) Exact host name to match on. * `suffix` - (Optional) Specified ending characters of the host name to match on. +The `path` object supports the following: + +* `exact` - (Optional) The exact path to match on. +* `regex` - (Optional) The regex used to match the path. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 745692d8759cd89352de86d69737444fd0f1f718 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 17:35:08 -0400 Subject: [PATCH 35/36] r/aws_appmesh_gateway_route: Add 'query_parameter' to the 'spec.http_route.match' and 'spec.http2_route.match' configuration blocks. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^GatewayRoute$$/http2RouteWithQueryParameter' PKG=appmesh ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/appmesh/... -v -count 1 -parallel 20 -run=TestAccAppMesh_serial/^GatewayRoute$/http2RouteWithQueryParameter -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/GatewayRoute === RUN TestAccAppMesh_serial/GatewayRoute/http2RouteWithQueryParameter --- PASS: TestAccAppMesh_serial (17.44s) --- PASS: TestAccAppMesh_serial/GatewayRoute (17.44s) --- PASS: TestAccAppMesh_serial/GatewayRoute/http2RouteWithQueryParameter (17.44s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 22.610s --- .changelog/29064.txt | 2 +- internal/service/appmesh/appmesh_test.go | 29 ++--- internal/service/appmesh/gateway_route.go | 76 +++++++++++++ .../service/appmesh/gateway_route_test.go | 100 ++++++++++++++++++ internal/service/appmesh/route.go | 1 - .../r/appmesh_gateway_route.html.markdown | 10 ++ 6 files changed, 202 insertions(+), 16 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index d98d70536649..bb5642f7358d 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -23,5 +23,5 @@ resource/aws_appmesh_route: `spec.http_route.match.prefix` and `spec.http2_route ``` ```release-note:enhancement -resource/aws_appmesh_gateway_route: Add `header` and `path` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks +resource/aws_appmesh_gateway_route: Add `header`, `path` and `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks ``` diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 4356f19d5460..d5a461b50c51 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -11,20 +11,21 @@ func TestAccAppMesh_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "GatewayRoute": { - "basic": testAccGatewayRoute_basic, - "disappears": testAccGatewayRoute_disappears, - "grpcRoute": testAccGatewayRoute_grpcRoute, - "grpcRouteTargetPort": testAccGatewayRoute_grpcRouteTargetPort, - "grpcRouteWithPort": testAccGatewayRoute_grpcRouteWithPort, - "httpRoute": testAccGatewayRoute_httpRoute, - "httpRouteTargetPort": testAccGatewayRoute_httpRouteTargetPort, - "httpRouteWithPath": testAccGatewayRoute_httpRouteWithPath, - "httpRouteWithPort": testAccGatewayRoute_httpRouteWithPort, - "http2Route": testAccGatewayRoute_http2Route, - "http2RouteTargetPort": testAccGatewayRoute_http2RouteTargetPort, - "http2RouteWithPort": testAccGatewayRoute_http2RouteWithPort, - "tags": testAccGatewayRoute_tags, - "dataSourceBasic": testAccGatewayRouteDataSource_basic, + "basic": testAccGatewayRoute_basic, + "disappears": testAccGatewayRoute_disappears, + "grpcRoute": testAccGatewayRoute_grpcRoute, + "grpcRouteTargetPort": testAccGatewayRoute_grpcRouteTargetPort, + "grpcRouteWithPort": testAccGatewayRoute_grpcRouteWithPort, + "httpRoute": testAccGatewayRoute_httpRoute, + "httpRouteTargetPort": testAccGatewayRoute_httpRouteTargetPort, + "httpRouteWithPath": testAccGatewayRoute_httpRouteWithPath, + "httpRouteWithPort": testAccGatewayRoute_httpRouteWithPort, + "http2Route": testAccGatewayRoute_http2Route, + "http2RouteTargetPort": testAccGatewayRoute_http2RouteTargetPort, + "http2RouteWithPort": testAccGatewayRoute_http2RouteWithPort, + "http2RouteWithQueryParameter": testAccGatewayRoute_http2RouteWithQueryParameter, + "tags": testAccGatewayRoute_tags, + "dataSourceBasic": testAccGatewayRouteDataSource_basic, }, "Mesh": { "basic": testAccMesh_basic, diff --git a/internal/service/appmesh/gateway_route.go b/internal/service/appmesh/gateway_route.go index 1fa7865c7e5e..40e71918d8a2 100644 --- a/internal/service/appmesh/gateway_route.go +++ b/internal/service/appmesh/gateway_route.go @@ -343,6 +343,34 @@ func resourceGatewayRouteSpecSchema() *schema.Schema { fmt.Sprintf("spec.0.%s.0.match.0.path", attrName), }, }, + "query_parameter": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Optional: true, + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, }, }, }, @@ -896,6 +924,34 @@ func expandHTTPGatewayRouteMatch(vHttpRouteMatch []interface{}) *appmesh.HttpGat routeMatch.Path = pathMatch } + if vQueryParameters, ok := mRouteMatch["query_parameter"].(*schema.Set); ok && vQueryParameters.Len() > 0 { + queryParameters := []*appmesh.HttpQueryParameter{} + + for _, vQueryParameter := range vQueryParameters.List() { + queryParameter := &appmesh.HttpQueryParameter{} + + mQueryParameter := vQueryParameter.(map[string]interface{}) + + if vName, ok := mQueryParameter["name"].(string); ok && vName != "" { + queryParameter.Name = aws.String(vName) + } + + if vMatch, ok := mQueryParameter["match"].([]interface{}); ok && len(vMatch) > 0 && vMatch[0] != nil { + queryParameter.Match = &appmesh.QueryParameterMatch{} + + mMatch := vMatch[0].(map[string]interface{}) + + if vExact, ok := mMatch["exact"].(string); ok && vExact != "" { + queryParameter.Match.Exact = aws.String(vExact) + } + } + + queryParameters = append(queryParameters, queryParameter) + } + + routeMatch.QueryParameters = queryParameters + } + return routeMatch } @@ -1069,6 +1125,26 @@ func flattenHTTPGatewayRouteMatch(routeMatch *appmesh.HttpGatewayRouteMatch) []i mRouteMatch["path"] = []interface{}{mPath} } + vQueryParameters := []interface{}{} + + for _, queryParameter := range routeMatch.QueryParameters { + mQueryParameter := map[string]interface{}{ + "name": aws.StringValue(queryParameter.Name), + } + + if match := queryParameter.Match; match != nil { + mMatch := map[string]interface{}{ + "exact": aws.StringValue(match.Exact), + } + + mQueryParameter["match"] = []interface{}{mMatch} + } + + vQueryParameters = append(vQueryParameters, mQueryParameter) + } + + mRouteMatch["query_parameter"] = vQueryParameters + return []interface{}{mRouteMatch} } diff --git a/internal/service/appmesh/gateway_route_test.go b/internal/service/appmesh/gateway_route_test.go index 79a9996640dd..7632ebcb7b19 100644 --- a/internal/service/appmesh/gateway_route_test.go +++ b/internal/service/appmesh/gateway_route_test.go @@ -51,6 +51,7 @@ func testAccGatewayRoute_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.priority", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), @@ -366,6 +367,7 @@ func testAccGatewayRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), @@ -395,6 +397,7 @@ func testAccGatewayRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", "/users"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), @@ -584,6 +587,7 @@ func testAccGatewayRoute_httpRouteWithPath(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.path.0.regex", "/.*"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.prefix", ""), + resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), @@ -777,6 +781,7 @@ func testAccGatewayRoute_http2Route(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), @@ -819,6 +824,7 @@ func testAccGatewayRoute_http2Route(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/users"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.query_parameter.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "0"), resource.TestCheckResourceAttr(resourceName, "virtual_gateway_name", vgName), resource.TestCheckResourceAttrSet(resourceName, "created_date"), @@ -1105,6 +1111,66 @@ func testAccGatewayRoute_http2RouteWithPort(t *testing.T) { }) } +func testAccGatewayRoute_http2RouteWithQueryParameter(t *testing.T) { + ctx := acctest.Context(t) + var v appmesh.GatewayRouteData + resourceName := "aws_appmesh_gateway_route.test" + vsResourceName := "aws_appmesh_virtual_service.test.0" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + grName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckGatewayRouteDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccGatewayRouteConfig_http2RouteWithQueryParameter(meshName, vgName, grName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckGatewayRouteExists(ctx, 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", vsResourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.hostname.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.path.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.port", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.prefix", "/"), + resource.TestCheckResourceAttr(resourceName, "spec.0.http2_route.0.match.0.query_parameter.#", "1"), + resource.TestCheckTypeSetElemNestedAttrs(resourceName, "spec.0.http2_route.0.match.0.query_parameter.*", map[string]string{ + "match.#": "1", + "match.0.exact": "xact", + "name": "param1", + }), + 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)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccGatewayRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccGatewayRoute_tags(t *testing.T) { ctx := acctest.Context(t) var v appmesh.GatewayRouteData @@ -1904,6 +1970,40 @@ resource "aws_appmesh_gateway_route" "test" { `, grName)) } +func testAccGatewayRouteConfig_http2RouteWithQueryParameter(meshName, vgName, grName string) string { + return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), 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 { + prefix = "/" + + query_parameter { + name = "param1" + + match { + exact = "xact" + } + } + } + } + } +} +`, grName)) +} + func testAccGatewayRouteConfig_http2RouteMatchHostname(meshName, vgName, grName string) string { return acctest.ConfigCompose(testAccGatewayRouteConfig_base(meshName, vgName, "http2"), fmt.Sprintf(` resource "aws_appmesh_gateway_route" "test" { diff --git a/internal/service/appmesh/route.go b/internal/service/appmesh/route.go index 1d1175c5e2ac..ca05b2891120 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -269,7 +269,6 @@ func resourceRouteSpecSchema() *schema.Schema { }, }, }, - "scheme": { Type: schema.TypeString, Optional: true, diff --git a/website/docs/r/appmesh_gateway_route.html.markdown b/website/docs/r/appmesh_gateway_route.html.markdown index 0bec4de35828..f96e4c5c2401 100644 --- a/website/docs/r/appmesh_gateway_route.html.markdown +++ b/website/docs/r/appmesh_gateway_route.html.markdown @@ -106,6 +106,7 @@ The `http_route` and `http2_route`'s `match` object supports the following: * `path` - (Optional) Client request path to match on. * `port` - (Optional) The port number to match from the request. * `prefix` - (Optional) Path to match requests with. This parameter must always start with `/`, which by itself matches all requests to the virtual service name. +* `query_parameter` - (Optional) Client request query parameters to match on. The `header` object supports the following: @@ -137,6 +138,15 @@ The `path` object supports the following: * `exact` - (Optional) The exact path to match on. * `regex` - (Optional) The regex used to match the path. +The `query_parameter` object supports the following: + +* `name` - (Required) Name for the query parameter that will be matched on. +* `match` - (Optional) The query parameter to match on. + +The `query_parameter`'s `match` object supports the following: + +* `exact` - (Optional) The exact query parameter to match on. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: From cec988d478535824a5a478dfae489fbb81cf33b4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Sat, 25 Mar 2023 17:44:46 -0400 Subject: [PATCH 36/36] r/aws_appmesh_virtual_router: 'spec.listener' is Optional. --- .changelog/29064.txt | 4 ++++ internal/service/appmesh/virtual_router.go | 4 ++-- website/docs/r/appmesh_virtual_router.html.markdown | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.changelog/29064.txt b/.changelog/29064.txt index bb5642f7358d..c33a4dbb3499 100644 --- a/.changelog/29064.txt +++ b/.changelog/29064.txt @@ -25,3 +25,7 @@ resource/aws_appmesh_route: `spec.http_route.match.prefix` and `spec.http2_route ```release-note:enhancement resource/aws_appmesh_gateway_route: Add `header`, `path` and `query_parameter` to the `spec.http_route.match` and `spec.http2_route.match` configuration blocks ``` + +```release-note:bug +resource/aws_appmesh_virtual_router: `spec.listener` is Optional +``` \ No newline at end of file diff --git a/internal/service/appmesh/virtual_router.go b/internal/service/appmesh/virtual_router.go index d26f8444d1a5..8d1b0e95cc3f 100644 --- a/internal/service/appmesh/virtual_router.go +++ b/internal/service/appmesh/virtual_router.go @@ -93,8 +93,8 @@ func resourceVirtualRouterSpecSchema() *schema.Schema { Schema: map[string]*schema.Schema{ "listener": { Type: schema.TypeList, - Required: true, - MinItems: 1, + Optional: true, + MinItems: 0, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "port_mapping": { diff --git a/website/docs/r/appmesh_virtual_router.html.markdown b/website/docs/r/appmesh_virtual_router.html.markdown index caaeb7a26660..8ea21c475acb 100644 --- a/website/docs/r/appmesh_virtual_router.html.markdown +++ b/website/docs/r/appmesh_virtual_router.html.markdown @@ -52,7 +52,7 @@ The following arguments are supported: The `spec` object supports the following: -* `listener` - (Required) Listeners that the virtual router is expected to receive inbound traffic from. +* `listener` - (Optional) Listeners that the virtual router is expected to receive inbound traffic from. Currently only one listener is supported per virtual router. The `listener` object supports the following: