diff --git a/.changelog/32276.txt b/.changelog/32276.txt new file mode 100644 index 000000000000..8cb046fbccaf --- /dev/null +++ b/.changelog/32276.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_opensearchserverless_vpc_endpoint +``` \ No newline at end of file diff --git a/internal/service/opensearchserverless/access_policy.go b/internal/service/opensearchserverless/access_policy.go index 4bfe735c2a27..e8b888dc30b1 100644 --- a/internal/service/opensearchserverless/access_policy.go +++ b/internal/service/opensearchserverless/access_policy.go @@ -139,7 +139,7 @@ func (r *resourceAccessPolicy) Read(ctx context.Context, req resource.ReadReques return } - out, err := FindAccessPolicyByNameAndType(ctx, conn, state.ID.ValueString(), state.Type.ValueString()) + out, err := findAccessPolicyByNameAndType(ctx, conn, state.ID.ValueString(), state.Type.ValueString()) if tfresource.NotFound(err) { resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) diff --git a/internal/service/opensearchserverless/access_policy_data_source.go b/internal/service/opensearchserverless/access_policy_data_source.go index c2faf369cfe0..c4ccf3c48349 100644 --- a/internal/service/opensearchserverless/access_policy_data_source.go +++ b/internal/service/opensearchserverless/access_policy_data_source.go @@ -70,7 +70,7 @@ func (d *dataSourceAccessPolicy) Read(ctx context.Context, req datasource.ReadRe return } - out, err := FindAccessPolicyByNameAndType(ctx, conn, data.Name.ValueString(), data.Type.ValueString()) + out, err := findAccessPolicyByNameAndType(ctx, conn, data.Name.ValueString(), data.Type.ValueString()) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionReading, DSNameAccessPolicy, data.Name.String(), err), diff --git a/internal/service/opensearchserverless/collection.go b/internal/service/opensearchserverless/collection.go index d2116e363d60..9eda00316954 100644 --- a/internal/service/opensearchserverless/collection.go +++ b/internal/service/opensearchserverless/collection.go @@ -198,7 +198,7 @@ func (r *resourceCollection) Read(ctx context.Context, req resource.ReadRequest, return } - out, err := FindCollectionByID(ctx, conn, state.ID.ValueString()) + out, err := findCollectionByID(ctx, conn, state.ID.ValueString()) if tfresource.NotFound(err) { resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) @@ -339,7 +339,7 @@ func waitCollectionDeleted(ctx context.Context, conn *opensearchserverless.Clien func statusCollection(ctx context.Context, conn *opensearchserverless.Client, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := FindCollectionByID(ctx, conn, id) + output, err := findCollectionByID(ctx, conn, id) if tfresource.NotFound(err) { return nil, "", nil diff --git a/internal/service/opensearchserverless/collection_data_source.go b/internal/service/opensearchserverless/collection_data_source.go index 3e20ae26fa5c..90b55cf9c74c 100644 --- a/internal/service/opensearchserverless/collection_data_source.go +++ b/internal/service/opensearchserverless/collection_data_source.go @@ -98,7 +98,7 @@ func (d *dataSourceCollection) Read(ctx context.Context, req datasource.ReadRequ var out *awstypes.CollectionDetail if !data.ID.IsNull() && !data.ID.IsUnknown() { - output, err := FindCollectionByID(ctx, conn, data.ID.ValueString()) + output, err := findCollectionByID(ctx, conn, data.ID.ValueString()) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionReading, DSNameCollection, data.ID.String(), err), @@ -111,7 +111,7 @@ func (d *dataSourceCollection) Read(ctx context.Context, req datasource.ReadRequ } if !data.Name.IsNull() && !data.Name.IsUnknown() { - output, err := FindCollectionByName(ctx, conn, data.Name.ValueString()) + output, err := findCollectionByName(ctx, conn, data.Name.ValueString()) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionReading, DSNameCollection, data.ID.String(), err), diff --git a/internal/service/opensearchserverless/exports_test.go b/internal/service/opensearchserverless/exports_test.go index 47747b32ac01..fb57d2f6d47d 100644 --- a/internal/service/opensearchserverless/exports_test.go +++ b/internal/service/opensearchserverless/exports_test.go @@ -7,4 +7,10 @@ var ( ResourceSecurityConfig = newResourceSecurityConfig ResourceSecurityPolicy = newResourceSecurityPolicy ResourceVPCEndpoint = newResourceVPCEndpoint + + FindAccessPolicyByNameAndType = findAccessPolicyByNameAndType + FindCollectionByID = findCollectionByID + FindSecurityConfigByID = findSecurityConfigByID + FindSecurityPolicyByNameAndType = findSecurityPolicyByNameAndType + FindVPCEndpointByID = findVPCEndpointByID ) diff --git a/internal/service/opensearchserverless/find.go b/internal/service/opensearchserverless/find.go index 271d0d35d61b..761656d8c94d 100644 --- a/internal/service/opensearchserverless/find.go +++ b/internal/service/opensearchserverless/find.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -func FindAccessPolicyByNameAndType(ctx context.Context, conn *opensearchserverless.Client, id, policyType string) (*types.AccessPolicyDetail, error) { +func findAccessPolicyByNameAndType(ctx context.Context, conn *opensearchserverless.Client, id, policyType string) (*types.AccessPolicyDetail, error) { in := &opensearchserverless.GetAccessPolicyInput{ Name: aws.String(id), Type: types.AccessPolicyType(policyType), @@ -36,7 +36,7 @@ func FindAccessPolicyByNameAndType(ctx context.Context, conn *opensearchserverle return out.AccessPolicyDetail, nil } -func FindCollectionByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.CollectionDetail, error) { +func findCollectionByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.CollectionDetail, error) { in := &opensearchserverless.BatchGetCollectionInput{ Ids: []string{id}, } @@ -60,7 +60,7 @@ func FindCollectionByID(ctx context.Context, conn *opensearchserverless.Client, return &out.CollectionDetails[0], nil } -func FindCollectionByName(ctx context.Context, conn *opensearchserverless.Client, name string) (*types.CollectionDetail, error) { +func findCollectionByName(ctx context.Context, conn *opensearchserverless.Client, name string) (*types.CollectionDetail, error) { in := &opensearchserverless.BatchGetCollectionInput{ Names: []string{name}, } @@ -88,7 +88,7 @@ func FindCollectionByName(ctx context.Context, conn *opensearchserverless.Client return &out.CollectionDetails[0], nil } -func FindSecurityConfigByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.SecurityConfigDetail, error) { +func findSecurityConfigByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.SecurityConfigDetail, error) { in := &opensearchserverless.GetSecurityConfigInput{ Id: aws.String(id), } @@ -112,7 +112,7 @@ func FindSecurityConfigByID(ctx context.Context, conn *opensearchserverless.Clie return out.SecurityConfigDetail, nil } -func FindSecurityPolicyByNameAndType(ctx context.Context, conn *opensearchserverless.Client, name, policyType string) (*types.SecurityPolicyDetail, error) { +func findSecurityPolicyByNameAndType(ctx context.Context, conn *opensearchserverless.Client, name, policyType string) (*types.SecurityPolicyDetail, error) { in := &opensearchserverless.GetSecurityPolicyInput{ Name: aws.String(name), Type: types.SecurityPolicyType(policyType), @@ -137,7 +137,7 @@ func FindSecurityPolicyByNameAndType(ctx context.Context, conn *opensearchserver return out.SecurityPolicyDetail, nil } -func FindVPCEndpointByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.VpcEndpointDetail, error) { +func findVPCEndpointByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.VpcEndpointDetail, error) { in := &opensearchserverless.BatchGetVpcEndpointInput{ Ids: []string{id}, } diff --git a/internal/service/opensearchserverless/security_config.go b/internal/service/opensearchserverless/security_config.go index 993ba49524ef..4ac7a5ff06f6 100644 --- a/internal/service/opensearchserverless/security_config.go +++ b/internal/service/opensearchserverless/security_config.go @@ -167,7 +167,7 @@ func (r *resourceSecurityConfig) Read(ctx context.Context, req resource.ReadRequ return } - out, err := FindSecurityConfigByID(ctx, conn, state.ID.ValueString()) + out, err := findSecurityConfigByID(ctx, conn, state.ID.ValueString()) if tfresource.NotFound(err) { resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) diff --git a/internal/service/opensearchserverless/security_config_data_source.go b/internal/service/opensearchserverless/security_config_data_source.go index 559b5643c1c1..09be3f061763 100644 --- a/internal/service/opensearchserverless/security_config_data_source.go +++ b/internal/service/opensearchserverless/security_config_data_source.go @@ -83,7 +83,7 @@ func (d *dataSourceSecurityConfig) Read(ctx context.Context, req datasource.Read return } - out, err := FindSecurityConfigByID(ctx, conn, data.ID.ValueString()) + out, err := findSecurityConfigByID(ctx, conn, data.ID.ValueString()) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionReading, DSNameSecurityConfig, data.ID.String(), err), diff --git a/internal/service/opensearchserverless/security_policy.go b/internal/service/opensearchserverless/security_policy.go index 7b61ae8945a7..28594df72804 100644 --- a/internal/service/opensearchserverless/security_policy.go +++ b/internal/service/opensearchserverless/security_policy.go @@ -139,7 +139,7 @@ func (r *resourceSecurityPolicy) Read(ctx context.Context, req resource.ReadRequ return } - out, err := FindSecurityPolicyByNameAndType(ctx, conn, state.ID.ValueString(), state.Type.ValueString()) + out, err := findSecurityPolicyByNameAndType(ctx, conn, state.ID.ValueString(), state.Type.ValueString()) if tfresource.NotFound(err) { resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) diff --git a/internal/service/opensearchserverless/security_policy_data_source.go b/internal/service/opensearchserverless/security_policy_data_source.go index d6b3ffcf513d..4906fdade6ba 100644 --- a/internal/service/opensearchserverless/security_policy_data_source.go +++ b/internal/service/opensearchserverless/security_policy_data_source.go @@ -64,7 +64,7 @@ func dataSourceSecurityPolicyRead(ctx context.Context, d *schema.ResourceData, m securityPolicyName := d.Get("name").(string) securityPolicyType := d.Get("type").(string) - securityPolicy, err := FindSecurityPolicyByNameAndType(ctx, conn, securityPolicyName, securityPolicyType) + securityPolicy, err := findSecurityPolicyByNameAndType(ctx, conn, securityPolicyName, securityPolicyType) if err != nil { return sdkdiag.AppendErrorf(diags, "reading OpenSearch Security Policy with name (%s) and type (%s): %s", securityPolicyName, securityPolicyType, err) diff --git a/internal/service/opensearchserverless/service_package_gen.go b/internal/service/opensearchserverless/service_package_gen.go index 96f8ffa50a37..db6b44f59646 100644 --- a/internal/service/opensearchserverless/service_package_gen.go +++ b/internal/service/opensearchserverless/service_package_gen.go @@ -61,6 +61,10 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac Factory: DataSourceSecurityPolicy, TypeName: "aws_opensearchserverless_security_policy", }, + { + Factory: DataSourceVPCEndpoint, + TypeName: "aws_opensearchserverless_vpc_endpoint", + }, } } diff --git a/internal/service/opensearchserverless/vpc_endpoint.go b/internal/service/opensearchserverless/vpc_endpoint.go index 765cd98dd534..07aa1b9f9d0e 100644 --- a/internal/service/opensearchserverless/vpc_endpoint.go +++ b/internal/service/opensearchserverless/vpc_endpoint.go @@ -151,7 +151,7 @@ func (r *resourceVpcEndpoint) Create(ctx context.Context, req resource.CreateReq // The create operation only returns the Id and Name so retrieve the newly // created VPC Endpoint so we can store the possibly computed // security_group_ids in state - vpcEndpoint, err := FindVPCEndpointByID(ctx, conn, aws.ToString(out.CreateVpcEndpointDetail.Id)) + vpcEndpoint, err := findVPCEndpointByID(ctx, conn, aws.ToString(out.CreateVpcEndpointDetail.Id)) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionChecking, ResNameVPCEndpoint, plan.Name.String(), nil), @@ -174,7 +174,7 @@ func (r *resourceVpcEndpoint) Read(ctx context.Context, req resource.ReadRequest return } - out, err := FindVPCEndpointByID(ctx, conn, state.ID.ValueString()) + out, err := findVPCEndpointByID(ctx, conn, state.ID.ValueString()) if tfresource.NotFound(err) { resp.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) resp.State.RemoveResource(ctx) @@ -255,7 +255,7 @@ func (r *resourceVpcEndpoint) Update(ctx context.Context, req resource.UpdateReq // The update operation only returns security_group_ids if those were // changed so retrieve the updated VPC Endpoint so we can store the // actual security_group_ids in state - vpcEndpoint, err := FindVPCEndpointByID(ctx, conn, *out.UpdateVpcEndpointDetail.Id) + vpcEndpoint, err := findVPCEndpointByID(ctx, conn, *out.UpdateVpcEndpointDetail.Id) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionChecking, ResNameVPCEndpoint, plan.Name.String(), nil), @@ -374,7 +374,7 @@ func waitVPCEndpointDeleted(ctx context.Context, conn *opensearchserverless.Clie func statusVPCEndpoint(ctx context.Context, conn *opensearchserverless.Client, id string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - out, err := FindVPCEndpointByID(ctx, conn, id) + out, err := findVPCEndpointByID(ctx, conn, id) if tfresource.NotFound(err) { return nil, "", nil } diff --git a/internal/service/opensearchserverless/vpc_endpoint_data_source.go b/internal/service/opensearchserverless/vpc_endpoint_data_source.go new file mode 100644 index 000000000000..34d4684a466a --- /dev/null +++ b/internal/service/opensearchserverless/vpc_endpoint_data_source.go @@ -0,0 +1,78 @@ +package opensearchserverless + +import ( + "context" + "regexp" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" +) + +// @SDKDataSource("aws_opensearchserverless_vpc_endpoint") +func DataSourceVPCEndpoint() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceVPCEndpointRead, + + Schema: map[string]*schema.Schema{ + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "vpc_endpoint_id": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 255), + validation.StringMatch(regexp.MustCompile(`^vpce-[0-9a-z]*$`), `must start with "vpce-" and can include any lower case letter or number`), + ), + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "security_group_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "subnet_ids": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "vpc_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceVPCEndpointRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchServerlessClient(ctx) + + id := d.Get("vpc_endpoint_id").(string) + vpcEndpoint, err := findVPCEndpointByID(ctx, conn, id) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading OpenSearch Serverless VPC Endpoint with id (%s): %s", id, err) + } + + d.SetId(aws.ToString(vpcEndpoint.Id)) + + createdDate := time.UnixMilli(aws.ToInt64(vpcEndpoint.CreatedDate)) + d.Set("created_date", createdDate.Format(time.RFC3339)) + + d.Set("name", vpcEndpoint.Name) + d.Set("security_group_ids", vpcEndpoint.SecurityGroupIds) + d.Set("subnet_ids", vpcEndpoint.SubnetIds) + d.Set("vpc_id", vpcEndpoint.VpcId) + + return diags +} diff --git a/internal/service/opensearchserverless/vpc_endpoint_data_source_test.go b/internal/service/opensearchserverless/vpc_endpoint_data_source_test.go new file mode 100644 index 000000000000..ef88298008c5 --- /dev/null +++ b/internal/service/opensearchserverless/vpc_endpoint_data_source_test.go @@ -0,0 +1,107 @@ +package opensearchserverless_test + +import ( + "fmt" + "testing" + + sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccOpenSearchServerlessVPCEndpointDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_opensearchserverless_vpc_endpoint.test" + dataSourceName := "data.aws_opensearchserverless_vpc_endpoint.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.OpenSearchServerlessEndpointID) + }, + ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServerlessEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPCEndpointDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVPCEndpointDataSourceConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "security_group_ids.#", resourceName, "security_group_ids.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "subnet_ids.#", resourceName, "subnet_ids.#"), + resource.TestCheckResourceAttrPair(dataSourceName, "vpc_id", resourceName, "vpc_id"), + ), + }, + }, + }) +} + +func testAccVPCEndpointDataSourceConfig_networkingBase(rName string, subnetCount int) string { + return acctest.ConfigCompose( + acctest.ConfigAvailableAZsNoOptInDefaultExclude(), + fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" + enable_dns_hostnames = true + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + count = %[2]d + + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[count.index] + cidr_block = cidrsubnet(aws_vpc.test.cidr_block, 8, count.index) + + tags = { + Name = %[1]q + } +} +`, rName, subnetCount), + ) +} + +func testAccVPCEndpointDataSourceConfig_securityGroupBase(rName string, sgCount int) string { + return acctest.ConfigCompose( + fmt.Sprintf(` +resource "aws_security_group" "test" { + count = %[2]d + name = "%[1]s-${count.index}" + vpc_id = aws_vpc.test.id + + tags = { + Name = %[1]q + } +} +`, rName, sgCount), + ) +} + +func testAccVPCEndpointDataSourceConfig_basic(rName string) string { + return acctest.ConfigCompose( + testAccVPCEndpointDataSourceConfig_networkingBase(rName, 2), + testAccVPCEndpointDataSourceConfig_securityGroupBase(rName, 2), + fmt.Sprintf(` +resource "aws_opensearchserverless_vpc_endpoint" "test" { + name = %[1]q + security_group_ids = aws_security_group.test[*].id + subnet_ids = aws_subnet.test[*].id + vpc_id = aws_vpc.test.id +} + +data "aws_opensearchserverless_vpc_endpoint" "test" { + vpc_endpoint_id = aws_opensearchserverless_vpc_endpoint.test.id +} +`, rName)) +} diff --git a/website/docs/d/opensearchserverless_vpc_endpoint.html.markdown b/website/docs/d/opensearchserverless_vpc_endpoint.html.markdown new file mode 100644 index 000000000000..43f529d0beec --- /dev/null +++ b/website/docs/d/opensearchserverless_vpc_endpoint.html.markdown @@ -0,0 +1,35 @@ +--- +subcategory: "OpenSearch Serverless" +layout: "aws" +page_title: "AWS: aws_opensearchserverless_vpc_endpoint" +description: |- + Terraform data source for managing an AWS OpenSearch Serverless VPC Endpoint. +--- + +# Data Source: aws_opensearchserverless_vpc_endpoint + +Terraform data source for managing an AWS OpenSearch Serverless VPC Endpoint. + +## Example Usage + +```terraform +data "aws_opensearchserverless_vpc_endpoint" "example" { + id = "vpce-829a4487959e2a839" +} +``` + +## Argument Reference + +The following arguments are required: + +* `id` - (Required) The unique identifier of the endpoint. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `created_date` - The date the endpoint was created. +* `name` - The name of the endpoint. +* `security_group_ids` - The IDs of the security groups that define the ports, protocols, and sources for inbound traffic that you are authorizing into your endpoint. +* `subnet_ids` - The IDs of the subnets from which you access OpenSearch Serverless. +* `vpc_id` - The ID of the VPC from which you access OpenSearch Serverless.