From 78290830c5fbbcb04600199338c547c67c53569e Mon Sep 17 00:00:00 2001 From: Stefan Grosaru Date: Wed, 7 Sep 2022 21:09:03 +0100 Subject: [PATCH 01/25] Add AppMesh Route data source --- internal/provider/provider.go | 1 + internal/service/appmesh/route_data_source.go | 620 ++++++++++++++++++ .../service/appmesh/route_data_source_test.go | 350 ++++++++++ 3 files changed, 971 insertions(+) create mode 100644 internal/service/appmesh/route_data_source.go create mode 100644 internal/service/appmesh/route_data_source_test.go diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 18a8e3c52a9..492148f4fc5 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -432,6 +432,7 @@ func New(_ context.Context) (*schema.Provider, error) { "aws_appmesh_mesh": appmesh.DataSourceMesh(), "aws_appmesh_virtual_service": appmesh.DataSourceVirtualService(), + "aws_appmesh_route": appmesh.DataSourceRoute(), "aws_autoscaling_group": autoscaling.DataSourceGroup(), "aws_autoscaling_groups": autoscaling.DataSourceGroups(), diff --git a/internal/service/appmesh/route_data_source.go b/internal/service/appmesh/route_data_source.go new file mode 100644 index 00000000000..1128a7ceabe --- /dev/null +++ b/internal/service/appmesh/route_data_source.go @@ -0,0 +1,620 @@ +package appmesh + +import ( + "fmt" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" +) + +func DataSourceRoute() *schema.Resource { + return &schema.Resource{ + Read: dataSourceRouteRead, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "mesh_name": { + Type: schema.TypeString, + Required: true, + }, + + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "virtual_router_name": { + Type: schema.TypeString, + Required: true, + }, + + "spec": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grpc_route": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node": { + Type: schema.TypeString, + Computed: true, + }, + + "weight": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "match": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metadata": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "invert": { + Type: schema.TypeBool, + Computed: true, + }, + + "match": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Computed: true, + }, + + "prefix": { + Type: schema.TypeString, + Computed: true, + }, + + "range": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end": { + Type: schema.TypeInt, + Computed: true, + }, + + "start": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "regex": { + Type: schema.TypeString, + Computed: true, + }, + + "suffix": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "method_name": { + Type: schema.TypeString, + Computed: true, + }, + + "prefix": { + Type: schema.TypeString, + Computed: true, + }, + + "service_name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "retry_policy": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grpc_retry_events": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "http_retry_events": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "max_retries": { + Type: schema.TypeInt, + Computed: true, + }, + + "per_retry_timeout": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "tcp_retry_events": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + + "timeout": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idle": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "per_request": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "http2_route": func() *schema.Schema { + schema := DataSourceRouteHTTPRouteSchema() + return schema + }(), + + "http_route": func() *schema.Schema { + schema := DataSourceRouteHTTPRouteSchema() + return schema + }(), + + "priority": { + Type: schema.TypeInt, + Computed: true, + }, + + "tcp_route": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node": { + Type: schema.TypeString, + Computed: true, + }, + + "weight": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "timeout": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idle": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "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.TagsSchemaComputed(), + }, + } +} + +func DataSourceRouteHTTPRouteSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node": { + Type: schema.TypeString, + Computed: true, + }, + + "weight": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + + "match": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "invert": { + Type: schema.TypeBool, + Computed: true, + }, + + "match": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Computed: true, + }, + + "prefix": { + Type: schema.TypeString, + Computed: true, + }, + + "range": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end": { + Type: schema.TypeInt, + Computed: true, + }, + + "start": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "regex": { + Type: schema.TypeString, + Computed: true, + }, + + "suffix": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "name": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "method": { + Type: schema.TypeString, + Computed: true, + }, + + "prefix": { + Type: schema.TypeString, + Computed: true, + }, + + "scheme": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + + "retry_policy": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_retry_events": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + + "max_retries": { + Type: schema.TypeInt, + Computed: true, + }, + + "per_retry_timeout": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "tcp_retry_events": { + Type: schema.TypeSet, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + + "timeout": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idle": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + + "per_request": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Computed: true, + }, + + "value": { + Type: schema.TypeInt, + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func dataSourceRouteRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).AppMeshConn + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + req := &appmesh.DescribeRouteInput{ + MeshName: aws.String(d.Get("mesh_name").(string)), + VirtualRouterName: aws.String(d.Get("virtual_router_name").(string)), + RouteName: aws.String(d.Get("name").(string)), + } + + if v, ok := d.GetOk("mesh_owner"); ok { + req.MeshOwner = aws.String(v.(string)) + } + + resp, err := conn.DescribeRoute(req) + if err != nil { + return fmt.Errorf("error reading App Mesh Route: %s", err) + } + + arn := aws.StringValue(resp.Route.Metadata.Arn) + + d.SetId(aws.StringValue(resp.Route.RouteName)) + + d.Set("name", resp.Route.RouteName) + d.Set("mesh_name", resp.Route.MeshName) + d.Set("mesh_owner", resp.Route.Metadata.MeshOwner) + d.Set("virtual_router_name", resp.Route.VirtualRouterName) + d.Set("arn", arn) + d.Set("created_date", resp.Route.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", resp.Route.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("resource_owner", resp.Route.Metadata.ResourceOwner) + + err = d.Set("spec", flattenRouteSpec(resp.Route.Spec)) + if err != nil { + return fmt.Errorf("error setting spec: %s", err) + } + + tags, err := ListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for App Mesh Route (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %s", err) + } + + return nil +} diff --git a/internal/service/appmesh/route_data_source_test.go b/internal/service/appmesh/route_data_source_test.go new file mode 100644 index 00000000000..01ad86eda61 --- /dev/null +++ b/internal/service/appmesh/route_data_source_test.go @@ -0,0 +1,350 @@ +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 TestAccAppMeshRouteDataSource_http2Route(t *testing.T) { + resourceName := "aws_appmesh_route.test" + dataSourceName := "data.aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vrName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + 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: testAccCheckRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRouteDataSourceConfig_http2Route(meshName, vrName, vnName, rName), + 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, "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.0.http2_route", dataSourceName, "spec.0.http2_route"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAppMeshRouteDataSource_httpRoute(t *testing.T) { + resourceName := "aws_appmesh_route.test" + dataSourceName := "data.aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vrName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + 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: testAccCheckRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRouteDataSourceConfig_httpRoute(meshName, vrName, vnName, rName), + 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, "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.0.http_route", dataSourceName, "spec.0.http_route"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAppMeshRouteDataSource_grpcRoute(t *testing.T) { + resourceName := "aws_appmesh_route.test" + dataSourceName := "data.aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vrName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + 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: testAccCheckRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRouteDataSourceConfig_grpcRoute(meshName, vrName, vnName, rName), + 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, "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.0.grpc_route", dataSourceName, "spec.0.grpc_route"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func TestAccAppMeshRouteDataSource_tcpRoute(t *testing.T) { + resourceName := "aws_appmesh_route.test" + dataSourceName := "data.aws_appmesh_route.test" + meshName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vrName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + 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: testAccCheckRouteDestroy, + Steps: []resource.TestStep{ + { + Config: testAccRouteDataSourceConfig_tcpRoute(meshName, vrName, vnName, rName), + 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, "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.0.tcp_route", dataSourceName, "spec.0.tcp_route"), + resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + ), + }, + }, + }) +} + +func testAccRouteDataSourceConfigBase(meshName, vrName, vnName 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" + } + } + } + } + + resource "aws_appmesh_virtual_node" "test" { + name = %[3]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} + } +`, meshName, vrName, vnName) +} + +func testAccRouteDataSourceConfig_httpRoute(meshName, vrName, vnName, rName string) string { + return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + http2_route { + match { + prefix = "/" + method = "POST" + scheme = "http" + + header { + name = "X-Testing1" + } + } + + retry_policy { + http_retry_events = [ + "server-error", + ] + + max_retries = 1 + + per_retry_timeout { + unit = "s" + value = 15 + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test.name + weight = 100 + } + } + } + } + } + +data "aws_appmesh_route" "test" { + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name +} +`, rName)) +} + +func testAccRouteDataSourceConfig_http2Route(meshName, vrName, vnName, rName string) string { + return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + http2_route { + match { + prefix = "/" + method = "POST" + scheme = "http" + + header { + name = "X-Testing1" + } + } + + retry_policy { + http_retry_events = [ + "server-error", + ] + + max_retries = 1 + + per_retry_timeout { + unit = "s" + value = 15 + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test.name + weight = 100 + } + } + } + } +} + +data "aws_appmesh_route" "test" { + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name +} +`, rName)) +} + +func testAccRouteDataSourceConfig_grpcRoute(meshName, vrName, vnName, rName string) string { + return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` +resource "aws_appmesh_route" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + grpc_route { + match { + metadata { + name = "X-Testing1" + } + } + + retry_policy { + grpc_retry_events = [ + "deadline-exceeded", + "resource-exhausted", + ] + + http_retry_events = [ + "server-error", + ] + + max_retries = 1 + + per_retry_timeout { + unit = "s" + value = 15 + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test.name + weight = 100 + } + } + } + } +} + +data "aws_appmesh_route" "test" { + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name +} +`, rName)) +} + +func testAccRouteDataSourceConfig_tcpRoute(meshName, vrName, vnName, rName string) string { + return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), 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 { + tcp_route { + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test.name + weight = 100 + } + } + } + } +} + +data "aws_appmesh_route" "test" { + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name +} +`, rName)) +} From 7b74bcec9a40b761aa3e182a610d0e91e22b6722 Mon Sep 17 00:00:00 2001 From: stefangrosaru Date: Wed, 7 Sep 2022 23:33:35 +0100 Subject: [PATCH 02/25] Add changelog --- .changelog/26695.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/26695.txt diff --git a/.changelog/26695.txt b/.changelog/26695.txt new file mode 100644 index 00000000000..3e07ec4f56a --- /dev/null +++ b/.changelog/26695.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_appmesh_route +``` From 97199c324f0750fcf17b5f4dd077c5f2399de1c9 Mon Sep 17 00:00:00 2001 From: stefangrosaru Date: Thu, 8 Sep 2022 00:20:03 +0100 Subject: [PATCH 03/25] Add App Mesh Route data source documentation --- website/docs/d/appmesh_route.html.markdown | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 website/docs/d/appmesh_route.html.markdown diff --git a/website/docs/d/appmesh_route.html.markdown b/website/docs/d/appmesh_route.html.markdown new file mode 100644 index 00000000000..a8e7f7ba875 --- /dev/null +++ b/website/docs/d/appmesh_route.html.markdown @@ -0,0 +1,68 @@ +--- +subcategory: "App Mesh" +layout: "aws" +page_title: "AWS: aws_appmesh_route" +description: |- + Provides an AWS App Mesh route resource. +--- + +# Data Source: aws_appmesh_route + +The App Mesh Route data source allows details of an App Mesh Route to be retrieved by its name, mesh_name, virtual_router_name, and optionally the mesh_owner. + +## Example Usage + +```hcl +data "aws_appmesh_virtual_service" "test" { + name = "test-route" + mesh_name = "test-mesh" + virtual_router_name = "test-router" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) Name of the route. +* `mesh_name` - (Required) Name of the service mesh in which the virtual router exists. +* `virtual_router_name` - (Required) Name of the virtual router 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 route. +* `created_date` - Creation date of the route. +* `last_updated_date` - Last update date of the route. +* `resource_owner` - Resource owner's AWS account ID. +* `spec` - Route specification +* `tags` - Map of tags. + +### Spec + +* `grpc_route` - GRPC routing information for the route. +* `http2_route` - HTTP/2 routing information for the route. +* `http_route` - HTTP routing information for the route. +* `tcp_route` - TCP routing information for the route. +* `priority` - Priority for the route, between `0` and `1000`. + +### grpc_route + +* `action` - Action to take if a match is determined. +* `match` - Criteria for determining an gRPC request match. +* `retry_policy` - Retry policy. +* `timeout` - Types of timeouts. + +### http2_route and http_route + +* `action` - Action to take if a match is determined. +* `match` - Criteria for determining an HTTP request match. +* `retry_policy` - Retry policy. +* `timeout` - Types of timeouts. + +### tcp_route + +* `action` - Action to take if a match is determined. +* `timeout` - Types of timeouts. From 3b6cd8bc2b58e6e128673a2e6fa8d1386556e1b3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 08:48:19 -0400 Subject: [PATCH 04/25] r/aws_appmesh_mesh: Alphabetize attributes. --- internal/service/appmesh/mesh.go | 65 ++++++++++++++------------------ 1 file changed, 28 insertions(+), 37 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 50db0d68d3c..e831015a923 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -17,6 +17,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_mesh") @@ -26,18 +27,38 @@ func ResourceMesh() *schema.Resource { ReadWithoutTimeout: resourceMeshRead, UpdateWithoutTimeout: resourceMeshUpdate, DeleteWithoutTimeout: resourceMeshDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, 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_owner": { + Type: schema.TypeString, + Computed: true, + }, "name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, "spec": { Type: schema.TypeList, Optional: true, @@ -54,13 +75,10 @@ func ResourceMesh() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { - Type: schema.TypeString, - Optional: true, - Default: appmesh.EgressFilterTypeDropAll, - ValidateFunc: validation.StringInSlice([]string{ - appmesh.EgressFilterTypeAllowAll, - appmesh.EgressFilterTypeDropAll, - }, false), + Type: schema.TypeString, + Optional: true, + Default: appmesh.EgressFilterTypeDropAll, + ValidateFunc: validation.StringInSlice(appmesh.EgressFilterType_Values(), false), }, }, }, @@ -68,35 +86,8 @@ func ResourceMesh() *schema.Resource { }, }, }, - - "arn": { - Type: schema.TypeString, - Computed: true, - }, - - "created_date": { - Type: schema.TypeString, - Computed: true, - }, - - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - - "mesh_owner": { - Type: schema.TypeString, - Computed: true, - }, - - "resource_owner": { - Type: schema.TypeString, - Computed: true, - }, - - "tags": tftags.TagsSchema(), - - "tags_all": tftags.TagsSchemaComputed(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), }, CustomizeDiff: verify.SetTagsDiff, From dff4209cfeddb3b06b24306eeca647fc5d32bb08 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 08:52:46 -0400 Subject: [PATCH 05/25] r/aws_appmesh_mesh: Tidy up resource Create, Update and Delete. --- internal/service/appmesh/mesh.go | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index e831015a923..9c42d36e44d 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -101,16 +101,16 @@ func resourceMeshCreate(ctx context.Context, d *schema.ResourceData, meta interf tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) meshName := d.Get("name").(string) - req := &appmesh.CreateMeshInput{ + input := &appmesh.CreateMeshInput{ MeshName: aws.String(meshName), Spec: expandMeshSpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), } - log.Printf("[DEBUG] Creating App Mesh service mesh: %#v", req) - _, err := conn.CreateMeshWithContext(ctx, req) + _, err := conn.CreateMeshWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh service mesh: %s", err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Service Mesh (%s): %s", meshName, err) } d.SetId(meshName) @@ -214,25 +214,24 @@ func resourceMeshUpdate(ctx context.Context, d *schema.ResourceData, meta interf conn := meta.(*conns.AWSClient).AppMeshConn() if d.HasChange("spec") { - _, v := d.GetChange("spec") - req := &appmesh.UpdateMeshInput{ + input := &appmesh.UpdateMeshInput{ MeshName: aws.String(d.Id()), - Spec: expandMeshSpec(v.([]interface{})), + Spec: expandMeshSpec(d.Get("spec").([]interface{})), } - log.Printf("[DEBUG] Updating App Mesh service mesh: %#v", req) - _, err := conn.UpdateMeshWithContext(ctx, req) + _, err := conn.UpdateMeshWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh service mesh: %s", err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Service Mesh (%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 service mesh (%s) tags: %s", arn, err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Service Mesh (%s) tags: %s", arn, err) } } @@ -247,11 +246,13 @@ func resourceMeshDelete(ctx context.Context, d *schema.ResourceData, meta interf _, err := conn.DeleteMeshWithContext(ctx, &appmesh.DeleteMeshInput{ MeshName: aws.String(d.Id()), }) + if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { return diags } + if err != nil { - return sdkdiag.AppendErrorf(diags, "deleting App Mesh service mesh: %s", err) + return sdkdiag.AppendErrorf(diags, "deleting App Mesh Service Mesh (%s): %s", d.Id(), err) } return diags From 3b0fc673c5a3a80b37fe2d4ab228c9e65a8e9272 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 09:07:36 -0400 Subject: [PATCH 06/25] r/aws_appmesh_mesh: Tidy up resource Read. --- internal/service/appmesh/mesh.go | 111 ++++++++++++++++--------------- 1 file changed, 59 insertions(+), 52 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 9c42d36e44d..4146a77cb56 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -124,67 +124,29 @@ func resourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interfac defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeMeshInput{ - MeshName: aws.String(d.Id()), - } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } - - var resp *appmesh.DescribeMeshOutput - - err := resource.RetryContext(ctx, propagationTimeout, func() *resource.RetryError { - var err error - - resp, err = conn.DescribeMeshWithContext(ctx, req) - - 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) { - resp, err = conn.DescribeMeshWithContext(ctx, req) - } + outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, propagationTimeout, func() (interface{}, error) { + return FindMeshByTwoPartKey(ctx, conn, d.Id(), d.Get("mesh_owner").(string)) + }, d.IsNewResource()) - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] App Mesh Service Mesh (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Service Mesh: %s", err) - } - - if resp == nil || resp.Mesh == nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Service Mesh: empty response") - } - - if aws.StringValue(resp.Mesh.Status.Status) == appmesh.MeshStatusCodeDeleted { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Service Mesh: %s after creation", aws.StringValue(resp.Mesh.Status.Status)) - } - - log.Printf("[WARN] App Mesh Service Mesh (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags + return sdkdiag.AppendErrorf(diags, "reading App Mesh Service Mesh (%s): %s", d.Id(), err) } - arn := aws.StringValue(resp.Mesh.Metadata.Arn) - d.Set("name", resp.Mesh.MeshName) + mesh := outputRaw.(*appmesh.MeshData) + arn := aws.StringValue(mesh.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.Mesh.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.Mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("mesh_owner", resp.Mesh.Metadata.MeshOwner) - d.Set("resource_owner", resp.Mesh.Metadata.ResourceOwner) - err = d.Set("spec", flattenMeshSpec(resp.Mesh.Spec)) + d.Set("created_date", mesh.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_owner", mesh.Metadata.MeshOwner) + d.Set("name", mesh.MeshName) + d.Set("resource_owner", mesh.Metadata.ResourceOwner) + err = d.Set("spec", flattenMeshSpec(mesh.Spec)) if err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } @@ -192,7 +154,7 @@ func resourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interfac tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh service mesh (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Service Mesh (%s): %s", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -257,3 +219,48 @@ func resourceMeshDelete(ctx context.Context, d *schema.ResourceData, meta interf return diags } + +func FindMeshByTwoPartKey(ctx context.Context, conn *appmesh.AppMesh, name, owner string) (*appmesh.MeshData, error) { + input := &appmesh.DescribeMeshInput{ + MeshName: aws.String(name), + } + if owner != "" { + input.MeshOwner = aws.String(owner) + } + + output, err := findMesh(ctx, conn, input) + + if err != nil { + return nil, err + } + + if status := aws.StringValue(output.Status.Status); status == appmesh.MeshStatusCodeDeleted { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + return output, nil +} + +func findMesh(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.DescribeMeshInput) (*appmesh.MeshData, error) { + output, err := conn.DescribeMeshWithContext(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.Mesh == nil || output.Mesh.Metadata == nil || output.Mesh.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.Mesh, nil +} From c7b6ebcbe07d2e3989b0b2cd30360662c982ac45 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 09:26:05 -0400 Subject: [PATCH 07/25] r/aws_appmesh_mesh: Tidy up acceptance tests. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Mesh$$' 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/^Mesh$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Mesh === RUN TestAccAppMesh_serial/Mesh/basic === RUN TestAccAppMesh_serial/Mesh/disappears === RUN TestAccAppMesh_serial/Mesh/egressFilter === RUN TestAccAppMesh_serial/Mesh/tags === RUN TestAccAppMesh_serial/Mesh/dataSourceBasic === RUN TestAccAppMesh_serial/Mesh/dataSourceMeshOwner === RUN TestAccAppMesh_serial/Mesh/dataSourceSpecAndTagsSet --- PASS: TestAccAppMesh_serial (141.49s) --- PASS: TestAccAppMesh_serial/Mesh (141.49s) --- PASS: TestAccAppMesh_serial/Mesh/basic (18.02s) --- PASS: TestAccAppMesh_serial/Mesh/disappears (11.18s) --- PASS: TestAccAppMesh_serial/Mesh/egressFilter (35.47s) --- PASS: TestAccAppMesh_serial/Mesh/tags (35.17s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceBasic (13.69s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceMeshOwner (14.72s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceSpecAndTagsSet (13.24s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 149.261s --- internal/service/appmesh/appmesh_test.go | 1 + internal/service/appmesh/mesh_test.go | 110 +++++++++++++---------- 2 files changed, 62 insertions(+), 49 deletions(-) diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 6dd9fbd24ed..6e80d751a6f 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -23,6 +23,7 @@ func TestAccAppMesh_serial(t *testing.T) { }, "Mesh": { "basic": testAccMesh_basic, + "disappears": testAccMesh_disappears, "egressFilter": testAccMesh_egressFilter, "tags": testAccMesh_tags, "dataSourceBasic": testAccMeshDataSource_basic, diff --git a/internal/service/appmesh/mesh_test.go b/internal/service/appmesh/mesh_test.go index f020c70b0d8..3e6a208eb35 100644 --- a/internal/service/appmesh/mesh_test.go +++ b/internal/service/appmesh/mesh_test.go @@ -6,14 +6,14 @@ import ( "regexp" "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 testAccMesh_basic(t *testing.T) { @@ -30,14 +30,15 @@ func testAccMesh_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccMeshConfig_basic(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckMeshExists(ctx, resourceName, &mesh), - resource.TestCheckResourceAttr(resourceName, "name", rName), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "appmesh", regexp.MustCompile(`mesh/.+`)), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), acctest.CheckResourceAttrAccountID(resourceName, "mesh_owner"), + resource.TestCheckResourceAttr(resourceName, "name", rName), acctest.CheckResourceAttrAccountID(resourceName, "resource_owner"), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "appmesh", regexp.MustCompile(`mesh/.+`)), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), ), }, { @@ -49,6 +50,30 @@ func testAccMesh_basic(t *testing.T) { }) } +func testAccMesh_disappears(t *testing.T) { + ctx := acctest.Context(t) + var mesh appmesh.MeshData + resourceName := "aws_appmesh_mesh.test" + 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: testAccCheckMeshDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccMeshConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckMeshExists(ctx, resourceName, &mesh), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfappmesh.ResourceMesh(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccMesh_egressFilter(t *testing.T) { ctx := acctest.Context(t) var mesh appmesh.MeshData @@ -65,7 +90,8 @@ func testAccMesh_egressFilter(t *testing.T) { Config: testAccMeshConfig_egressFilter(rName, "ALLOW_ALL"), Check: resource.ComposeTestCheckFunc( testAccCheckMeshExists(ctx, resourceName, &mesh), - resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.egress_filter.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.egress_filter.0.type", "ALLOW_ALL"), ), }, @@ -103,12 +129,11 @@ func testAccMesh_tags(t *testing.T) { CheckDestroy: testAccCheckMeshDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccMeshConfig_tags(rName), + Config: testAccMeshConfig_tags1(rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckMeshExists(ctx, resourceName, &mesh), - 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"), ), }, { @@ -117,19 +142,20 @@ func testAccMesh_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccMeshConfig_updateTags(rName), + Config: testAccMeshConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckMeshExists(ctx, resourceName, &mesh), - resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr(resourceName, "tags.good", "bad2"), - resource.TestCheckResourceAttr(resourceName, "tags.fizz", "buzz"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - Config: testAccMeshConfig_removeTags(rName), + Config: testAccMeshConfig_tags1(rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckMeshExists(ctx, resourceName, &mesh), resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, }, @@ -145,42 +171,42 @@ func testAccCheckMeshDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := conn.DescribeMeshWithContext(ctx, &appmesh.DescribeMeshInput{ - MeshName: aws.String(rs.Primary.Attributes["name"]), - }) - if tfawserr.ErrCodeEquals(err, "NotFoundException") { + _, err := tfappmesh.FindMeshByTwoPartKey(ctx, conn, rs.Primary.ID, rs.Primary.Attributes["mesh_owner"]) + + if tfresource.NotFound(err) { continue } + if err != nil { return err } - return fmt.Errorf("still exist.") + + return fmt.Errorf("App Mesh Service Mesh %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckMeshExists(ctx context.Context, name string, v *appmesh.MeshData) resource.TestCheckFunc { +func testAccCheckMeshExists(ctx context.Context, n string, v *appmesh.MeshData) 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 Service Mesh ID is set") } - resp, err := conn.DescribeMeshWithContext(ctx, &appmesh.DescribeMeshInput{ - MeshName: aws.String(rs.Primary.Attributes["name"]), - }) + output, err := tfappmesh.FindMeshByTwoPartKey(ctx, conn, rs.Primary.ID, rs.Primary.Attributes["mesh_owner"]) + if err != nil { return err } - *v = *resp.Mesh + *v = *output return nil } @@ -208,41 +234,27 @@ resource "aws_appmesh_mesh" "test" { `, rName, egressFilterType) } -func testAccMeshConfig_tags(rName string) string { +func testAccMeshConfig_tags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q tags = { - foo = "bar" - good = "bad" + %[2]q = %[3]q } } -`, rName) +`, rName, tagKey1, tagValue1) } -func testAccMeshConfig_updateTags(rName string) string { +func testAccMeshConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q tags = { - foo = "bar" - good = "bad2" - fizz = "buzz" + %[2]q = %[3]q + %[4]q = %[5]q } } -`, rName) -} - -func testAccMeshConfig_removeTags(rName string) string { - return fmt.Sprintf(` -resource "aws_appmesh_mesh" "test" { - name = %[1]q - - tags = { - foo = "bar" - } -} -`, rName) +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) } From b5e25f64dded069690ecd62a143cce21073ef2e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 11:36:19 -0400 Subject: [PATCH 08/25] d/aws_appmesh_mesh: Tidy up. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Mesh$$/dataSource' 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/^Mesh$/dataSource -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Mesh === RUN TestAccAppMesh_serial/Mesh/dataSourceSpecAndTagsSet === RUN TestAccAppMesh_serial/Mesh/dataSourceBasic === RUN TestAccAppMesh_serial/Mesh/dataSourceMeshOwner --- PASS: TestAccAppMesh_serial (42.20s) --- PASS: TestAccAppMesh_serial/Mesh (42.20s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceSpecAndTagsSet (15.28s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceBasic (12.89s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceMeshOwner (14.03s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 47.909s --- internal/service/appmesh/mesh_data_source.go | 42 ++++++------------- .../service/appmesh/mesh_data_source_test.go | 22 +++++----- 2 files changed, 24 insertions(+), 40 deletions(-) diff --git a/internal/service/appmesh/mesh_data_source.go b/internal/service/appmesh/mesh_data_source.go index 851ae37892f..5353676a334 100644 --- a/internal/service/appmesh/mesh_data_source.go +++ b/internal/service/appmesh/mesh_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_mesh") @@ -23,33 +23,27 @@ func DataSourceMesh() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "created_date": { Type: schema.TypeString, Computed: true, }, - "last_updated_date": { Type: schema.TypeString, Computed: 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, @@ -70,8 +64,7 @@ func DataSourceMesh() *schema.Resource { }, }, }, - - "tags": tftags.TagsSchemaComputed(), + names.AttrTags: tftags.TagsSchemaComputed(), }, } } @@ -82,31 +75,20 @@ func dataSourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interf ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig meshName := d.Get("name").(string) + mesh, err := FindMeshByTwoPartKey(ctx, conn, meshName, d.Get("mesh_owner").(string)) - req := &appmesh.DescribeMeshInput{ - MeshName: aws.String(meshName), - } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } - - resp, err := conn.DescribeMeshWithContext(ctx, req) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh service mesh: %s", err) - } - if aws.StringValue(resp.Mesh.Status.Status) == appmesh.MeshStatusCodeDeleted { - return sdkdiag.AppendErrorf(diags, "App Mesh Mesh (%s) has status: 'DELETED'", meshName) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Service Mesh (%s): %s", meshName, err) } - arn := aws.StringValue(resp.Mesh.Metadata.Arn) - - d.SetId(aws.StringValue(resp.Mesh.MeshName)) + d.SetId(aws.StringValue(mesh.MeshName)) + arn := aws.StringValue(mesh.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.Mesh.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.Mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("mesh_owner", resp.Mesh.Metadata.MeshOwner) - d.Set("resource_owner", resp.Mesh.Metadata.ResourceOwner) - err = d.Set("spec", flattenMeshSpec(resp.Mesh.Spec)) + d.Set("created_date", mesh.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_owner", mesh.Metadata.MeshOwner) + d.Set("resource_owner", mesh.Metadata.ResourceOwner) + err = d.Set("spec", flattenMeshSpec(mesh.Spec)) if err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } @@ -114,7 +96,7 @@ func dataSourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interf tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh service mesh (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Service Mesh (%s): %s", arn, err) } if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { diff --git a/internal/service/appmesh/mesh_data_source_test.go b/internal/service/appmesh/mesh_data_source_test.go index 9ff67390113..abdb9a68c03 100644 --- a/internal/service/appmesh/mesh_data_source_test.go +++ b/internal/service/appmesh/mesh_data_source_test.go @@ -20,19 +20,20 @@ func testAccMeshDataSource_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckMeshDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccMeshDataSourceConfig_basic(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"), 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.egress_filter.#", dataSourceName, "spec.0.egress_filter.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, @@ -49,19 +50,20 @@ func testAccMeshDataSource_meshOwner(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckMeshDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccMeshDataSourceConfig_meshOwner(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"), 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.egress_filter.#", dataSourceName, "spec.0.egress_filter.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, @@ -78,7 +80,6 @@ func testAccMeshDataSource_specAndTagsSet(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckMeshDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccMeshDataSourceConfig_specAndTagsSet(rName), @@ -89,8 +90,10 @@ func testAccMeshDataSource_specAndTagsSet(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.egress_filter.#", dataSourceName, "spec.0.egress_filter.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, @@ -138,8 +141,7 @@ resource "aws_appmesh_mesh" "test" { } tags = { - foo = "bar" - good = "bad" + Name = %[1]q } } From 811ad00ae04460f90522bda0066a8c086314fa16 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 12:08:43 -0400 Subject: [PATCH 09/25] r/aws_appmesh_virtual_service: Alphabetize attributes. --- internal/service/appmesh/virtual_service.go | 57 +++++++++------------ 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/internal/service/appmesh/virtual_service.go b/internal/service/appmesh/virtual_service.go index 92528514754..fcba11e7350 100644 --- a/internal/service/appmesh/virtual_service.go +++ b/internal/service/appmesh/virtual_service.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_service") @@ -34,20 +35,24 @@ func ResourceVirtualService() *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, @@ -55,7 +60,16 @@ func ResourceVirtualService() *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": { Type: schema.TypeList, Required: true, @@ -86,7 +100,6 @@ func ResourceVirtualService() *schema.Resource { }, }, }, - "virtual_router": { Type: schema.TypeList, Optional: true, @@ -109,30 +122,8 @@ func ResourceVirtualService() *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(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), }, CustomizeDiff: verify.SetTagsDiff, From 865b93dc57943f868f646041972f7562844180d3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 12:14:48 -0400 Subject: [PATCH 10/25] r/aws_appmesh_virtual_service: Tidy up resource Create, Update and Delete. --- internal/service/appmesh/mesh.go | 8 +++--- internal/service/appmesh/virtual_service.go | 32 +++++++++++---------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 4146a77cb56..2677db60f16 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -100,9 +100,9 @@ func resourceMeshCreate(ctx context.Context, d *schema.ResourceData, meta interf defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) - meshName := d.Get("name").(string) + name := d.Get("name").(string) input := &appmesh.CreateMeshInput{ - MeshName: aws.String(meshName), + MeshName: aws.String(name), Spec: expandMeshSpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), } @@ -110,10 +110,10 @@ func resourceMeshCreate(ctx context.Context, d *schema.ResourceData, meta interf _, err := conn.CreateMeshWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh Service Mesh (%s): %s", meshName, err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Service Mesh (%s): %s", name, err) } - d.SetId(meshName) + d.SetId(name) return append(diags, resourceMeshRead(ctx, d, meta)...) } diff --git a/internal/service/appmesh/virtual_service.go b/internal/service/appmesh/virtual_service.go index fcba11e7350..a8394cc10c7 100644 --- a/internal/service/appmesh/virtual_service.go +++ b/internal/service/appmesh/virtual_service.go @@ -136,23 +136,25 @@ func resourceVirtualServiceCreate(ctx context.Context, d *schema.ResourceData, m defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) - req := &appmesh.CreateVirtualServiceInput{ + name := d.Get("name").(string) + input := &appmesh.CreateVirtualServiceInput{ MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualServiceName: aws.String(d.Get("name").(string)), Spec: expandVirtualServiceSpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), + VirtualServiceName: 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 service: %#v", req) - resp, err := conn.CreateVirtualServiceWithContext(ctx, req) + output, err := conn.CreateVirtualServiceWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh virtual service: %s", err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Virtual Service (%s): %s", name, err) } - d.SetId(aws.StringValue(resp.VirtualService.Metadata.Uid)) + d.SetId(aws.StringValue(output.VirtualService.Metadata.Uid)) return append(diags, resourceVirtualServiceRead(ctx, d, meta)...) } @@ -255,20 +257,20 @@ func resourceVirtualServiceUpdate(ctx context.Context, d *schema.ResourceData, m conn := meta.(*conns.AWSClient).AppMeshConn() if d.HasChange("spec") { - _, v := d.GetChange("spec") - req := &appmesh.UpdateVirtualServiceInput{ + input := &appmesh.UpdateVirtualServiceInput{ MeshName: aws.String(d.Get("mesh_name").(string)), + Spec: expandVirtualServiceSpec(d.Get("spec").([]interface{})), VirtualServiceName: aws.String(d.Get("name").(string)), - Spec: expandVirtualServiceSpec(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 service: %#v", req) - _, err := conn.UpdateVirtualServiceWithContext(ctx, req) + _, err := conn.UpdateVirtualServiceWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh virtual service: %s", err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Virtual Service (%s): %s", d.Id(), err) } } @@ -277,7 +279,7 @@ func resourceVirtualServiceUpdate(ctx context.Context, d *schema.ResourceData, m o, n := d.GetChange("tags_all") if err := UpdateTags(ctx, conn, arn, o, n); err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh virtual service (%s) tags: %s", arn, err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Virtual Service (%s) tags: %s", arn, err) } } From 0855dc3d48f73f16c131e75dc0849f006d4de5f6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 13:20:34 -0400 Subject: [PATCH 11/25] r/aws_appmesh_virtual_service: Tidy up resource Read. --- internal/service/appmesh/virtual_service.go | 114 +++++++++++--------- 1 file changed, 61 insertions(+), 53 deletions(-) diff --git a/internal/service/appmesh/virtual_service.go b/internal/service/appmesh/virtual_service.go index a8394cc10c7..1a8d905ec05 100644 --- a/internal/service/appmesh/virtual_service.go +++ b/internal/service/appmesh/virtual_service.go @@ -165,69 +165,31 @@ func resourceVirtualServiceRead(ctx context.Context, d *schema.ResourceData, met defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeVirtualServiceInput{ - MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualServiceName: aws.String(d.Get("name").(string)), - } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } - - var resp *appmesh.DescribeVirtualServiceOutput - - err := resource.RetryContext(ctx, propagationTimeout, func() *resource.RetryError { - var err error + outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, propagationTimeout, func() (interface{}, error) { + return FindVirtualServiceByThreePartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("name").(string)) + }, d.IsNewResource()) - resp, err = conn.DescribeVirtualServiceWithContext(ctx, req) - - 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) { - resp, err = conn.DescribeVirtualServiceWithContext(ctx, req) - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] App Mesh Virtual Service (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Service: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Service (%s): %s", d.Id(), err) } - if resp == nil || resp.VirtualService == nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Service: empty response") - } + vs := outputRaw.(*appmesh.VirtualServiceData) - if aws.StringValue(resp.VirtualService.Status.Status) == appmesh.VirtualServiceStatusCodeDeleted { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Service: %s after creation", aws.StringValue(resp.VirtualService.Status.Status)) - } - - log.Printf("[WARN] App Mesh Virtual Service (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } - - arn := aws.StringValue(resp.VirtualService.Metadata.Arn) - d.Set("name", resp.VirtualService.VirtualServiceName) - d.Set("mesh_name", resp.VirtualService.MeshName) - d.Set("mesh_owner", resp.VirtualService.Metadata.MeshOwner) + arn := aws.StringValue(vs.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.VirtualService.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.VirtualService.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("resource_owner", resp.VirtualService.Metadata.ResourceOwner) - err = d.Set("spec", flattenVirtualServiceSpec(resp.VirtualService.Spec)) + d.Set("created_date", vs.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", vs.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", vs.MeshName) + d.Set("mesh_owner", vs.Metadata.MeshOwner) + d.Set("name", vs.VirtualServiceName) + d.Set("resource_owner", vs.Metadata.ResourceOwner) + err = d.Set("spec", flattenVirtualServiceSpec(vs.Spec)) if err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } @@ -235,7 +197,7 @@ func resourceVirtualServiceRead(ctx context.Context, d *schema.ResourceData, met tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh virtual service (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Service (%s): %s", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -339,3 +301,49 @@ func resourceVirtualServiceImport(ctx context.Context, d *schema.ResourceData, m return []*schema.ResourceData{d}, nil } + +func FindVirtualServiceByThreePartKey(ctx context.Context, conn *appmesh.AppMesh, meshName, meshOwner, name string) (*appmesh.VirtualServiceData, error) { + input := &appmesh.DescribeVirtualServiceInput{ + MeshName: aws.String(meshName), + VirtualServiceName: aws.String(name), + } + if meshOwner != "" { + input.MeshOwner = aws.String(meshOwner) + } + + output, err := findVirtualService(ctx, conn, input) + + if err != nil { + return nil, err + } + + if status := aws.StringValue(output.Status.Status); status == appmesh.VirtualServiceStatusCodeDeleted { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + return output, nil +} + +func findVirtualService(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.DescribeVirtualServiceInput) (*appmesh.VirtualServiceData, error) { + output, err := conn.DescribeVirtualServiceWithContext(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.VirtualService == nil || output.VirtualService.Metadata == nil || output.VirtualService.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.VirtualService, nil +} From b4c866ed550bb3f9a8e2a347b682eb9b2d7c3d7f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 13:30:07 -0400 Subject: [PATCH 12/25] r/aws_appmesh_virtual_service: Tidy up resource Import. --- internal/service/appmesh/virtual_service.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/internal/service/appmesh/virtual_service.go b/internal/service/appmesh/virtual_service.go index 1a8d905ec05..59a48c5c942 100644 --- a/internal/service/appmesh/virtual_service.go +++ b/internal/service/appmesh/virtual_service.go @@ -281,23 +281,19 @@ func resourceVirtualServiceImport(ctx context.Context, d *schema.ResourceData, m return []*schema.ResourceData{}, fmt.Errorf("wrong format of import ID (%s), use: 'mesh-name/virtual-service-name'", d.Id()) } - mesh := parts[0] + conn := meta.(*conns.AWSClient).AppMeshConn() + meshName := parts[0] name := parts[1] - log.Printf("[DEBUG] Importing App Mesh virtual service %s from mesh %s", name, mesh) - conn := meta.(*conns.AWSClient).AppMeshConn() + vs, err := FindVirtualServiceByThreePartKey(ctx, conn, meshName, "", name) - resp, err := conn.DescribeVirtualServiceWithContext(ctx, &appmesh.DescribeVirtualServiceInput{ - MeshName: aws.String(mesh), - VirtualServiceName: aws.String(name), - }) if err != nil { return nil, err } - d.SetId(aws.StringValue(resp.VirtualService.Metadata.Uid)) - d.Set("name", resp.VirtualService.VirtualServiceName) - d.Set("mesh_name", resp.VirtualService.MeshName) + d.SetId(aws.StringValue(vs.Metadata.Uid)) + d.Set("mesh_name", vs.MeshName) + d.Set("name", vs.VirtualServiceName) return []*schema.ResourceData{d}, nil } From e50176f8d06ac43db63719021f49abf7cfddc3b3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 13:54:48 -0400 Subject: [PATCH 13/25] r/aws_appmesh_virtual_service: Tidy up acceptance tests. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^VirtualService$$' 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/^VirtualService$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/VirtualService === RUN TestAccAppMesh_serial/VirtualService/tags === RUN TestAccAppMesh_serial/VirtualService/dataSourceVirtualNode === RUN TestAccAppMesh_serial/VirtualService/dataSourceVirtualRouter === RUN TestAccAppMesh_serial/VirtualService/disappears === RUN TestAccAppMesh_serial/VirtualService/virtualNode === RUN TestAccAppMesh_serial/VirtualService/virtualRouter --- PASS: TestAccAppMesh_serial (140.21s) --- PASS: TestAccAppMesh_serial/VirtualService (140.21s) --- PASS: TestAccAppMesh_serial/VirtualService/tags (42.80s) --- PASS: TestAccAppMesh_serial/VirtualService/dataSourceVirtualNode (15.36s) --- PASS: TestAccAppMesh_serial/VirtualService/dataSourceVirtualRouter (15.61s) --- PASS: TestAccAppMesh_serial/VirtualService/disappears (13.90s) --- PASS: TestAccAppMesh_serial/VirtualService/virtualNode (27.55s) --- PASS: TestAccAppMesh_serial/VirtualService/virtualRouter (24.99s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 146.586s --- .../service/appmesh/virtual_service_test.go | 121 +++++++++++------- 1 file changed, 75 insertions(+), 46 deletions(-) diff --git a/internal/service/appmesh/virtual_service_test.go b/internal/service/appmesh/virtual_service_test.go index ab9772f9ddd..92df78c7419 100644 --- a/internal/service/appmesh/virtual_service_test.go +++ b/internal/service/appmesh/virtual_service_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 testAccVirtualService_virtualNode(t *testing.T) { @@ -32,7 +31,7 @@ func testAccVirtualService_virtualNode(t *testing.T) { CheckDestroy: testAccCheckVirtualServiceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.foo"), + Config: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.test1"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), resource.TestCheckResourceAttr(resourceName, "name", vsName), @@ -49,7 +48,7 @@ func testAccVirtualService_virtualNode(t *testing.T) { ), }, { - Config: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.bar"), + Config: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.test2"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), resource.TestCheckResourceAttr(resourceName, "name", vsName), @@ -87,7 +86,7 @@ func testAccVirtualService_virtualRouter(t *testing.T) { CheckDestroy: testAccCheckVirtualServiceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVirtualServiceConfig_virtualRouter(meshName, vrName1, vrName2, vsName, "aws_appmesh_virtual_router.foo"), + Config: testAccVirtualServiceConfig_virtualRouter(meshName, vrName1, vrName2, vsName, "aws_appmesh_virtual_router.test1"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), resource.TestCheckResourceAttr(resourceName, "name", vsName), @@ -103,7 +102,7 @@ func testAccVirtualService_virtualRouter(t *testing.T) { acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "appmesh", fmt.Sprintf("mesh/%s/virtualService/%s", meshName, vsName))), }, { - Config: testAccVirtualServiceConfig_virtualRouter(meshName, vrName1, vrName2, vsName, "aws_appmesh_virtual_router.bar"), + Config: testAccVirtualServiceConfig_virtualRouter(meshName, vrName1, vrName2, vsName, "aws_appmesh_virtual_router.test2"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), resource.TestCheckResourceAttr(resourceName, "name", vsName), @@ -135,35 +134,28 @@ func testAccVirtualService_tags(t *testing.T) { CheckDestroy: testAccCheckVirtualServiceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVirtualServiceConfig_tags(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.foo", "foo", "bar", "good", "bad"), + Config: testAccVirtualServiceConfig_tags1(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.test1", "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), - 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: testAccVirtualServiceConfig_tags(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.foo", "foo2", "bar", "good", "bad2"), + Config: testAccVirtualServiceConfig_tags2(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.test1", "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), - 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: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.foo"), + Config: testAccVirtualServiceConfig_tags1(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.test1", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { @@ -192,7 +184,7 @@ func testAccVirtualService_disappears(t *testing.T) { CheckDestroy: testAccCheckVirtualServiceDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.foo"), + Config: testAccVirtualServiceConfig_virtualNode(meshName, vnName1, vnName2, vsName, "aws_appmesh_virtual_node.test1"), Check: resource.ComposeTestCheckFunc( testAccCheckVirtualServiceExists(ctx, resourceName, &vs), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfappmesh.ResourceVirtualService(), resourceName), @@ -212,44 +204,42 @@ func testAccCheckVirtualServiceDestroy(ctx context.Context) resource.TestCheckFu continue } - _, err := conn.DescribeVirtualServiceWithContext(ctx, &appmesh.DescribeVirtualServiceInput{ - MeshName: aws.String(rs.Primary.Attributes["mesh_name"]), - VirtualServiceName: aws.String(rs.Primary.Attributes["name"]), - }) - if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + _, err := tfappmesh.FindVirtualServiceByThreePartKey(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 Service %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckVirtualServiceExists(ctx context.Context, name string, v *appmesh.VirtualServiceData) resource.TestCheckFunc { +func testAccCheckVirtualServiceExists(ctx context.Context, n string, v *appmesh.VirtualServiceData) 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 Service ID is set") } - resp, err := conn.DescribeVirtualServiceWithContext(ctx, &appmesh.DescribeVirtualServiceInput{ - MeshName: aws.String(rs.Primary.Attributes["mesh_name"]), - VirtualServiceName: aws.String(rs.Primary.Attributes["name"]), - }) + output, err := tfappmesh.FindVirtualServiceByThreePartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["name"]) + if err != nil { return err } - *v = *resp.VirtualService + *v = *output return nil } @@ -261,14 +251,14 @@ resource "aws_appmesh_mesh" "test" { name = %[1]q } -resource "aws_appmesh_virtual_node" "foo" { +resource "aws_appmesh_virtual_node" "test1" { name = %[2]q mesh_name = aws_appmesh_mesh.test.id spec {} } -resource "aws_appmesh_virtual_node" "bar" { +resource "aws_appmesh_virtual_node" "test2" { name = %[3]q mesh_name = aws_appmesh_mesh.test.id @@ -296,7 +286,7 @@ resource "aws_appmesh_mesh" "test" { name = %[1]q } -resource "aws_appmesh_virtual_router" "foo" { +resource "aws_appmesh_virtual_router" "test1" { name = %[2]q mesh_name = aws_appmesh_mesh.test.id @@ -310,7 +300,7 @@ resource "aws_appmesh_virtual_router" "foo" { } } -resource "aws_appmesh_virtual_router" "bar" { +resource "aws_appmesh_virtual_router" "test2" { name = %[3]q mesh_name = aws_appmesh_mesh.test.id @@ -339,20 +329,59 @@ resource "aws_appmesh_virtual_service" "test" { `, meshName, vrName1, vrName2, vsName, rName) } -func testAccVirtualServiceConfig_tags(meshName, vnName1, vnName2, vsName, rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { +func testAccVirtualServiceConfig_tags1(meshName, vnName1, vnName2, vsName, rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_node" "test1" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} +} + +resource "aws_appmesh_virtual_node" "test2" { + name = %[3]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} +} + +resource "aws_appmesh_virtual_service" "test" { + name = %[4]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_node { + virtual_node_name = %[5]s.name + } + } + } + + tags = { + %[6]s = %[7]q + } +} +`, meshName, vnName1, vnName2, vsName, rName, tagKey1, tagValue1) +} + +func testAccVirtualServiceConfig_tags2(meshName, vnName1, vnName2, vsName, rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q } -resource "aws_appmesh_virtual_node" "foo" { +resource "aws_appmesh_virtual_node" "test1" { name = %[2]q mesh_name = aws_appmesh_mesh.test.id spec {} } -resource "aws_appmesh_virtual_node" "bar" { +resource "aws_appmesh_virtual_node" "test2" { name = %[3]q mesh_name = aws_appmesh_mesh.test.id From 3cd54092ea3d3157d0c3683be7ddb577dd4b7777 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 14:31:06 -0400 Subject: [PATCH 14/25] d/aws_appmesh_virtual_service: Tidy up. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^VirtualService$$' 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/^VirtualService$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/VirtualService === RUN TestAccAppMesh_serial/VirtualService/disappears === RUN TestAccAppMesh_serial/VirtualService/virtualNode === RUN TestAccAppMesh_serial/VirtualService/virtualRouter === RUN TestAccAppMesh_serial/VirtualService/tags === RUN TestAccAppMesh_serial/VirtualService/dataSourceVirtualNode === RUN TestAccAppMesh_serial/VirtualService/dataSourceVirtualRouter --- PASS: TestAccAppMesh_serial (147.73s) --- PASS: TestAccAppMesh_serial/VirtualService (147.73s) --- PASS: TestAccAppMesh_serial/VirtualService/disappears (15.75s) --- PASS: TestAccAppMesh_serial/VirtualService/virtualNode (29.07s) --- PASS: TestAccAppMesh_serial/VirtualService/virtualRouter (25.88s) --- PASS: TestAccAppMesh_serial/VirtualService/tags (42.00s) --- PASS: TestAccAppMesh_serial/VirtualService/dataSourceVirtualNode (17.03s) --- PASS: TestAccAppMesh_serial/VirtualService/dataSourceVirtualRouter (18.00s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 153.175s --- internal/service/appmesh/mesh.go | 3 +- internal/service/appmesh/mesh_data_source.go | 3 +- internal/service/appmesh/virtual_service.go | 3 +- .../appmesh/virtual_service_data_source.go | 48 ++++++------------- .../virtual_service_data_source_test.go | 17 ++++--- 5 files changed, 28 insertions(+), 46 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 2677db60f16..4efa08b82a7 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -146,8 +146,7 @@ func resourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interfac d.Set("mesh_owner", mesh.Metadata.MeshOwner) d.Set("name", mesh.MeshName) d.Set("resource_owner", mesh.Metadata.ResourceOwner) - err = d.Set("spec", flattenMeshSpec(mesh.Spec)) - if err != nil { + if err := d.Set("spec", flattenMeshSpec(mesh.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } diff --git a/internal/service/appmesh/mesh_data_source.go b/internal/service/appmesh/mesh_data_source.go index 5353676a334..c72821f9e39 100644 --- a/internal/service/appmesh/mesh_data_source.go +++ b/internal/service/appmesh/mesh_data_source.go @@ -88,8 +88,7 @@ func dataSourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interf d.Set("last_updated_date", mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) d.Set("mesh_owner", mesh.Metadata.MeshOwner) d.Set("resource_owner", mesh.Metadata.ResourceOwner) - err = d.Set("spec", flattenMeshSpec(mesh.Spec)) - if err != nil { + if err := d.Set("spec", flattenMeshSpec(mesh.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } diff --git a/internal/service/appmesh/virtual_service.go b/internal/service/appmesh/virtual_service.go index 59a48c5c942..068048f727a 100644 --- a/internal/service/appmesh/virtual_service.go +++ b/internal/service/appmesh/virtual_service.go @@ -189,8 +189,7 @@ func resourceVirtualServiceRead(ctx context.Context, d *schema.ResourceData, met d.Set("mesh_owner", vs.Metadata.MeshOwner) d.Set("name", vs.VirtualServiceName) d.Set("resource_owner", vs.Metadata.ResourceOwner) - err = d.Set("spec", flattenVirtualServiceSpec(vs.Spec)) - if err != nil { + if err := d.Set("spec", flattenVirtualServiceSpec(vs.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } diff --git a/internal/service/appmesh/virtual_service_data_source.go b/internal/service/appmesh/virtual_service_data_source.go index 1a36b3f38ea..0f88abba7ea 100644 --- a/internal/service/appmesh/virtual_service_data_source.go +++ b/internal/service/appmesh/virtual_service_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_service") @@ -23,38 +23,31 @@ func DataSourceVirtualService() *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, @@ -77,7 +70,6 @@ func DataSourceVirtualService() *schema.Resource { }, }, }, - "virtual_router": { Type: schema.TypeList, Computed: true, @@ -96,8 +88,7 @@ func DataSourceVirtualService() *schema.Resource { }, }, }, - - "tags": tftags.TagsSchema(), + names.AttrTags: tftags.TagsSchema(), }, } } @@ -107,34 +98,23 @@ func dataSourceVirtualServiceRead(ctx context.Context, d *schema.ResourceData, m conn := meta.(*conns.AWSClient).AppMeshConn() ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeVirtualServiceInput{ - MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualServiceName: aws.String(d.Get("name").(string)), - } - - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } + virtualServiceName := d.Get("name").(string) + vs, err := FindVirtualServiceByThreePartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), virtualServiceName) - resp, err := conn.DescribeVirtualServiceWithContext(ctx, req) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Service: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Service (%s): %s", virtualServiceName, err) } - arn := aws.StringValue(resp.VirtualService.Metadata.Arn) - - d.SetId(aws.StringValue(resp.VirtualService.VirtualServiceName)) - - d.Set("name", resp.VirtualService.VirtualServiceName) - d.Set("mesh_name", resp.VirtualService.MeshName) - d.Set("mesh_owner", resp.VirtualService.Metadata.MeshOwner) + d.SetId(aws.StringValue(vs.VirtualServiceName)) + arn := aws.StringValue(vs.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.VirtualService.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.VirtualService.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("resource_owner", resp.VirtualService.Metadata.ResourceOwner) - - err = d.Set("spec", flattenVirtualServiceSpec(resp.VirtualService.Spec)) - if err != nil { + d.Set("created_date", vs.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", vs.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", vs.MeshName) + d.Set("mesh_owner", vs.Metadata.MeshOwner) + d.Set("name", vs.VirtualServiceName) + d.Set("resource_owner", vs.Metadata.ResourceOwner) + if err := d.Set("spec", flattenVirtualServiceSpec(vs.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } diff --git a/internal/service/appmesh/virtual_service_data_source_test.go b/internal/service/appmesh/virtual_service_data_source_test.go index 4061caaaf00..a31a268acd1 100644 --- a/internal/service/appmesh/virtual_service_data_source_test.go +++ b/internal/service/appmesh/virtual_service_data_source_test.go @@ -21,7 +21,6 @@ func testAccVirtualServiceDataSource_virtualNode(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckVirtualServiceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccVirtualServiceDataSourceConfig_virtualNode(rName, vsName), @@ -33,8 +32,12 @@ func testAccVirtualServiceDataSource_virtualNode(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.provider.#", dataSourceName, "spec.0.provider.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_node.#", dataSourceName, "spec.0.provider.0.virtual_node.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_node.0.virtual_node_name", dataSourceName, "spec.0.provider.0.virtual_node.0.virtual_node_name"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_router.#", dataSourceName, "spec.0.provider.0.virtual_router.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, @@ -52,7 +55,6 @@ func testAccVirtualServiceDataSource_virtualRouter(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckVirtualServiceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccVirtualServiceDataSourceConfig_virtualRouter(rName, vsName), @@ -64,8 +66,12 @@ func testAccVirtualServiceDataSource_virtualRouter(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.provider.#", dataSourceName, "spec.0.provider.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_node.#", dataSourceName, "spec.0.provider.0.virtual_node.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_router.#", dataSourceName, "spec.0.provider.0.virtual_router.#"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.provider.0.virtual_router.0.virtual_router_name", dataSourceName, "spec.0.provider.0.virtual_router.0.virtual_router_name"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, @@ -98,8 +104,7 @@ resource "aws_appmesh_virtual_service" "test" { } tags = { - foo = "bar" - good = "bad" + Name = %[1]q } } From d429db865b9df6c523ad85d44ae7e6832b340838 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 16:52:21 -0400 Subject: [PATCH 15/25] r/aws_appmesh_route: Alphabetize attributes. --- internal/service/appmesh/route.go | 640 +++++++++++++----------------- 1 file changed, 286 insertions(+), 354 deletions(-) diff --git a/internal/service/appmesh/route.go b/internal/service/appmesh/route.go index 03647fdb3bc..a6a53427c5a 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -20,34 +20,280 @@ 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_route") func ResourceRoute() *schema.Resource { + // httpRouteSchema returns the schema for `http_route` and `http2_route` attributes. + httpRouteSchema := func() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_node": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "weight": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 100), + }, + }, + }, + }, + }, + }, + }, + "match": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "header": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "invert": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "match": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "range": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "end": { + Type: schema.TypeInt, + Required: true, + }, + "start": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "suffix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 50), + }, + }, + }, + }, + "method": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(appmesh.HttpMethod_Values(), false), + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "prefix": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), + }, + "scheme": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice(appmesh.HttpScheme_Values(), false), + }, + }, + }, + }, + "retry_policy": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "http_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "max_retries": { + Type: schema.TypeInt, + Required: true, + }, + "per_retry_timeout": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "tcp_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + }, + "timeout": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idle": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + "per_request": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, + }, + }, + }, + }, + }, + }, + }, + }, + }, + } + } + return &schema.Resource{ CreateWithoutTimeout: resourceRouteCreate, ReadWithoutTimeout: resourceRouteRead, UpdateWithoutTimeout: resourceRouteUpdate, DeleteWithoutTimeout: resourceRouteDelete, + Importer: &schema.ResourceImporter{ StateContext: resourceRouteImport, }, 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, @@ -55,13 +301,16 @@ func ResourceRoute() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidAccountID, }, - - "virtual_router_name": { + "name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 255), }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, "spec": { Type: schema.TypeList, @@ -92,30 +341,27 @@ func ResourceRoute() *schema.Resource { MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, "virtual_node": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "weight": { Type: schema.TypeInt, Required: true, ValidateFunc: validation.IntBetween(0, 100), }, - - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, }, }, }, }, }, - "match": { Type: schema.TypeList, Optional: true, @@ -135,7 +381,6 @@ func ResourceRoute() *schema.Resource { Optional: true, Default: false, }, - "match": { Type: schema.TypeList, Optional: true, @@ -148,13 +393,11 @@ func ResourceRoute() *schema.Resource { Optional: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "prefix": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "range": { Type: schema.TypeList, Optional: true, @@ -166,7 +409,6 @@ func ResourceRoute() *schema.Resource { Type: schema.TypeInt, Required: true, }, - "start": { Type: schema.TypeInt, Required: true, @@ -174,13 +416,11 @@ func ResourceRoute() *schema.Resource { }, }, }, - "regex": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "suffix": { Type: schema.TypeString, Optional: true, @@ -189,7 +429,6 @@ func ResourceRoute() *schema.Resource { }, }, }, - "name": { Type: schema.TypeString, Required: true, @@ -198,33 +437,28 @@ func ResourceRoute() *schema.Resource { }, }, }, - "method_name": { Type: schema.TypeString, Optional: true, RequiredWith: []string{"spec.0.grpc_route.0.match.0.service_name"}, }, - + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, "prefix": { Type: schema.TypeString, Optional: true, ValidateFunc: validation.StringLenBetween(0, 50), }, - "service_name": { Type: schema.TypeString, Optional: true, }, - - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, }, }, - "retry_policy": { Type: schema.TypeList, Optional: true, @@ -237,22 +471,17 @@ func ResourceRoute() *schema.Resource { Optional: true, MinItems: 0, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, - "http_retry_events": { Type: schema.TypeSet, Optional: true, MinItems: 0, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, - "max_retries": { Type: schema.TypeInt, Required: true, }, - "per_retry_timeout": { Type: schema.TypeList, Required: true, @@ -265,7 +494,6 @@ func ResourceRoute() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), }, - "value": { Type: schema.TypeInt, Required: true, @@ -273,18 +501,15 @@ func ResourceRoute() *schema.Resource { }, }, }, - "tcp_retry_events": { Type: schema.TypeSet, Optional: true, MinItems: 0, Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, }, }, }, }, - "timeout": { Type: schema.TypeList, Optional: true, @@ -304,7 +529,6 @@ func ResourceRoute() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), }, - "value": { Type: schema.TypeInt, Required: true, @@ -312,7 +536,6 @@ func ResourceRoute() *schema.Resource { }, }, }, - "per_request": { Type: schema.TypeList, Optional: true, @@ -325,7 +548,6 @@ func ResourceRoute() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), }, - "value": { Type: schema.TypeInt, Required: true, @@ -339,25 +561,21 @@ func ResourceRoute() *schema.Resource { }, }, }, - - "http2_route": func() *schema.Schema { - schema := RouteHTTPRouteSchema() - schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http_route", "spec.0.tcp_route"} - return schema - }(), - "http_route": func() *schema.Schema { - schema := RouteHTTPRouteSchema() + schema := httpRouteSchema() schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.tcp_route"} return schema }(), - + "http2_route": func() *schema.Schema { + schema := httpRouteSchema() + schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http_route", "spec.0.tcp_route"} + return schema + }(), "priority": { Type: schema.TypeInt, Optional: true, ValidateFunc: validation.IntBetween(0, 1000), }, - "tcp_route": { Type: schema.TypeList, Optional: true, @@ -380,30 +598,27 @@ func ResourceRoute() *schema.Resource { MaxItems: 10, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, "virtual_node": { Type: schema.TypeString, Required: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "weight": { Type: schema.TypeInt, Required: true, ValidateFunc: validation.IntBetween(0, 100), }, - - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, }, }, }, }, }, }, - "match": { Type: schema.TypeList, Optional: true, @@ -419,7 +634,6 @@ func ResourceRoute() *schema.Resource { }, }, }, - "timeout": { Type: schema.TypeList, Optional: true, @@ -439,7 +653,6 @@ func ResourceRoute() *schema.Resource { Required: true, ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), }, - "value": { Type: schema.TypeInt, Required: true, @@ -456,301 +669,20 @@ func ResourceRoute() *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, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "virtual_router_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, - - "tags": tftags.TagsSchema(), - - "tags_all": tftags.TagsSchemaComputed(), }, CustomizeDiff: verify.SetTagsDiff, } } -// RouteHTTPRouteSchema returns the schema for `http2_route` and `http_route` attributes. -func RouteHTTPRouteSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "weighted_target": { - Type: schema.TypeSet, - Required: true, - MinItems: 1, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - - "weight": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(0, 100), - }, - - "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{ - "header": { - Type: schema.TypeSet, - Optional: true, - MinItems: 0, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "invert": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - - "match": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "exact": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - - "prefix": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - - "range": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "end": { - Type: schema.TypeInt, - Required: true, - }, - - "start": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - - "regex": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - - "suffix": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, - }, - }, - - "name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 50), - }, - }, - }, - }, - - "method": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(appmesh.HttpMethod_Values(), false), - }, - - "prefix": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringMatch(regexp.MustCompile(`^/`), "must start with /"), - }, - - "scheme": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(appmesh.HttpScheme_Values(), false), - }, - - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - }, - }, - }, - - "retry_policy": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "http_retry_events": { - Type: schema.TypeSet, - Optional: true, - MinItems: 0, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - - "max_retries": { - Type: schema.TypeInt, - Required: true, - }, - - "per_retry_timeout": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - - "tcp_retry_events": { - Type: schema.TypeSet, - Optional: true, - MinItems: 0, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - }, - }, - }, - - "timeout": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idle": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - - "per_request": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - } -} - func resourceRouteCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).AppMeshConn() From b563c669973f7bc5634d19c565cadb283318d907 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 16:55:05 -0400 Subject: [PATCH 16/25] r/aws_appmesh_route: Tidy up resource Create, Update and Delete. --- internal/service/appmesh/route.go | 36 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/internal/service/appmesh/route.go b/internal/service/appmesh/route.go index a6a53427c5a..dbdf95094ae 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -689,24 +689,26 @@ func resourceRouteCreate(ctx context.Context, d *schema.ResourceData, meta inter defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) - req := &appmesh.CreateRouteInput{ + name := d.Get("name").(string) + input := &appmesh.CreateRouteInput{ MeshName: aws.String(d.Get("mesh_name").(string)), - RouteName: aws.String(d.Get("name").(string)), - VirtualRouterName: aws.String(d.Get("virtual_router_name").(string)), + RouteName: aws.String(name), Spec: expandRouteSpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), + VirtualRouterName: aws.String(d.Get("virtual_router_name").(string)), } + 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 route: %#v", req) - resp, err := conn.CreateRouteWithContext(ctx, req) + output, err := conn.CreateRouteWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh route: %s", err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Route (%s): %s", name, err) } - d.SetId(aws.StringValue(resp.Route.Metadata.Uid)) + d.SetId(aws.StringValue(output.Route.Metadata.Uid)) return append(diags, resourceRouteRead(ctx, d, meta)...) } @@ -811,30 +813,30 @@ func resourceRouteUpdate(ctx context.Context, d *schema.ResourceData, meta inter conn := meta.(*conns.AWSClient).AppMeshConn() if d.HasChange("spec") { - _, v := d.GetChange("spec") - req := &appmesh.UpdateRouteInput{ + input := &appmesh.UpdateRouteInput{ MeshName: aws.String(d.Get("mesh_name").(string)), RouteName: aws.String(d.Get("name").(string)), + Spec: expandRouteSpec(d.Get("spec").([]interface{})), VirtualRouterName: aws.String(d.Get("virtual_router_name").(string)), - Spec: expandRouteSpec(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 route: %#v", req) - _, err := conn.UpdateRouteWithContext(ctx, req) + _, err := conn.UpdateRouteWithContext(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh route: %s", err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh 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 route (%s) tags: %s", arn, err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Route (%s) tags: %s", arn, err) } } From 22537ed7712a47dea9f402f33435d126c8870d28 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 17:05:17 -0400 Subject: [PATCH 17/25] r/aws_appmesh_route: Tidy up resource Read. --- internal/service/appmesh/route.go | 139 +++++++++++++++--------------- 1 file changed, 68 insertions(+), 71 deletions(-) diff --git a/internal/service/appmesh/route.go b/internal/service/appmesh/route.go index dbdf95094ae..f3f264e9090 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -719,79 +719,38 @@ func resourceRouteRead(ctx context.Context, d *schema.ResourceData, meta interfa defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeRouteInput{ - MeshName: aws.String(d.Get("mesh_name").(string)), - RouteName: aws.String(d.Get("name").(string)), - VirtualRouterName: aws.String(d.Get("virtual_router_name").(string)), - } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } - - var resp *appmesh.DescribeRouteOutput - - err := resource.RetryContext(ctx, propagationTimeout, func() *resource.RetryError { - var err error - - resp, err = conn.DescribeRouteWithContext(ctx, req) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } + outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, propagationTimeout, func() (interface{}, error) { + return FindRouteByFourPartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("virtual_router_name").(string), d.Get("name").(string)) + }, d.IsNewResource()) - return nil - }) - - if tfresource.TimedOut(err) { - resp, err = conn.DescribeRouteWithContext(ctx, req) - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] App Mesh Route (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Route: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Route (%s): %s", d.Id(), err) } - if resp == nil || resp.Route == nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Route: empty response") - } - - if aws.StringValue(resp.Route.Status.Status) == appmesh.RouteStatusCodeDeleted { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Route: %s after creation", aws.StringValue(resp.Route.Status.Status)) - } - - log.Printf("[WARN] App Mesh Route (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } - - arn := aws.StringValue(resp.Route.Metadata.Arn) - d.Set("name", resp.Route.RouteName) - d.Set("mesh_name", resp.Route.MeshName) - d.Set("mesh_owner", resp.Route.Metadata.MeshOwner) - d.Set("virtual_router_name", resp.Route.VirtualRouterName) + route := outputRaw.(*appmesh.RouteData) + arn := aws.StringValue(route.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.Route.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.Route.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("resource_owner", resp.Route.Metadata.ResourceOwner) - err = d.Set("spec", flattenRouteSpec(resp.Route.Spec)) - if err != nil { + d.Set("created_date", route.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", route.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", route.MeshName) + d.Set("mesh_owner", route.Metadata.MeshOwner) + d.Set("name", route.RouteName) + d.Set("resource_owner", route.Metadata.ResourceOwner) + if err := d.Set("spec", flattenRouteSpec(route.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } + d.Set("virtual_router_name", route.VirtualRouterName) tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh route (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Route (%s): %s", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -877,31 +836,69 @@ func resourceRouteImport(ctx context.Context, d *schema.ResourceData, meta inter return []*schema.ResourceData{}, fmt.Errorf("wrong format of import ID (%s), use: 'mesh-name/virtual-router-name/route-name'", d.Id()) } - mesh := parts[0] - vrName := parts[1] + meshName := parts[0] + virtualRouterName := parts[1] name := parts[2] - log.Printf("[DEBUG] Importing App Mesh route %s from mesh %s/virtual router %s ", name, mesh, vrName) conn := meta.(*conns.AWSClient).AppMeshConn() - req := &appmesh.DescribeRouteInput{ - MeshName: aws.String(mesh), + route, err := FindRouteByFourPartKey(ctx, conn, meshName, "", virtualRouterName, name) + + if err != nil { + return nil, err + } + + d.SetId(aws.StringValue(route.Metadata.Uid)) + d.Set("mesh_name", route.MeshName) + d.Set("name", route.RouteName) + d.Set("virtual_router_name", route.VirtualRouterName) + + return []*schema.ResourceData{d}, nil +} + +func FindRouteByFourPartKey(ctx context.Context, conn *appmesh.AppMesh, meshName, meshOwner, virtualRouterName, name string) (*appmesh.RouteData, error) { + input := &appmesh.DescribeRouteInput{ + MeshName: aws.String(meshName), RouteName: aws.String(name), - VirtualRouterName: aws.String(vrName), + VirtualRouterName: aws.String(virtualRouterName), } - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) + if meshOwner != "" { + input.MeshOwner = aws.String(meshOwner) } - resp, err := conn.DescribeRouteWithContext(ctx, req) + output, err := findRoute(ctx, conn, input) + if err != nil { return nil, err } - d.SetId(aws.StringValue(resp.Route.Metadata.Uid)) - d.Set("name", resp.Route.RouteName) - d.Set("mesh_name", resp.Route.MeshName) - d.Set("virtual_router_name", resp.Route.VirtualRouterName) + if status := aws.StringValue(output.Status.Status); status == appmesh.RouteStatusCodeDeleted { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } - return []*schema.ResourceData{d}, nil + return output, nil +} + +func findRoute(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.DescribeRouteInput) (*appmesh.RouteData, error) { + output, err := conn.DescribeRouteWithContext(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.Route == nil || output.Route.Metadata == nil || output.Route.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.Route, nil } From d6e251bc0bcfe7a96279e91d34e0bfb794c5e3df Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 22 Mar 2023 17:26:10 -0400 Subject: [PATCH 18/25] r/aws_appmesh_route: Tidy up acceptance tests. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Route$$' 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$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Route === RUN TestAccAppMesh_serial/Route/tcpRouteTimeout === RUN TestAccAppMesh_serial/Route/grpcRoute === RUN TestAccAppMesh_serial/Route/grpcRouteWithPortMatch === RUN TestAccAppMesh_serial/Route/httpHeader === RUN TestAccAppMesh_serial/Route/httpRetryPolicy === RUN TestAccAppMesh_serial/Route/httpRouteTimeout === RUN TestAccAppMesh_serial/Route/tcpRouteWithPortMatch === RUN TestAccAppMesh_serial/Route/disappears === RUN TestAccAppMesh_serial/Route/grpcRouteEmptyMatch === RUN TestAccAppMesh_serial/Route/httpRouteWithPortMatch === RUN TestAccAppMesh_serial/Route/routePriority === RUN TestAccAppMesh_serial/Route/tags === RUN TestAccAppMesh_serial/Route/grpcRouteTimeout === RUN TestAccAppMesh_serial/Route/http2Route === RUN TestAccAppMesh_serial/Route/http2RouteWithPortMatch === RUN TestAccAppMesh_serial/Route/httpRoute === RUN TestAccAppMesh_serial/Route/tcpRoute === RUN TestAccAppMesh_serial/Route/http2RouteTimeout --- PASS: TestAccAppMesh_serial (577.95s) --- PASS: TestAccAppMesh_serial/Route (577.95s) --- PASS: TestAccAppMesh_serial/Route/tcpRouteTimeout (28.33s) --- PASS: TestAccAppMesh_serial/Route/grpcRoute (49.53s) --- PASS: TestAccAppMesh_serial/Route/grpcRouteWithPortMatch (49.50s) --- PASS: TestAccAppMesh_serial/Route/httpHeader (27.18s) --- PASS: TestAccAppMesh_serial/Route/httpRetryPolicy (38.14s) --- PASS: TestAccAppMesh_serial/Route/httpRouteTimeout (27.14s) --- PASS: TestAccAppMesh_serial/Route/tcpRouteWithPortMatch (38.03s) --- PASS: TestAccAppMesh_serial/Route/disappears (13.48s) --- PASS: TestAccAppMesh_serial/Route/grpcRouteEmptyMatch (16.17s) --- PASS: TestAccAppMesh_serial/Route/httpRouteWithPortMatch (37.83s) --- PASS: TestAccAppMesh_serial/Route/routePriority (27.04s) --- PASS: TestAccAppMesh_serial/Route/tags (37.77s) --- PASS: TestAccAppMesh_serial/Route/grpcRouteTimeout (27.63s) --- PASS: TestAccAppMesh_serial/Route/http2Route (28.18s) --- PASS: TestAccAppMesh_serial/Route/http2RouteWithPortMatch (27.32s) --- PASS: TestAccAppMesh_serial/Route/httpRoute (38.09s) --- PASS: TestAccAppMesh_serial/Route/tcpRoute (38.84s) --- PASS: TestAccAppMesh_serial/Route/http2RouteTimeout (27.75s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 583.190s --- internal/service/appmesh/route_test.go | 266 ++++++++++++++----------- 1 file changed, 145 insertions(+), 121 deletions(-) diff --git a/internal/service/appmesh/route_test.go b/internal/service/appmesh/route_test.go index 0e06b927483..db806a81918 100644 --- a/internal/service/appmesh/route_test.go +++ b/internal/service/appmesh/route_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 testAccRoute_grpcRoute(t *testing.T) { @@ -1570,36 +1569,36 @@ func testAccRoute_tags(t *testing.T) { CheckDestroy: testAccCheckRouteDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccRouteConfig_tags(meshName, vrName, vn1Name, vn2Name, rName, "foo", "bar", "good", "bad"), + Config: testAccRouteConfig_tags1(meshName, vrName, vn1Name, vn2Name, rName, "key1", "value1"), Check: resource.ComposeTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), - 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: testAccRouteConfig_tags(meshName, vrName, vn1Name, vn2Name, rName, "foo2", "bar", "good", "bad2"), + ResourceName: resourceName, + ImportStateIdFunc: testAccRouteImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccRouteConfig_tags2(meshName, vrName, vn1Name, vn2Name, rName, "key1", "value1updated", "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr(resourceName, "tags.foo2", "bar"), - resource.TestCheckResourceAttr(resourceName, "tags.good", "bad2"), + resource.TestCheckResourceAttr(resourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, { - Config: testAccRouteConfig_http(meshName, vrName, vn1Name, vn2Name, rName), + Config: testAccRouteConfig_tags1(meshName, vrName, vn1Name, vn2Name, rName, "key2", "value2"), Check: resource.ComposeTestCheckFunc( testAccCheckRouteExists(ctx, resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.key2", "value2"), ), }, - { - ResourceName: resourceName, - ImportStateIdFunc: testAccRouteImportStateIdFunc(resourceName), - ImportState: true, - ImportStateVerify: true, - }, }, }) } @@ -1969,52 +1968,48 @@ func testAccCheckRouteDestroy(ctx context.Context) resource.TestCheckFunc { continue } - _, err := conn.DescribeRouteWithContext(ctx, &appmesh.DescribeRouteInput{ - MeshName: aws.String(rs.Primary.Attributes["mesh_name"]), - RouteName: aws.String(rs.Primary.Attributes["name"]), - VirtualRouterName: aws.String(rs.Primary.Attributes["virtual_router_name"]), - }) - if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + _, err := tfappmesh.FindRouteByFourPartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["virtual_router_name"], rs.Primary.Attributes["name"]) + + if tfresource.NotFound(err) { continue } + if err != nil { return err } - return fmt.Errorf("still exist.") + + return fmt.Errorf("App Mesh Route %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckRouteExists(ctx context.Context, name string, v *appmesh.RouteData) resource.TestCheckFunc { +func testAccCheckRouteExists(ctx context.Context, n string, v *appmesh.RouteData) 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 Route ID is set") } - resp, err := conn.DescribeRouteWithContext(ctx, &appmesh.DescribeRouteInput{ - MeshName: aws.String(rs.Primary.Attributes["mesh_name"]), - RouteName: aws.String(rs.Primary.Attributes["name"]), - VirtualRouterName: aws.String(rs.Primary.Attributes["virtual_router_name"]), - }) + output, err := tfappmesh.FindRouteByFourPartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["virtual_router_name"], rs.Primary.Attributes["name"]) + if err != nil { return err } - *v = *resp.Route + *v = *output return nil } } -func testAccRouteConfigBase(meshName, vrName, vrProtocol, vn1Name, vn2Name string) string { +func testAccRouteConfig_base(meshName, vrName, vrProtocol, vn1Name, vn2Name string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q @@ -2034,7 +2029,7 @@ resource "aws_appmesh_virtual_router" "test" { } } -resource "aws_appmesh_virtual_node" "foo" { +resource "aws_appmesh_virtual_node" "test1" { name = %[4]q mesh_name = aws_appmesh_mesh.test.id @@ -2048,13 +2043,13 @@ resource "aws_appmesh_virtual_node" "foo" { service_discovery { dns { - hostname = "foo.simpleapp.local" + hostname = "test1.simpleapp.local" } } } } -resource "aws_appmesh_virtual_node" "bar" { +resource "aws_appmesh_virtual_node" "test2" { name = %[5]q mesh_name = aws_appmesh_mesh.test.id @@ -2068,7 +2063,7 @@ resource "aws_appmesh_virtual_node" "bar" { service_discovery { dns { - hostname = "bar.simpleapp.local" + hostname = "test2.simpleapp.local" } } } @@ -2077,7 +2072,7 @@ resource "aws_appmesh_virtual_node" "bar" { } func testAccRouteConfig_grpcRoute(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2111,7 +2106,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2122,7 +2117,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2176,12 +2171,12 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 90 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 10 } } @@ -2192,7 +2187,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2227,7 +2222,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 port = 8080 } @@ -2239,7 +2234,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2293,13 +2288,13 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 90 port = 8080 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 10 port = 8080 } @@ -2311,7 +2306,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteUpdatedWithZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2365,12 +2360,12 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 99 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 0 } } @@ -2381,7 +2376,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteWithTimeout(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2397,7 +2392,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2415,7 +2410,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteWithTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2431,7 +2426,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2454,7 +2449,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteWithEmptyMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2466,7 +2461,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2477,7 +2472,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_grpcRouteWithMaxRetriesZero(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "grpc", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -2511,7 +2506,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2522,7 +2517,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http2Route(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2555,7 +2550,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2566,7 +2561,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http2RouteUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2617,7 +2612,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2628,7 +2623,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http2RouteWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2661,7 +2656,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 port = 8080 } @@ -2673,7 +2668,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http2RouteWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2724,7 +2719,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 port = 8080 } @@ -2736,7 +2731,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http2RouteWithTimeout(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2756,7 +2751,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2774,7 +2769,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http2RouteWithTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http2", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2794,7 +2789,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2817,7 +2812,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_http(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2831,7 +2826,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2842,7 +2837,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2856,12 +2851,12 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 90 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 10 } } @@ -2872,7 +2867,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2887,7 +2882,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 port = 8080 } @@ -2899,7 +2894,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2914,13 +2909,13 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 90 port = 8080 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 10 port = 8080 } @@ -2932,7 +2927,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2946,12 +2941,12 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 99 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 0 } } @@ -2962,7 +2957,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpTimeout(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -2976,7 +2971,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -2994,7 +2989,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3008,7 +3003,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3031,7 +3026,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcp(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3041,7 +3036,7 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3052,7 +3047,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcpUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3062,12 +3057,12 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 90 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 10 } } @@ -3078,7 +3073,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcpWithPortMatch(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3088,7 +3083,7 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 port = 8080 } @@ -3103,7 +3098,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcpWithPortMatchUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3113,13 +3108,13 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 90 port = 8080 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 10 port = 8080 } @@ -3134,7 +3129,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcpUpdatedZeroWeight(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3144,12 +3139,12 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 99 } weighted_target { - virtual_node = aws_appmesh_virtual_node.bar.name + virtual_node = aws_appmesh_virtual_node.test2.name weight = 0 } } @@ -3160,7 +3155,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcpTimeout(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3170,7 +3165,7 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3188,7 +3183,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_tcpTimeoutUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteConfig_base(meshName, vrName, "tcp", vn1Name, vn2Name), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -3198,7 +3193,7 @@ resource "aws_appmesh_route" "test" { tcp_route { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3215,8 +3210,37 @@ resource "aws_appmesh_route" "test" { `, rName)) } -func testAccRouteConfig_tags(meshName, vrName, vn1Name, vn2Name, rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` +func testAccRouteConfig_tags1(meshName, vrName, vn1Name, vn2Name, rName, tagKey1, tagValue1 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 = "/" + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test1.name + weight = 100 + } + } + } + } + + tags = { + %[2]s = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccRouteConfig_tags2(meshName, vrName, vn1Name, vn2Name, rName, tagKey1, tagValue1, tagKey2, tagValue2 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 @@ -3230,7 +3254,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3246,7 +3270,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpHeader(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3265,7 +3289,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3276,7 +3300,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpHeaderUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3308,7 +3332,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3319,7 +3343,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_routePriority(meshName, vrName, vn1Name, vn2Name, rName string, priority int) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3333,7 +3357,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3346,7 +3370,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpRetryPolicy(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3373,7 +3397,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3384,7 +3408,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpMaxRetriesZero(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3411,7 +3435,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } @@ -3422,7 +3446,7 @@ resource "aws_appmesh_route" "test" { } func testAccRouteConfig_httpRetryPolicyUpdated(meshName, vrName, vn1Name, vn2Name, rName string) string { - return acctest.ConfigCompose(testAccRouteConfigBase(meshName, vrName, "http", vn1Name, vn2Name), fmt.Sprintf(` + 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 @@ -3454,7 +3478,7 @@ resource "aws_appmesh_route" "test" { action { weighted_target { - virtual_node = aws_appmesh_virtual_node.foo.name + virtual_node = aws_appmesh_virtual_node.test1.name weight = 100 } } From e37ed10ef4cfb7d44218cac09e547ec538bfe57c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 08:43:46 -0400 Subject: [PATCH 19/25] d/aws_appmesh_mesh: Add and use 'dataSourcePropertyFromResourceProperty'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Mesh$$' 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/^Mesh$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Mesh === RUN TestAccAppMesh_serial/Mesh/tags === RUN TestAccAppMesh_serial/Mesh/dataSourceBasic === RUN TestAccAppMesh_serial/Mesh/dataSourceMeshOwner === RUN TestAccAppMesh_serial/Mesh/dataSourceSpecAndTagsSet === RUN TestAccAppMesh_serial/Mesh/basic === RUN TestAccAppMesh_serial/Mesh/disappears === RUN TestAccAppMesh_serial/Mesh/egressFilter --- PASS: TestAccAppMesh_serial (137.21s) --- PASS: TestAccAppMesh_serial/Mesh (137.21s) --- PASS: TestAccAppMesh_serial/Mesh/tags (41.34s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceBasic (13.35s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceMeshOwner (13.61s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceSpecAndTagsSet (13.37s) --- PASS: TestAccAppMesh_serial/Mesh/basic (14.27s) --- PASS: TestAccAppMesh_serial/Mesh/disappears (10.24s) --- PASS: TestAccAppMesh_serial/Mesh/egressFilter (31.04s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 142.992s --- internal/service/appmesh/mesh.go | 109 ++++++++++++++----- internal/service/appmesh/mesh_data_source.go | 21 +--- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 4efa08b82a7..2e5f7086646 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -59,38 +59,42 @@ func ResourceMesh() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "spec": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "egress_filter": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": { - Type: schema.TypeString, - Optional: true, - Default: appmesh.EgressFilterTypeDropAll, - ValidateFunc: validation.StringInSlice(appmesh.EgressFilterType_Values(), false), - }, - }, + "spec": resourceMeshSpecSchema(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + }, + + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceMeshSpecSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + DiffSuppressFunc: verify.SuppressMissingOptionalConfigurationBlock, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "egress_filter": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Optional: true, + Default: appmesh.EgressFilterTypeDropAll, + ValidateFunc: validation.StringInSlice(appmesh.EgressFilterType_Values(), false), }, }, }, }, }, - names.AttrTags: tftags.TagsSchema(), - names.AttrTagsAll: tftags.TagsSchemaComputed(), }, - - CustomizeDiff: verify.SetTagsDiff, } } @@ -263,3 +267,56 @@ func findMesh(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.Describ return output.Mesh, nil } + +// Adapted from https://github.com/hashicorp/terraform-provider-google/google/datasource_helpers.go. Thanks! +// TODO Move to a shared package. + +// dataSourceSchemaFromResourceSchema is a recursive func that +// converts an existing Resource schema to a Datasource schema. +// All schema elements are copied, but certain attributes are ignored or changed: +// - all attributes have Computed = true +// - all attributes have ForceNew, Required = false +// - Validation funcs and attributes (e.g. MaxItems) are not copied +func dataSourceSchemaFromResourceSchema(rs map[string]*schema.Schema) map[string]*schema.Schema { + ds := make(map[string]*schema.Schema, len(rs)) + + for k, v := range rs { + ds[k] = dataSourcePropertyFromResourceProperty(v) + } + + return ds +} + +func dataSourcePropertyFromResourceProperty(rs *schema.Schema) *schema.Schema { + ds := &schema.Schema{ + Computed: true, + ForceNew: false, + Required: false, + Description: rs.Description, + Type: rs.Type, + } + + switch rs.Type { + case schema.TypeSet: + ds.Set = rs.Set + fallthrough + case schema.TypeList: + // List & Set types are generally used for 2 cases: + // - a list/set of simple primitive values (e.g. list of strings) + // - a sub resource + if elem, ok := rs.Elem.(*schema.Resource); ok { + // handle the case where the Element is a sub-resource + ds.Elem = &schema.Resource{ + Schema: dataSourceSchemaFromResourceSchema(elem.Schema), + } + } else { + // handle simple primitive case + ds.Elem = rs.Elem + } + default: + // Elem of all other types are copied as-is + ds.Elem = rs.Elem + } + + return ds +} diff --git a/internal/service/appmesh/mesh_data_source.go b/internal/service/appmesh/mesh_data_source.go index c72821f9e39..c810a48b321 100644 --- a/internal/service/appmesh/mesh_data_source.go +++ b/internal/service/appmesh/mesh_data_source.go @@ -44,26 +44,7 @@ func DataSourceMesh() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "spec": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "egress_filter": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "type": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, + "spec": dataSourcePropertyFromResourceProperty(resourceMeshSpecSchema()), names.AttrTags: tftags.TagsSchemaComputed(), }, } From dfcf92e8d9ebf3cc4472821480f5bef804c658e2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 08:55:34 -0400 Subject: [PATCH 20/25] d/aws_appmesh_virtual_service: Use 'dataSourcePropertyFromResourceProperty'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^VirtualService$$' 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/^VirtualService$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/VirtualService === RUN TestAccAppMesh_serial/VirtualService/disappears === RUN TestAccAppMesh_serial/VirtualService/virtualNode === RUN TestAccAppMesh_serial/VirtualService/virtualRouter === RUN TestAccAppMesh_serial/VirtualService/tags === RUN TestAccAppMesh_serial/VirtualService/dataSourceVirtualNode === RUN TestAccAppMesh_serial/VirtualService/dataSourceVirtualRouter --- PASS: TestAccAppMesh_serial (137.73s) --- PASS: TestAccAppMesh_serial/VirtualService (137.73s) --- PASS: TestAccAppMesh_serial/VirtualService/disappears (14.75s) --- PASS: TestAccAppMesh_serial/VirtualService/virtualNode (28.11s) --- PASS: TestAccAppMesh_serial/VirtualService/virtualRouter (24.70s) --- PASS: TestAccAppMesh_serial/VirtualService/tags (39.02s) --- PASS: TestAccAppMesh_serial/VirtualService/dataSourceVirtualNode (15.60s) --- PASS: TestAccAppMesh_serial/VirtualService/dataSourceVirtualRouter (15.56s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 143.268s --- internal/service/appmesh/virtual_service.go | 96 ++++++++++--------- .../appmesh/virtual_service_data_source.go | 41 +------- 2 files changed, 51 insertions(+), 86 deletions(-) diff --git a/internal/service/appmesh/virtual_service.go b/internal/service/appmesh/virtual_service.go index 068048f727a..5f7991a0ebe 100644 --- a/internal/service/appmesh/virtual_service.go +++ b/internal/service/appmesh/virtual_service.go @@ -70,50 +70,58 @@ func ResourceVirtualService() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "spec": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "provider": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - ConflictsWith: []string{"spec.0.provider.0.virtual_router"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + "spec": resourceVirualServiceSpecSchema(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + }, + + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceVirualServiceSpecSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "provider": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + ConflictsWith: []string{"spec.0.provider.0.virtual_router"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_node_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - "virtual_router": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - ConflictsWith: []string{"spec.0.provider.0.virtual_node"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_router_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + }, + }, + "virtual_router": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + ConflictsWith: []string{"spec.0.provider.0.virtual_node"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "virtual_router_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, }, @@ -122,11 +130,7 @@ func ResourceVirtualService() *schema.Resource { }, }, }, - names.AttrTags: tftags.TagsSchema(), - names.AttrTagsAll: tftags.TagsSchemaComputed(), }, - - CustomizeDiff: verify.SetTagsDiff, } } diff --git a/internal/service/appmesh/virtual_service_data_source.go b/internal/service/appmesh/virtual_service_data_source.go index 0f88abba7ea..a43fe747717 100644 --- a/internal/service/appmesh/virtual_service_data_source.go +++ b/internal/service/appmesh/virtual_service_data_source.go @@ -48,46 +48,7 @@ func DataSourceVirtualService() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "spec": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "provider": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node_name": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - "virtual_router": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_router_name": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, + "spec": dataSourcePropertyFromResourceProperty(resourceVirualServiceSpecSchema()), names.AttrTags: tftags.TagsSchema(), }, } From 705536983ba50a5fcf7566816c539b5a10bf3b6a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 10:44:59 -0400 Subject: [PATCH 21/25] d/aws_appmesh_route: Use 'dataSourcePropertyFromResourceProperty'. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Route$$' 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$ -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Route === RUN TestAccAppMesh_serial/Route/httpRoute === RUN TestAccAppMesh_serial/Route/httpRouteWithPortMatch === RUN TestAccAppMesh_serial/Route/tags === RUN TestAccAppMesh_serial/Route/dataSourceGRPCRoute === RUN TestAccAppMesh_serial/Route/dataSourceTCPRoute === RUN TestAccAppMesh_serial/Route/grpcRouteTimeout === RUN TestAccAppMesh_serial/Route/httpHeader === RUN TestAccAppMesh_serial/Route/tcpRouteWithPortMatch === RUN TestAccAppMesh_serial/Route/httpRetryPolicy === RUN TestAccAppMesh_serial/Route/httpRouteTimeout === RUN TestAccAppMesh_serial/Route/routePriority === RUN TestAccAppMesh_serial/Route/tcpRoute === RUN TestAccAppMesh_serial/Route/dataSourceHTTP2Route === RUN TestAccAppMesh_serial/Route/grpcRoute === RUN TestAccAppMesh_serial/Route/grpcRouteEmptyMatch === RUN TestAccAppMesh_serial/Route/http2Route === RUN TestAccAppMesh_serial/Route/dataSourceHTTPRoute === RUN TestAccAppMesh_serial/Route/http2RouteTimeout === RUN TestAccAppMesh_serial/Route/tcpRouteTimeout === RUN TestAccAppMesh_serial/Route/disappears === RUN TestAccAppMesh_serial/Route/grpcRouteWithPortMatch === RUN TestAccAppMesh_serial/Route/http2RouteWithPortMatch --- PASS: TestAccAppMesh_serial (649.12s) --- PASS: TestAccAppMesh_serial/Route (649.12s) --- PASS: TestAccAppMesh_serial/Route/httpRoute (39.04s) --- PASS: TestAccAppMesh_serial/Route/httpRouteWithPortMatch (38.09s) --- PASS: TestAccAppMesh_serial/Route/tags (38.12s) --- PASS: TestAccAppMesh_serial/Route/dataSourceGRPCRoute (14.93s) --- PASS: TestAccAppMesh_serial/Route/dataSourceTCPRoute (14.79s) --- PASS: TestAccAppMesh_serial/Route/grpcRouteTimeout (27.14s) --- PASS: TestAccAppMesh_serial/Route/httpHeader (27.29s) --- PASS: TestAccAppMesh_serial/Route/tcpRouteWithPortMatch (39.36s) --- PASS: TestAccAppMesh_serial/Route/httpRetryPolicy (39.26s) --- PASS: TestAccAppMesh_serial/Route/httpRouteTimeout (27.52s) --- PASS: TestAccAppMesh_serial/Route/routePriority (27.09s) --- PASS: TestAccAppMesh_serial/Route/tcpRoute (39.31s) --- PASS: TestAccAppMesh_serial/Route/dataSourceHTTP2Route (15.71s) --- PASS: TestAccAppMesh_serial/Route/grpcRoute (51.35s) --- PASS: TestAccAppMesh_serial/Route/grpcRouteEmptyMatch (16.72s) --- PASS: TestAccAppMesh_serial/Route/http2Route (28.70s) --- PASS: TestAccAppMesh_serial/Route/dataSourceHTTPRoute (16.06s) --- PASS: TestAccAppMesh_serial/Route/http2RouteTimeout (28.80s) --- PASS: TestAccAppMesh_serial/Route/tcpRouteTimeout (27.79s) --- PASS: TestAccAppMesh_serial/Route/disappears (13.90s) --- PASS: TestAccAppMesh_serial/Route/grpcRouteWithPortMatch (50.50s) --- PASS: TestAccAppMesh_serial/Route/http2RouteWithPortMatch (27.65s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 654.457s --- internal/service/appmesh/appmesh_test.go | 4 + internal/service/appmesh/route.go | 733 +++++++++--------- internal/service/appmesh/route_data_source.go | 584 +------------- .../service/appmesh/route_data_source_test.go | 210 ++--- 4 files changed, 515 insertions(+), 1016 deletions(-) diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 6e80d751a6f..f53b865826f 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -49,6 +49,10 @@ func TestAccAppMesh_serial(t *testing.T) { "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/route.go b/internal/service/appmesh/route.go index f3f264e9090..a76898e809a 100644 --- a/internal/service/appmesh/route.go +++ b/internal/service/appmesh/route.go @@ -25,6 +25,68 @@ import ( // @SDKResource("aws_appmesh_route") func ResourceRoute() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceRouteCreate, + ReadWithoutTimeout: resourceRouteRead, + UpdateWithoutTimeout: resourceRouteUpdate, + DeleteWithoutTimeout: resourceRouteDelete, + + Importer: &schema.ResourceImporter{ + StateContext: resourceRouteImport, + }, + + 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, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + Computed: true, + 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": resourceRouteSpecSchema(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "virtual_router_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + }, + + CustomizeDiff: verify.SetTagsDiff, + } +} + +func resourceRouteSpecSchema() *schema.Schema { // httpRouteSchema returns the schema for `http_route` and `http2_route` attributes. httpRouteSchema := func() *schema.Schema { return &schema.Schema{ @@ -265,294 +327,245 @@ func ResourceRoute() *schema.Resource { } } - return &schema.Resource{ - CreateWithoutTimeout: resourceRouteCreate, - ReadWithoutTimeout: resourceRouteRead, - UpdateWithoutTimeout: resourceRouteUpdate, - DeleteWithoutTimeout: resourceRouteDelete, - - Importer: &schema.ResourceImporter{ - StateContext: resourceRouteImport, - }, - - 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, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "mesh_owner": { - Type: schema.TypeString, - Optional: true, - Computed: true, - 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": { - 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, - ConflictsWith: []string{"spec.0.http2_route", "spec.0.http_route", "spec.0.tcp_route"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "weighted_target": { - Type: schema.TypeSet, - Required: true, - MinItems: 1, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "virtual_node": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "weight": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(0, 100), - }, - }, + 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, + ConflictsWith: []string{"spec.0.http2_route", "spec.0.http_route", "spec.0.tcp_route"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_node": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "weight": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 100), }, }, }, }, }, - "match": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "metadata": { - 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, - }, - }, + }, + }, + "match": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "metadata": { + 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), + "regex": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "suffix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, }, }, }, - }, - "method_name": { - Type: schema.TypeString, - Optional: true, - RequiredWith: []string{"spec.0.grpc_route.0.match.0.service_name"}, - }, - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "prefix": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(0, 50), - }, - "service_name": { - Type: schema.TypeString, - Optional: true, + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 50), + }, }, }, }, + "method_name": { + Type: schema.TypeString, + Optional: true, + RequiredWith: []string{"spec.0.grpc_route.0.match.0.service_name"}, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "prefix": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 50), + }, + "service_name": { + Type: schema.TypeString, + Optional: true, + }, }, - "retry_policy": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "grpc_retry_events": { - Type: schema.TypeSet, - Optional: true, - MinItems: 0, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "http_retry_events": { - Type: schema.TypeSet, - Optional: true, - MinItems: 0, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - "max_retries": { - Type: schema.TypeInt, - Required: true, - }, - "per_retry_timeout": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, + }, + }, + "retry_policy": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grpc_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "http_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "max_retries": { + Type: schema.TypeInt, + Required: true, + }, + "per_retry_timeout": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, }, - }, - "tcp_retry_events": { - Type: schema.TypeSet, - Optional: true, - MinItems: 0, - Elem: &schema.Schema{Type: schema.TypeString}, }, }, }, + "tcp_retry_events": { + Type: schema.TypeSet, + Optional: true, + MinItems: 0, + Elem: &schema.Schema{Type: schema.TypeString}, + }, }, - "timeout": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idle": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, + }, + }, + "timeout": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idle": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, }, }, - "per_request": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, + }, + }, + "per_request": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, }, }, }, @@ -561,103 +574,103 @@ func ResourceRoute() *schema.Resource { }, }, }, - "http_route": func() *schema.Schema { - schema := httpRouteSchema() - schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.tcp_route"} - return schema - }(), - "http2_route": func() *schema.Schema { - schema := httpRouteSchema() - schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http_route", "spec.0.tcp_route"} - return schema - }(), - "priority": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IntBetween(0, 1000), - }, - "tcp_route": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - ConflictsWith: []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.http_route"}, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "weighted_target": { - Type: schema.TypeSet, - Required: true, - MinItems: 1, - MaxItems: 10, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - "virtual_node": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - "weight": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(0, 100), - }, - }, + }, + }, + "http_route": func() *schema.Schema { + schema := httpRouteSchema() + schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.tcp_route"} + return schema + }(), + "http2_route": func() *schema.Schema { + schema := httpRouteSchema() + schema.ConflictsWith = []string{"spec.0.grpc_route", "spec.0.http_route", "spec.0.tcp_route"} + return schema + }(), + "priority": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntBetween(0, 1000), + }, + "tcp_route": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + ConflictsWith: []string{"spec.0.grpc_route", "spec.0.http2_route", "spec.0.http_route"}, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "weighted_target": { + Type: schema.TypeSet, + Required: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "virtual_node": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "weight": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 100), }, }, }, }, }, - "match": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IsPortNumber, - }, - }, + }, + }, + "match": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IsPortNumber, }, }, - "timeout": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idle": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), - }, - "value": { - Type: schema.TypeInt, - Required: true, - }, - }, + }, + }, + "timeout": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "idle": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "unit": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.DurationUnit_Values(), false), + }, + "value": { + Type: schema.TypeInt, + Required: true, }, }, }, @@ -669,17 +682,7 @@ func ResourceRoute() *schema.Resource { }, }, }, - names.AttrTags: tftags.TagsSchema(), - names.AttrTagsAll: tftags.TagsSchemaComputed(), - "virtual_router_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, }, - - CustomizeDiff: verify.SetTagsDiff, } } diff --git a/internal/service/appmesh/route_data_source.go b/internal/service/appmesh/route_data_source.go index 2eecc1d866b..96578baac57 100644 --- a/internal/service/appmesh/route_data_source.go +++ b/internal/service/appmesh/route_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_route") @@ -19,555 +19,41 @@ func DataSourceRoute() *schema.Resource { ReadWithoutTimeout: dataSourceRouteRead, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - }, - - "mesh_name": { + "arn": { Type: schema.TypeString, - Required: true, + Computed: true, }, - - "mesh_owner": { + "created_date": { Type: schema.TypeString, - Optional: true, Computed: true, }, - - "virtual_router_name": { + "last_updated_date": { Type: schema.TypeString, - Required: true, - }, - - "spec": { - Type: schema.TypeList, Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "grpc_route": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "weighted_target": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node": { - Type: schema.TypeString, - Computed: true, - }, - - "weight": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - - "match": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "metadata": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "invert": { - Type: schema.TypeBool, - Computed: true, - }, - - "match": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "exact": { - Type: schema.TypeString, - Computed: true, - }, - - "prefix": { - Type: schema.TypeString, - Computed: true, - }, - - "range": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "end": { - Type: schema.TypeInt, - Computed: true, - }, - - "start": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - "regex": { - Type: schema.TypeString, - Computed: true, - }, - - "suffix": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "name": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "method_name": { - Type: schema.TypeString, - Computed: true, - }, - - "prefix": { - Type: schema.TypeString, - Computed: true, - }, - - "service_name": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "retry_policy": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "grpc_retry_events": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - "http_retry_events": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - "max_retries": { - Type: schema.TypeInt, - Computed: true, - }, - - "per_retry_timeout": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - "tcp_retry_events": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - - "timeout": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idle": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - "per_request": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - - "http2_route": func() *schema.Schema { - schema := DataSourceRouteHTTPRouteSchema() - return schema - }(), - - "http_route": func() *schema.Schema { - schema := DataSourceRouteHTTPRouteSchema() - return schema - }(), - - "priority": { - Type: schema.TypeInt, - Computed: true, - }, - - "tcp_route": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "weighted_target": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node": { - Type: schema.TypeString, - Computed: true, - }, - - "weight": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - - "timeout": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idle": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, - }, }, - - "arn": { + "mesh_name": { Type: schema.TypeString, - Computed: true, + Required: true, }, - - "created_date": { + "mesh_owner": { Type: schema.TypeString, + Optional: true, Computed: true, }, - - "last_updated_date": { + "name": { Type: schema.TypeString, - Computed: true, + Required: true, }, - "resource_owner": { Type: schema.TypeString, Computed: true, }, - - "tags": tftags.TagsSchemaComputed(), - }, - } -} - -func DataSourceRouteHTTPRouteSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "action": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "weighted_target": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "virtual_node": { - Type: schema.TypeString, - Computed: true, - }, - - "weight": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, - - "match": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "header": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "invert": { - Type: schema.TypeBool, - Computed: true, - }, - - "match": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "exact": { - Type: schema.TypeString, - Computed: true, - }, - - "prefix": { - Type: schema.TypeString, - Computed: true, - }, - - "range": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "end": { - Type: schema.TypeInt, - Computed: true, - }, - - "start": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - "regex": { - Type: schema.TypeString, - Computed: true, - }, - - "suffix": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "name": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "method": { - Type: schema.TypeString, - Computed: true, - }, - - "prefix": { - Type: schema.TypeString, - Computed: true, - }, - - "scheme": { - Type: schema.TypeString, - Computed: true, - }, - }, - }, - }, - - "retry_policy": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "http_retry_events": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - - "max_retries": { - Type: schema.TypeInt, - Computed: true, - }, - - "per_retry_timeout": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - "tcp_retry_events": { - Type: schema.TypeSet, - Computed: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - }, - }, - }, - - "timeout": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "idle": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - - "per_request": { - Type: schema.TypeList, - Computed: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "unit": { - Type: schema.TypeString, - Computed: true, - }, - - "value": { - Type: schema.TypeInt, - Computed: true, - }, - }, - }, - }, - }, - }, - }, + "virtual_router_name": { + Type: schema.TypeString, + Required: true, }, + "spec": dataSourcePropertyFromResourceProperty(resourceRouteSpecSchema()), + names.AttrTags: tftags.TagsSchemaComputed(), }, } } @@ -577,38 +63,26 @@ func dataSourceRouteRead(ctx context.Context, d *schema.ResourceData, meta inter conn := meta.(*conns.AWSClient).AppMeshConn() ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &appmesh.DescribeRouteInput{ - MeshName: aws.String(d.Get("mesh_name").(string)), - VirtualRouterName: aws.String(d.Get("virtual_router_name").(string)), - RouteName: aws.String(d.Get("name").(string)), - } - - if v, ok := d.GetOk("mesh_owner"); ok { - req.MeshOwner = aws.String(v.(string)) - } + routeName := d.Get("name").(string) + route, err := FindRouteByFourPartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("virtual_router_name").(string), routeName) - resp, err := conn.DescribeRoute(req) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Route: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Route (%s): %s", routeName, err) } - arn := aws.StringValue(resp.Route.Metadata.Arn) - - d.SetId(aws.StringValue(resp.Route.RouteName)) - - d.Set("name", resp.Route.RouteName) - d.Set("mesh_name", resp.Route.MeshName) - d.Set("mesh_owner", resp.Route.Metadata.MeshOwner) - d.Set("virtual_router_name", resp.Route.VirtualRouterName) + d.SetId(aws.StringValue(route.RouteName)) + arn := aws.StringValue(route.Metadata.Arn) d.Set("arn", arn) - d.Set("created_date", resp.Route.Metadata.CreatedAt.Format(time.RFC3339)) - d.Set("last_updated_date", resp.Route.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("resource_owner", resp.Route.Metadata.ResourceOwner) - - err = d.Set("spec", flattenRouteSpec(resp.Route.Spec)) - if err != nil { + d.Set("created_date", route.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", route.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", route.MeshName) + d.Set("mesh_owner", route.Metadata.MeshOwner) + d.Set("name", route.RouteName) + d.Set("resource_owner", route.Metadata.ResourceOwner) + if err := d.Set("spec", flattenRouteSpec(route.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } + d.Set("virtual_router_name", route.VirtualRouterName) tags, err := ListTags(ctx, conn, arn) diff --git a/internal/service/appmesh/route_data_source_test.go b/internal/service/appmesh/route_data_source_test.go index ef701345bc8..f3630676ca0 100644 --- a/internal/service/appmesh/route_data_source_test.go +++ b/internal/service/appmesh/route_data_source_test.go @@ -10,7 +10,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/acctest" ) -func TestAccAppMeshRouteDataSource_http2Route(t *testing.T) { +func testAccRouteDataSource_http2Route(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_appmesh_route.test" dataSourceName := "data.aws_appmesh_route.test" @@ -19,11 +19,10 @@ func TestAccAppMeshRouteDataSource_http2Route(t *testing.T) { vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - 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, - CheckDestroy: testAccCheckRouteDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccRouteDataSourceConfig_http2Route(meshName, vrName, vnName, rName), @@ -36,15 +35,20 @@ func TestAccAppMeshRouteDataSource_http2Route(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.0.http2_route", dataSourceName, "spec.0.http2_route"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + 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, "spec.0.priority", dataSourceName, "spec.0.priority"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.tcp_route.#", dataSourceName, "spec.0.tcp_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, }) } -func TestAccAppMeshRouteDataSource_httpRoute(t *testing.T) { +func testAccRouteDataSource_httpRoute(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_appmesh_route.test" dataSourceName := "data.aws_appmesh_route.test" @@ -53,11 +57,10 @@ func TestAccAppMeshRouteDataSource_httpRoute(t *testing.T) { vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - 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, - CheckDestroy: testAccCheckRouteDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccRouteDataSourceConfig_httpRoute(meshName, vrName, vnName, rName), @@ -70,15 +73,20 @@ func TestAccAppMeshRouteDataSource_httpRoute(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.0.http_route", dataSourceName, "spec.0.http_route"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + 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, "spec.0.priority", dataSourceName, "spec.0.priority"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.tcp_route.#", dataSourceName, "spec.0.tcp_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, }) } -func TestAccAppMeshRouteDataSource_grpcRoute(t *testing.T) { +func testAccRouteDataSource_grpcRoute(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_appmesh_route.test" dataSourceName := "data.aws_appmesh_route.test" @@ -87,7 +95,7 @@ func TestAccAppMeshRouteDataSource_grpcRoute(t *testing.T) { vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - 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, @@ -104,15 +112,20 @@ func TestAccAppMeshRouteDataSource_grpcRoute(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.0.grpc_route", dataSourceName, "spec.0.grpc_route"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + 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, "spec.0.priority", dataSourceName, "spec.0.priority"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.tcp_route.#", dataSourceName, "spec.0.tcp_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, }) } -func TestAccAppMeshRouteDataSource_tcpRoute(t *testing.T) { +func testAccRouteDataSource_tcpRoute(t *testing.T) { ctx := acctest.Context(t) resourceName := "aws_appmesh_route.test" dataSourceName := "data.aws_appmesh_route.test" @@ -121,7 +134,7 @@ func TestAccAppMeshRouteDataSource_tcpRoute(t *testing.T) { vnName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - 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, @@ -138,95 +151,100 @@ func TestAccAppMeshRouteDataSource_tcpRoute(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.0.tcp_route", dataSourceName, "spec.0.tcp_route"), - resource.TestCheckResourceAttrPair(resourceName, "tags", dataSourceName, "tags"), + 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, "spec.0.priority", dataSourceName, "spec.0.priority"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.tcp_route.#", dataSourceName, "spec.0.tcp_route.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), ), }, }, }) } -func testAccRouteDataSourceConfigBase(meshName, vrName, vnName string) string { +func testAccRouteDataSourceConfig_base(meshName, vrName, vnName 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" - } - } - } - } - - resource "aws_appmesh_virtual_node" "test" { - name = %[3]q - mesh_name = aws_appmesh_mesh.test.id - - spec {} - } +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" + } + } + } +} + +resource "aws_appmesh_virtual_node" "test" { + name = %[3]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} +} `, meshName, vrName, vnName) } func testAccRouteDataSourceConfig_httpRoute(meshName, vrName, vnName, rName string) string { - return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteDataSourceConfig_base(meshName, vrName, vnName), fmt.Sprintf(` resource "aws_appmesh_route" "test" { - name = %[1]q - mesh_name = aws_appmesh_mesh.test.id - virtual_router_name = aws_appmesh_virtual_router.test.name - - spec { - http2_route { - match { - prefix = "/" - method = "POST" - scheme = "http" - - header { - name = "X-Testing1" - } - } - - retry_policy { - http_retry_events = [ - "server-error", - ] - - max_retries = 1 - - per_retry_timeout { - unit = "s" - value = 15 - } - } - - action { - weighted_target { - virtual_node = aws_appmesh_virtual_node.test.name - weight = 100 - } - } - } - } + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + virtual_router_name = aws_appmesh_virtual_router.test.name + + spec { + http2_route { + match { + prefix = "/" + method = "POST" + scheme = "http" + + header { + name = "X-Testing1" + } + } + + retry_policy { + http_retry_events = [ + "server-error", + ] + + max_retries = 1 + + per_retry_timeout { + unit = "s" + value = 15 + } + } + + action { + weighted_target { + virtual_node = aws_appmesh_virtual_node.test.name + weight = 100 + } + } + } } +} data "aws_appmesh_route" "test" { - name = aws_appmesh_route.test.name - mesh_name = aws_appmesh_route.test.mesh_name - virtual_router_name = aws_appmesh_route.test.virtual_router_name + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name } `, rName)) } func testAccRouteDataSourceConfig_http2Route(meshName, vrName, vnName, rName string) string { - return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteDataSourceConfig_base(meshName, vrName, vnName), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -268,15 +286,15 @@ resource "aws_appmesh_route" "test" { } data "aws_appmesh_route" "test" { - name = aws_appmesh_route.test.name - mesh_name = aws_appmesh_route.test.mesh_name - virtual_router_name = aws_appmesh_route.test.virtual_router_name + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name } `, rName)) } func testAccRouteDataSourceConfig_grpcRoute(meshName, vrName, vnName, rName string) string { - return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteDataSourceConfig_base(meshName, vrName, vnName), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -319,15 +337,15 @@ resource "aws_appmesh_route" "test" { } data "aws_appmesh_route" "test" { - name = aws_appmesh_route.test.name - mesh_name = aws_appmesh_route.test.mesh_name - virtual_router_name = aws_appmesh_route.test.virtual_router_name + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name } `, rName)) } func testAccRouteDataSourceConfig_tcpRoute(meshName, vrName, vnName, rName string) string { - return acctest.ConfigCompose(testAccRouteDataSourceConfigBase(meshName, vrName, vnName), fmt.Sprintf(` + return acctest.ConfigCompose(testAccRouteDataSourceConfig_base(meshName, vrName, vnName), fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = aws_appmesh_mesh.test.id @@ -346,9 +364,9 @@ resource "aws_appmesh_route" "test" { } data "aws_appmesh_route" "test" { - name = aws_appmesh_route.test.name - mesh_name = aws_appmesh_route.test.mesh_name - virtual_router_name = aws_appmesh_route.test.virtual_router_name + name = aws_appmesh_route.test.name + mesh_name = aws_appmesh_route.test.mesh_name + virtual_router_name = aws_appmesh_route.test.virtual_router_name } `, rName)) } From b78a3a4546da3eca1149b1f40e1d7d6f8b9e55e7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 12:30:27 -0400 Subject: [PATCH 22/25] d/aws_appmesh_mesh: Don't attempt to list tags if the current AWS account is not the mesh owner. Acceptance test output: % make testacc TESTARGS='-run=TestAccAppMesh_serial/^Mesh$$/dataSourceShared' 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/^Mesh$/dataSourceShared -timeout 180m === RUN TestAccAppMesh_serial === PAUSE TestAccAppMesh_serial === CONT TestAccAppMesh_serial === RUN TestAccAppMesh_serial/Mesh === RUN TestAccAppMesh_serial/Mesh/dataSourceShared --- PASS: TestAccAppMesh_serial (28.44s) --- PASS: TestAccAppMesh_serial/Mesh (28.44s) --- PASS: TestAccAppMesh_serial/Mesh/dataSourceShared (28.44s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/appmesh 35.884s --- .changelog/26695.txt | 4 + internal/service/appmesh/appmesh_test.go | 1 + internal/service/appmesh/mesh_data_source.go | 16 +++- .../service/appmesh/mesh_data_source_test.go | 78 ++++++++++++++++++- 4 files changed, 93 insertions(+), 6 deletions(-) diff --git a/.changelog/26695.txt b/.changelog/26695.txt index 3e07ec4f56a..07486d09013 100644 --- a/.changelog/26695.txt +++ b/.changelog/26695.txt @@ -1,3 +1,7 @@ ```release-note:new-data-source aws_appmesh_route ``` + +```release-note:bug +data-source/aws_appmesh_mesh: Don't attempt to list tags if the current AWS account is not the mesh owner +``` \ No newline at end of file diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index f53b865826f..166965e227c 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -29,6 +29,7 @@ func TestAccAppMesh_serial(t *testing.T) { "dataSourceBasic": testAccMeshDataSource_basic, "dataSourceMeshOwner": testAccMeshDataSource_meshOwner, "dataSourceSpecAndTagsSet": testAccMeshDataSource_specAndTagsSet, + "dataSourceShared": testAccMeshDataSource_shared, }, "Route": { "disappears": testAccRoute_disappears, diff --git a/internal/service/appmesh/mesh_data_source.go b/internal/service/appmesh/mesh_data_source.go index c810a48b321..dcc637259e7 100644 --- a/internal/service/appmesh/mesh_data_source.go +++ b/internal/service/appmesh/mesh_data_source.go @@ -67,16 +67,24 @@ func dataSourceMeshRead(ctx context.Context, d *schema.ResourceData, meta interf d.Set("arn", arn) d.Set("created_date", mesh.Metadata.CreatedAt.Format(time.RFC3339)) d.Set("last_updated_date", mesh.Metadata.LastUpdatedAt.Format(time.RFC3339)) - d.Set("mesh_owner", mesh.Metadata.MeshOwner) + meshOwner := aws.StringValue(mesh.Metadata.MeshOwner) + d.Set("mesh_owner", meshOwner) d.Set("resource_owner", mesh.Metadata.ResourceOwner) if err := d.Set("spec", flattenMeshSpec(mesh.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 Service Mesh (%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 Service Mesh (%s): %s", arn, err) + } } if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { diff --git a/internal/service/appmesh/mesh_data_source_test.go b/internal/service/appmesh/mesh_data_source_test.go index abdb9a68c03..77eeb121ba3 100644 --- a/internal/service/appmesh/mesh_data_source_test.go +++ b/internal/service/appmesh/mesh_data_source_test.go @@ -100,6 +100,40 @@ func testAccMeshDataSource_specAndTagsSet(t *testing.T) { }) } +func testAccMeshDataSource_shared(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appmesh_mesh.test" + dataSourceName := "data.aws_appmesh_mesh.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckAlternateAccount(t) + acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) + }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5FactoriesAlternate(ctx, t), + Steps: []resource.TestStep{ + { + Config: testAccMeshDataSourceConfig_shared(rName), + 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_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.egress_filter.#", dataSourceName, "spec.0.egress_filter.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.egress_filter.0.type", dataSourceName, "spec.0.egress_filter.0.type"), + resource.TestCheckNoResourceAttr(dataSourceName, "tags.%"), + ), + }, + }, + }) +} + func testAccMeshDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { @@ -129,8 +163,6 @@ data "aws_appmesh_mesh" "test" { func testAccMeshDataSourceConfig_specAndTagsSet(rName string) string { return fmt.Sprintf(` -data "aws_caller_identity" "current" {} - resource "aws_appmesh_mesh" "test" { name = %[1]q @@ -150,3 +182,45 @@ data "aws_appmesh_mesh" "test" { } `, rName) } + +func testAccMeshDataSourceConfig_shared(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAlternateAccountProvider(), fmt.Sprintf(` +data "aws_caller_identity" "source" {} + +data "aws_caller_identity" "target" { + provider = "awsalternate" +} + +resource "aws_appmesh_mesh" "test" { + name = %[1]q + + tags = { + Name = %[1]q + } +} + +resource "aws_ram_resource_share" "test" { + name = %[1]q + allow_external_principals = false +} + +resource "aws_ram_resource_association" "test" { + resource_arn = aws_appmesh_mesh.test.arn + resource_share_arn = aws_ram_resource_share.test.arn +} + +resource "aws_ram_principal_association" "test" { + principal = data.aws_caller_identity.target.arn + resource_share_arn = aws_ram_resource_share.test.arn +} + +data "aws_appmesh_mesh" "test" { + provider = "awsalternate" + + name = aws_appmesh_mesh.test.name + mesh_owner = data.aws_caller_identity.source.account_id + + depends_on = [aws_ram_resource_association.test, aws_ram_principal_association.test] +} +`, rName)) +} From a40da1cf9a2d809389b5ac8f39757eab9d73d0ec Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 12:39:09 -0400 Subject: [PATCH 23/25] d/aws_appmesh_virtual_service: Don't attempt to list tags if the current AWS account is not the mesh owner. --- .changelog/26695.txt | 4 ++++ .../appmesh/virtual_service_data_source.go | 16 ++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/.changelog/26695.txt b/.changelog/26695.txt index 07486d09013..f8c6525bbcc 100644 --- a/.changelog/26695.txt +++ b/.changelog/26695.txt @@ -4,4 +4,8 @@ aws_appmesh_route ```release-note:bug data-source/aws_appmesh_mesh: Don't attempt to list tags if the current AWS account is not the mesh owner +``` + +```release-note:bug +data-source/aws_appmesh_virtual_service: Don't attempt to list tags if the current AWS account is not the mesh owner ``` \ No newline at end of file diff --git a/internal/service/appmesh/virtual_service_data_source.go b/internal/service/appmesh/virtual_service_data_source.go index a43fe747717..f926dd8838a 100644 --- a/internal/service/appmesh/virtual_service_data_source.go +++ b/internal/service/appmesh/virtual_service_data_source.go @@ -72,17 +72,25 @@ func dataSourceVirtualServiceRead(ctx context.Context, d *schema.ResourceData, m d.Set("created_date", vs.Metadata.CreatedAt.Format(time.RFC3339)) d.Set("last_updated_date", vs.Metadata.LastUpdatedAt.Format(time.RFC3339)) d.Set("mesh_name", vs.MeshName) - d.Set("mesh_owner", vs.Metadata.MeshOwner) + meshOwner := aws.StringValue(vs.Metadata.MeshOwner) + d.Set("mesh_owner", meshOwner) d.Set("name", vs.VirtualServiceName) d.Set("resource_owner", vs.Metadata.ResourceOwner) if err := d.Set("spec", flattenVirtualServiceSpec(vs.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 Service (%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 Service (%s): %s", arn, err) + } } if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { From c027741a5bc3e195cf87291da46b53e5bceec729 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 12:40:26 -0400 Subject: [PATCH 24/25] d/aws_appmesh_route: Don't attempt to list tags if the current AWS account is not the mesh owner. --- internal/service/appmesh/route_data_source.go | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/internal/service/appmesh/route_data_source.go b/internal/service/appmesh/route_data_source.go index 96578baac57..ee089ae6807 100644 --- a/internal/service/appmesh/route_data_source.go +++ b/internal/service/appmesh/route_data_source.go @@ -76,7 +76,8 @@ func dataSourceRouteRead(ctx context.Context, d *schema.ResourceData, meta inter d.Set("created_date", route.Metadata.CreatedAt.Format(time.RFC3339)) d.Set("last_updated_date", route.Metadata.LastUpdatedAt.Format(time.RFC3339)) d.Set("mesh_name", route.MeshName) - d.Set("mesh_owner", route.Metadata.MeshOwner) + meshOwner := aws.StringValue(route.Metadata.MeshOwner) + d.Set("mesh_owner", meshOwner) d.Set("name", route.RouteName) d.Set("resource_owner", route.Metadata.ResourceOwner) if err := d.Set("spec", flattenRouteSpec(route.Spec)); err != nil { @@ -84,10 +85,17 @@ func dataSourceRouteRead(ctx context.Context, d *schema.ResourceData, meta inter } d.Set("virtual_router_name", route.VirtualRouterName) - 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 Route (%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 Route (%s): %s", arn, err) + } } if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { From 42055bf499399b0eb2be6f4794f28294c7318c1d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 23 Mar 2023 13:38:50 -0400 Subject: [PATCH 25/25] Fix providerlint 'S019: schema should omit Computed, Optional, or Required set to false'. --- internal/service/appmesh/mesh.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 2e5f7086646..7e62ec0be76 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -290,8 +290,6 @@ func dataSourceSchemaFromResourceSchema(rs map[string]*schema.Schema) map[string func dataSourcePropertyFromResourceProperty(rs *schema.Schema) *schema.Schema { ds := &schema.Schema{ Computed: true, - ForceNew: false, - Required: false, Description: rs.Description, Type: rs.Type, }