diff --git a/.changelog/19774.txt b/.changelog/19774.txt new file mode 100644 index 00000000000..a4268e1737a --- /dev/null +++ b/.changelog/19774.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_appmesh_virtual_service +``` diff --git a/aws/data_source_aws_appmesh_mesh_test.go b/aws/data_source_aws_appmesh_mesh_test.go index a5a6b8a7d13..f636fa8324b 100644 --- a/aws/data_source_aws_appmesh_mesh_test.go +++ b/aws/data_source_aws_appmesh_mesh_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) -func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { +func TestAccDataSourceAWSAppmeshMesh_basic(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_mesh.test" dataSourceName := "data.aws_appmesh_mesh.test" @@ -37,7 +37,7 @@ func TestAccAWSAppmeshMeshDataSource_basic(t *testing.T) { }) } -func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { +func TestAccDataSourceAWSAppmeshMesh_meshOwner(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_mesh.test" dataSourceName := "data.aws_appmesh_mesh.test" @@ -65,7 +65,7 @@ func TestAccAWSAppmeshMeshDataSource_meshOwner(t *testing.T) { }) } -func TestAccAWSAppmeshMeshDataSource_specAndTagsSet(t *testing.T) { +func TestAccDataSourceAWSAppmeshMesh_specAndTagsSet(t *testing.T) { rName := acctest.RandomWithPrefix("tf-acc-test") resourceName := "aws_appmesh_mesh.test" dataSourceName := "data.aws_appmesh_mesh.test" diff --git a/aws/data_source_aws_appmesh_virtual_service.go b/aws/data_source_aws_appmesh_virtual_service.go new file mode 100644 index 00000000000..8954223d0fb --- /dev/null +++ b/aws/data_source_aws_appmesh_virtual_service.go @@ -0,0 +1,147 @@ +package aws + +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/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func dataSourceAwsAppmeshVirtualService() *schema.Resource { + return &schema.Resource{ + Read: dataSourceAwsAppmeshVirtualServiceRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + + "mesh_name": { + Type: schema.TypeString, + Required: true, + }, + + "mesh_owner": { + Type: schema.TypeString, + Optional: true, + Computed: true, + }, + + "name": { + Type: schema.TypeString, + Required: true, + }, + + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + + "spec": { + 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, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + + "tags": tagsSchema(), + }, + } +} + +func dataSourceAwsAppmeshVirtualServiceRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).appmeshconn + ignoreTagsConfig := meta.(*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)) + } + + resp, err := conn.DescribeVirtualService(req) + if err != nil { + return fmt.Errorf("error reading App Mesh Virtual Service: %s", 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.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", flattenAppmeshVirtualServiceSpec(resp.VirtualService.Spec)) + if err != nil { + return fmt.Errorf("error setting spec: %s", err) + } + + tags, err := keyvaluetags.AppmeshListTags(conn, arn) + + if err != nil { + return fmt.Errorf("error listing tags for App Mesh Virtual Service (%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/aws/data_source_aws_appmesh_virtual_service_test.go b/aws/data_source_aws_appmesh_virtual_service_test.go new file mode 100644 index 00000000000..92c808acc7f --- /dev/null +++ b/aws/data_source_aws_appmesh_virtual_service_test.go @@ -0,0 +1,151 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/appmesh" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceAWSAppmeshVirtualService_virtualNode(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_virtual_service.test" + dataSourceName := "data.aws_appmesh_virtual_service.test" + vsName := fmt.Sprintf("tf-acc-test-%d.mesh.local", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshVirtualServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualNode(rName, vsName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_name", dataSourceName, "mesh_name"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.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"), + ), + }, + }, + }) +} + +func TestAccDataSourceAWSAppmeshVirtualService_virtualRouter(t *testing.T) { + rName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_appmesh_virtual_service.test" + dataSourceName := "data.aws_appmesh_virtual_service.test" + vsName := fmt.Sprintf("tf-acc-test-%d.mesh.local", acctest.RandInt()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPartitionHasServicePreCheck(appmesh.EndpointsID, t) }, + ErrorCheck: testAccErrorCheck(t, appmesh.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAppmeshVirtualServiceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualRouter(rName, vsName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_name", dataSourceName, "mesh_name"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.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"), + ), + }, + }, + }) +} + +func testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualNode(rName, vsName string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_node" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + + spec {} +} + +resource "aws_appmesh_virtual_service" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_node { + virtual_node_name = aws_appmesh_virtual_node.test.name + } + } + } + + tags = { + foo = "bar" + good = "bad" + } +} + +data "aws_appmesh_virtual_service" "test" { + name = aws_appmesh_virtual_service.test.name + mesh_name = aws_appmesh_mesh.test.name +} +`, rName, vsName) +} + +func testAccCheckAwsAppmeshVirtualServiceDataSourceConfig_virtualRouter(rName, vsName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_router" "test" { + name = %[1]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } +} + +resource "aws_appmesh_virtual_service" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + provider { + virtual_router { + virtual_router_name = aws_appmesh_virtual_router.test.name + } + } + } +} + +data "aws_appmesh_virtual_service" "test" { + name = aws_appmesh_virtual_service.test.name + mesh_name = aws_appmesh_mesh.test.name + mesh_owner = data.aws_caller_identity.current.account_id +} +`, rName, vsName) +} diff --git a/aws/provider.go b/aws/provider.go index 90a10131846..4a6c3d71bce 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -197,6 +197,7 @@ func Provider() *schema.Provider { "aws_apigatewayv2_api": dataSourceAwsApiGatewayV2Api(), "aws_apigatewayv2_apis": dataSourceAwsApiGatewayV2Apis(), "aws_appmesh_mesh": dataSourceAwsAppmeshMesh(), + "aws_appmesh_virtual_service": dataSourceAwsAppmeshVirtualService(), "aws_arn": dataSourceAwsArn(), "aws_autoscaling_group": dataSourceAwsAutoscalingGroup(), "aws_autoscaling_groups": dataSourceAwsAutoscalingGroups(), diff --git a/website/docs/d/appmesh_virtual_service.html.markdown b/website/docs/d/appmesh_virtual_service.html.markdown new file mode 100644 index 00000000000..cab1b5201ca --- /dev/null +++ b/website/docs/d/appmesh_virtual_service.html.markdown @@ -0,0 +1,66 @@ +--- +subcategory: "AppMesh" +layout: "aws" +page_title: "AWS: aws_appmesh_virtual_service" +description: |- + Provides an AWS App Mesh virtual service resource. +--- + +# Data Source: aws_appmesh_virtual_service + +The App Mesh Virtual Service data source allows details of an App Mesh Virtual Service to be retrieved by its name, mesh_name, and optionally the mesh_owner. + +## Example Usage + +```hcl +data "aws_appmesh_virtual_service" "test" { + name = "example.mesh.local" + mesh_name = "example-mesh" +} +``` + +```hcl +data "aws_caller_identity" "current" {} + +data "aws_appmesh_virtual_service" "test" { + name = "example.mesh.local" + mesh_name = "example-mesh" + mesh_owner = data.aws_caller_identity.current.account_id +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name of the virtual service. +* `mesh_name` - (Required) The name of the service mesh in which the virtual service exists. +* `mesh_owner` - (Optional) The AWS account ID of the service mesh's owner. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - The ARN of the virtual service. +* `created_date` - The creation date of the virtual service. +* `last_updated_date` - The last update date of the virtual service. +* `resource_owner` - The resource owner's AWS account ID. +* `spec` - The virtual service specification +* `tags` - A map of tags. + +### Spec + +* `provider` - The App Mesh object that is acting as the provider for a virtual service. + +### Provider + +* `virtual_node` - The virtual node associated with the virtual service. +* `virtual_router` - The virtual router associated with the virtual service. + +### Virtual Node + +* `virtual_node_name` - The name of the virtual node that is acting as a service provider. + +### Virtual Router + +* `virtual_router_name` - The name of the virtual router that is acting as a service provider.