Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[data source]: aws_opensearchserverless_collection #32247

Merged
merged 10 commits into from
Jun 28, 2023
3 changes: 3 additions & 0 deletions .changelog/32247.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_opensearchserverless_collection
```
170 changes: 170 additions & 0 deletions internal/service/opensearchserverless/collection_data_source.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
package opensearchserverless

import (
"context"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
awstypes "github.com/aws/aws-sdk-go-v2/service/opensearchserverless/types"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"github.com/hashicorp/terraform-plugin-framework/datasource"
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkDataSource(name="Collection")
func newDataSourceCollection(context.Context) (datasource.DataSourceWithConfigure, error) {
return &dataSourceCollection{}, nil
}

const (
DSNameCollection = "Collection Data Source"
)

type dataSourceCollection struct {
framework.DataSourceWithConfigure
}

func (d *dataSourceCollection) Metadata(_ context.Context, _ datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name
resp.TypeName = "aws_opensearchserverless_collection"
}

func (d *dataSourceCollection) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"arn": framework.ARNAttributeComputedOnly(),
"collection_endpoint": schema.StringAttribute{
Computed: true,
},
"created_date": schema.StringAttribute{
Computed: true,
},
"dashboard_endpoint": schema.StringAttribute{
Computed: true,
},
"description": schema.StringAttribute{
Computed: true,
},
"id": schema.StringAttribute{
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtParent().AtName("name"),
),
stringvalidator.ExactlyOneOf(
path.MatchRelative().AtParent().AtName("name"),
),
},
},
"kms_key_arn": schema.StringAttribute{
Computed: true,
},
"last_modified_date": schema.StringAttribute{
Computed: true,
},
"name": schema.StringAttribute{
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.ConflictsWith(
path.MatchRelative().AtParent().AtName("id"),
),
},
},
names.AttrTags: tftags.TagsAttributeComputedOnly(),
"type": schema.StringAttribute{
Computed: true,
},
},
}
}
func (d *dataSourceCollection) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
conn := d.Meta().OpenSearchServerlessClient(ctx)

var data dataSourceCollectionData
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
if resp.Diagnostics.HasError() {
return
}

var out *awstypes.CollectionDetail

if !data.ID.IsNull() && !data.ID.IsUnknown() {
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),
err.Error(),
)
return
}

out = output
}

if !data.Name.IsNull() && !data.Name.IsUnknown() {
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),
err.Error(),
)
return
}

out = output
}

data.ARN = flex.StringToFramework(ctx, out.Arn)
data.CollectionEndpoint = flex.StringToFramework(ctx, out.CollectionEndpoint)
data.DashboardEndpoint = flex.StringToFramework(ctx, out.DashboardEndpoint)
data.Description = flex.StringToFramework(ctx, out.Description)
data.ID = flex.StringToFramework(ctx, out.Id)
data.KmsKeyARN = flex.StringToFramework(ctx, out.KmsKeyArn)
data.Name = flex.StringToFramework(ctx, out.Name)
data.Type = flex.StringValueToFramework(ctx, out.Type)

createdDate := time.UnixMilli(aws.ToInt64(out.CreatedDate))
data.CreatedDate = flex.StringValueToFramework(ctx, createdDate.Format(time.RFC3339))

lastModifiedDate := time.UnixMilli(aws.ToInt64(out.LastModifiedDate))
data.LastModifiedDate = flex.StringValueToFramework(ctx, lastModifiedDate.Format(time.RFC3339))

ignoreTagsConfig := d.Meta().IgnoreTagsConfig
tags, err := listTags(ctx, conn, aws.ToString(out.Arn))

if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.OpenSearchServerless, create.ErrActionReading, DSNameCollection, data.ID.String(), err),
err.Error(),
)
return
}

tags = tags.IgnoreConfig(ignoreTagsConfig)
data.Tags = flex.FlattenFrameworkStringValueMapLegacy(ctx, tags.Map())

resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
}

type dataSourceCollectionData struct {
ARN types.String `tfsdk:"arn"`
CollectionEndpoint types.String `tfsdk:"collection_endpoint"`
CreatedDate types.String `tfsdk:"created_date"`
DashboardEndpoint types.String `tfsdk:"dashboard_endpoint"`
Description types.String `tfsdk:"description"`
ID types.String `tfsdk:"id"`
KmsKeyARN types.String `tfsdk:"kms_key_arn"`
LastModifiedDate types.String `tfsdk:"last_modified_date"`
Name types.String `tfsdk:"name"`
Tags types.Map `tfsdk:"tags"`
Type types.String `tfsdk:"type"`
}
135 changes: 135 additions & 0 deletions internal/service/opensearchserverless/collection_data_source_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package opensearchserverless_test

import (
"fmt"
"testing"

"github.com/aws/aws-sdk-go-v2/service/opensearchserverless/types"
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 TestAccOpenSearchServerlessCollectionDataSource_basic(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var collection types.CollectionDetail
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
dataSourceName := "data.aws_opensearchserverless_collection.test"
resourceName := "aws_opensearchserverless_collection.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.OpenSearchServerlessEndpointID)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServerlessEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCollectionDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccCollectionDataSourceConfig_basic(rName, "encryption"),
Check: resource.ComposeTestCheckFunc(
testAccCheckCollectionExists(ctx, dataSourceName, &collection),
resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"),
resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "collection_endpoint", resourceName, "collection_endpoint"),
resource.TestCheckResourceAttrPair(dataSourceName, "dashboard_endpoint", resourceName, "dashboard_endpoint"),
resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"),
resource.TestCheckResourceAttrPair(dataSourceName, "kms_key_arn", resourceName, "kms_key_arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "type", resourceName, "type"),
),
},
},
})
}

func TestAccOpenSearchServerlessCollectionDataSource_name(t *testing.T) {
ctx := acctest.Context(t)
if testing.Short() {
t.Skip("skipping long-running test in short mode")
}

var collection types.CollectionDetail
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
dataSourceName := "data.aws_opensearchserverless_collection.test"
resourceName := "aws_opensearchserverless_collection.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.OpenSearchServerlessEndpointID)
testAccPreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServerlessEndpointID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckCollectionDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccCollectionDataSourceConfig_name(rName, "encryption"),
Check: resource.ComposeTestCheckFunc(
testAccCheckCollectionExists(ctx, dataSourceName, &collection),
resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"),
resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "collection_endpoint", resourceName, "collection_endpoint"),
resource.TestCheckResourceAttrPair(dataSourceName, "dashboard_endpoint", resourceName, "dashboard_endpoint"),
resource.TestCheckResourceAttrPair(dataSourceName, "description", resourceName, "description"),
resource.TestCheckResourceAttrPair(dataSourceName, "kms_key_arn", resourceName, "kms_key_arn"),
resource.TestCheckResourceAttrPair(dataSourceName, "type", resourceName, "type"),
),
},
},
})
}

func testAccCollectionDataSourceBaseConfig(rName, policyType string) string {
return fmt.Sprintf(`
resource "aws_opensearchserverless_security_policy" "test" {
name = %[1]q
type = %[2]q
policy = jsonencode({
Rules = [
{
Resource = [
"collection/%[1]s"
],
ResourceType = "collection"
}
],
AWSOwnedKey = true
})
}

resource "aws_opensearchserverless_collection" "test" {
name = %[1]q
depends_on = [aws_opensearchserverless_security_policy.test]
}
`, rName, policyType)
}

func testAccCollectionDataSourceConfig_basic(rName, policyType string) string {
return acctest.ConfigCompose(
testAccCollectionDataSourceBaseConfig(rName, policyType),
`
data "aws_opensearchserverless_collection" "test" {
id = aws_opensearchserverless_collection.test.id
}
`)
}

func testAccCollectionDataSourceConfig_name(rName, policyType string) string {
return acctest.ConfigCompose(
testAccCollectionDataSourceBaseConfig(rName, policyType),
`
data "aws_opensearchserverless_collection" "test" {
name = aws_opensearchserverless_collection.test.name
}
`)
}
24 changes: 24 additions & 0 deletions internal/service/opensearchserverless/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,30 @@ 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) {
in := &opensearchserverless.BatchGetCollectionInput{
Names: []string{name},
}
out, err := conn.BatchGetCollection(ctx, in)
if err != nil {
var nfe *types.ResourceNotFoundException
if errors.As(err, &nfe) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: in,
}
}

return nil, err
}

if out == nil || out.CollectionDetails == nil || len(out.CollectionDetails) == 0 {
return nil, tfresource.NewEmptyResultError(in)
}
johnsonaj marked this conversation as resolved.
Show resolved Hide resolved

return &out.CollectionDetails[0], nil
}

func FindSecurityConfigByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.SecurityConfigDetail, error) {
in := &opensearchserverless.GetSecurityConfigInput{
Id: aws.String(id),
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

42 changes: 42 additions & 0 deletions website/docs/d/opensearchserverless_collection.html.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
---
subcategory: "OpenSearch Serverless"
layout: "aws"
page_title: "AWS: aws_opensearchserverless_collection"
description: |-
Terraform data source for managing an AWS OpenSearch Serverless Collection.
---

# Data Source: aws_opensearchserverless_collection

Terraform data source for managing an AWS OpenSearch Serverless Collection.

## Example Usage

### Basic Usage

```terraform
data "aws_opensearchserverless_collection" "example" {
name = "example"
}
```

## Argument Reference

The following arguments are required:

* `id` - (Required) ID of the collection. Either `id` or `name` must be provided.
* `name` - (Required) Name of the collection. Either `name` or `id` must be provided.

## Attributes Reference

In addition to all arguments above, the following attributes are exported:

* `arn` - Amazon Resource Name (ARN) of the collection.
* `collection_endpoint` - Collection-specific endpoint used to submit index, search, and data upload requests to an OpenSearch Serverless collection.
* `created_date` - Date the Collection was created.
* `dashboard_endpont` - Collection-specific endpoint used to access OpenSearch Dashboards.
* `description` - (Optional) Description of the collection.
johnsonaj marked this conversation as resolved.
Show resolved Hide resolved
* `kms_key_arn` - The ARN of the Amazon Web Services KMS key used to encrypt the collection.
* `last_modified_date` - Date the Collection was last modified.
* `tags` - A map of tags to assign to the collection.
* `type` - Type of collection.