From 4ae2dc871f0fa6d15c72f7e0fe3c392196f18fc0 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Wed, 30 Aug 2023 00:06:38 +0200 Subject: [PATCH 01/35] [WIP] - OpenSearchPackage --- internal/service/opensearch/package.go | 187 +++++++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 internal/service/opensearch/package.go diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go new file mode 100644 index 000000000000..cdd0d15ef313 --- /dev/null +++ b/internal/service/opensearch/package.go @@ -0,0 +1,187 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package opensearch + +import ( + "context" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/opensearchservice" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "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" +) + +// @SDKResource("aws_opensearch_vpc_endpoint") +func ResourcePackage() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: ResourcePackageCreate, + ReadWithoutTimeout: ResourcePackageRead, + UpdateWithoutTimeout: ResourcePackageUpdate, + DeleteWithoutTimeout: ResourcePackageDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(60 * time.Minute), + Update: schema.DefaultTimeout(60 * time.Minute), + Delete: schema.DefaultTimeout(90 * time.Minute), + }, + + Schema: map[string]*schema.Schema{ + "package_id": { + Type: schema.TypeString, + Computed: true, + }, + "package_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "package_description": { + Type: schema.TypeString, + Required: true, + }, + "package_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(opensearchservice.PackageType_Values(), false), + }, + "package_source": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "s3_bucket_name": { + Type: schema.TypeString, + Computed: true, + Required: true, + }, + "s3_key": { + Type: schema.TypeString, + Computed: true, + Required: true, + }, + }, + }, + }, + }, + } +} + +func ResourcePackageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + + input := &opensearchservice.CreatePackageInput{ + PackageDescription: aws.String(d.Get("package_description").(string)), + PackageName: aws.String(d.Get("package_name").(string)), + PackageType: aws.String(d.Get("package_type").(string)), + } + + if v, ok := d.GetOk("package_source"); ok { + input.PackageSource = expandPackageSource(v.([]interface{})[0].(map[string]interface{})) + } + + output, err := conn.CreatePackageWithContext(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating OpenSearch Package: %s", err) + } + + d.SetId(aws.StringValue(output.PackageDetails.PackageID)) + + return append(diags, ResourcePackageRead(ctx, d, meta)...) +} + +func ResourcePackageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + + input := &opensearchservice.DescribePackagesInput{ + Filters: []*opensearchservice.DescribePackagesFilter{ + { + Name: aws.String("PackageID"), + Value: []*string{aws.String(d.Id())}, + }, + }, + } + + output, err := conn.DescribePackagesWithContext(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading OpenSearch Package (%s): %s", d.Id(), err) + } + + if output == nil || len(output.PackageDetailsList) == 0 { + d.SetId("") + return sdkdiag.AppendErrorf(diags, "reading OpenSearch Package (%s): not found", d.Id()) + } + + d.Set("package_id", aws.StringValue(output.PackageDetailsList[0].PackageID)) + d.Set("package_name", aws.StringValue(output.PackageDetailsList[0].PackageName)) + d.Set("package_description", aws.StringValue(output.PackageDetailsList[0].PackageDescription)) + d.Set("package_type", aws.StringValue(output.PackageDetailsList[0].PackageType)) + + return diags +} + +func ResourcePackageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + + input := &opensearchservice.UpdatePackageInput{ + PackageID: aws.String(d.Id()), + PackageDescription: aws.String(d.Get("package_description").(string)), + PackageSource: expandPackageSource(d.Get("package_source").([]interface{})[0].(map[string]interface{})), + } + + _, err := conn.UpdatePackageWithContext(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "updating OpenSearch Package (%s): %s", d.Id(), err) + } + + return append(diags, ResourcePackageRead(ctx, d, meta)...) +} + +func ResourcePackageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + + log.Printf("[DEBUG] Deleting OpenSearch Package: %s", d.Id()) + _, err := conn.DeletePackageWithContext(ctx, &opensearchservice.DeletePackageInput{ + PackageID: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting OpenSearch Package (%s): %s", d.Id(), err) + } + + return diags +} + +func expandPackageSource(v interface{}) *opensearchservice.PackageSource { + if v == nil { + return nil + } + + return &opensearchservice.PackageSource{ + S3BucketName: aws.String(v.(map[string]interface{})["s3_bucket_name"].(string)), + S3Key: aws.String(v.(map[string]interface{})["s3_key"].(string)), + } +} From 584c2f4fc95f894896d24f56f4481dd34984421f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 10:50:08 +0200 Subject: [PATCH 02/35] chore: add `available_package_version` --- internal/service/opensearch/package.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index cdd0d15ef313..cdeccb3b7537 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -37,6 +37,10 @@ func ResourcePackage() *schema.Resource { }, Schema: map[string]*schema.Schema{ + "available_package_version": { + Type: schema.TypeString, + Computed: true, + }, "package_id": { Type: schema.TypeString, Computed: true, @@ -64,12 +68,10 @@ func ResourcePackage() *schema.Resource { Schema: map[string]*schema.Schema{ "s3_bucket_name": { Type: schema.TypeString, - Computed: true, Required: true, }, "s3_key": { Type: schema.TypeString, - Computed: true, Required: true, }, }, @@ -132,6 +134,7 @@ func ResourcePackageRead(ctx context.Context, d *schema.ResourceData, meta inter d.Set("package_name", aws.StringValue(output.PackageDetailsList[0].PackageName)) d.Set("package_description", aws.StringValue(output.PackageDetailsList[0].PackageDescription)) d.Set("package_type", aws.StringValue(output.PackageDetailsList[0].PackageType)) + d.Set("available_package_version", aws.StringValue(output.PackageDetailsList[0].AvailablePackageVersion) return diags } From 7c467ce0c0629c02d7a93c64aa84bf79089d504a Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 11:25:04 +0200 Subject: [PATCH 03/35] chore: change package description to optional and fix sdkresource annotation --- internal/service/opensearch/package.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index cdeccb3b7537..61b9c40effc8 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -18,7 +18,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" ) -// @SDKResource("aws_opensearch_vpc_endpoint") +// @SDKResource("aws_opensearch_package") func ResourcePackage() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: ResourcePackageCreate, @@ -52,7 +52,7 @@ func ResourcePackage() *schema.Resource { }, "package_description": { Type: schema.TypeString, - Required: true, + Optional: true, }, "package_type": { Type: schema.TypeString, @@ -134,7 +134,7 @@ func ResourcePackageRead(ctx context.Context, d *schema.ResourceData, meta inter d.Set("package_name", aws.StringValue(output.PackageDetailsList[0].PackageName)) d.Set("package_description", aws.StringValue(output.PackageDetailsList[0].PackageDescription)) d.Set("package_type", aws.StringValue(output.PackageDetailsList[0].PackageType)) - d.Set("available_package_version", aws.StringValue(output.PackageDetailsList[0].AvailablePackageVersion) + d.Set("available_package_version", aws.StringValue(output.PackageDetailsList[0].AvailablePackageVersion)) return diags } From 61a9f93d99e440a32867847af5b236bfb1d781a1 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:35:14 +0200 Subject: [PATCH 04/35] feat: add `aws_opensearch_package_association` --- .../service/opensearch/package_association.go | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 internal/service/opensearch/package_association.go diff --git a/internal/service/opensearch/package_association.go b/internal/service/opensearch/package_association.go new file mode 100644 index 000000000000..8741f9d0a510 --- /dev/null +++ b/internal/service/opensearch/package_association.go @@ -0,0 +1,83 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package opensearch + +import ( + "context" + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/opensearchservice" + "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "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" +) + +// @SDKResource("aws_opensearch_package_association") +func ResourcePackageAssociation() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: ResourcePackageAssociationCreate, + DeleteWithoutTimeout: ResourcePackageAssociationDelete, + + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + Schema: map[string]*schema.Schema{ + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "package_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + } +} + +func ResourcePackageAssociationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + + input := &opensearchservice.AssociatePackageInput{ + DomainName: aws.String(d.Get("domain_name").(string)), + PackageID: aws.String(d.Get("package_id").(string)), + } + + output, err := conn.AssociatePackageWithContext(ctx, input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "associating OpenSearch package: %s", err) + } + + d.SetId(fmt.Sprintf("package-association:%s-%s", aws.StringValue(output.DomainPackageDetails.DomainName), aws.StringValue(output.DomainPackageDetails.PackageID))) + + return diags +} + +func ResourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + + log.Printf("[DEBUG] Deleting OpenSearch Package: %s", d.Id()) + _, err := conn.DissociatePackageWithContext(ctx, &opensearchservice.DissociatePackageInput{ + PackageID: aws.String(d.Id()), + }) + + if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "dissociating OpenSearch Package (%s): %s", d.Id(), err) + } + + return diags +} From 1c4b60afe404b12b338aac85bffa7758acc87dcf Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:35:37 +0200 Subject: [PATCH 05/35] chore: remove timeouts from `aws_opensearch_package` --- internal/service/opensearch/package.go | 7 ------- 1 file changed, 7 deletions(-) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index 61b9c40effc8..6ff0330c9afb 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -6,7 +6,6 @@ package opensearch import ( "context" "log" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/opensearchservice" @@ -30,12 +29,6 @@ func ResourcePackage() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, - Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(60 * time.Minute), - Update: schema.DefaultTimeout(60 * time.Minute), - Delete: schema.DefaultTimeout(90 * time.Minute), - }, - Schema: map[string]*schema.Schema{ "available_package_version": { Type: schema.TypeString, From 1bab192f890b89cedded9079e823d0d3e8af793f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:46:13 +0200 Subject: [PATCH 06/35] chore: add ForceNews to `package_source` --- internal/service/opensearch/package.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index 6ff0330c9afb..054e0ce6be09 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -56,16 +56,19 @@ func ResourcePackage() *schema.Resource { "package_source": { Type: schema.TypeList, Required: true, + ForceNew: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "s3_bucket_name": { Type: schema.TypeString, Required: true, + ForceNew: true, }, "s3_key": { Type: schema.TypeString, Required: true, + ForceNew: true, }, }, }, From c1166bc6fc417edc1b0f5dccabaaace90b10a3e5 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:46:16 +0200 Subject: [PATCH 07/35] Create opensearch_package.html.markdown --- .../docs/r/opensearch_package.html.markdown | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 website/docs/r/opensearch_package.html.markdown diff --git a/website/docs/r/opensearch_package.html.markdown b/website/docs/r/opensearch_package.html.markdown new file mode 100644 index 000000000000..97ee4547e100 --- /dev/null +++ b/website/docs/r/opensearch_package.html.markdown @@ -0,0 +1,75 @@ +--- +subcategory: "OpenSearch" +layout: "aws" +page_title: "AWS: aws_opensearch_package" +description: |- + Terraform resource for managing an AWS OpenSearch package. +--- + +# Resource: aws_opensearch_package + +Manages an AWS Opensearch Package. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_s3_bucket" "my_opensearch_packages" { + bucket = "my-opensearch-packages" +} + +resource "aws_s3_object" "example" { + bucket = aws_s3_bucket.my_opensearch_packages.bucket + key = "example.txt" + source = "./example.txt" + etag = filemd5("./example.txt") +} + +resource "aws_opensearch_package" "example" { + package_name = "example-txt" + package_source { + s3_bucket_name = aws_s3_bucket.my_opensearch_packages.bucket + s3_key = aws_s3_object.example.key + } + package_type = "TXT-DICTIONARY" +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `package_name` - (Required, Forces new resource) Unique name for the package. +* `package_type` - (Required, Forces new resource) The type of package. +* `package_source` - (Required, Forces new resource) Configuration block for the package source options. +* `package_description` - (Optional, Forces new resource) Description of the package. + +### package_source + +* `s3_bucket_name` - (Required, Forces new resource) The name of the Amazon S3 bucket containing the package. +* `s3_key` - (Required, Forces new resource) Key (file name) of the package. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `id` - The Id of the package. +* `available_package_version` - The current version of the package. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Outbound Packages using the Package ID. For example: + +```terraform +import { + to = aws_opensearch_package.foo + id = "package-id" +} +``` + +Using `terraform import`, import AWS Opensearch Packages using the Package ID. For example: + +```console +% terraform import aws_opensearch_package.foo package-id +``` From 933aef354969328ab59de1d21053682f023572aa Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:51:08 +0200 Subject: [PATCH 08/35] chore: remove `Outbound` --- website/docs/r/opensearch_package.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/opensearch_package.html.markdown b/website/docs/r/opensearch_package.html.markdown index 97ee4547e100..1770fdfebd05 100644 --- a/website/docs/r/opensearch_package.html.markdown +++ b/website/docs/r/opensearch_package.html.markdown @@ -59,7 +59,7 @@ This resource exports the following attributes in addition to the arguments abov ## Import -In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Outbound Packages using the Package ID. For example: +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Packages using the Package ID. For example: ```terraform import { From e6457bbf01a750c517bfe85ca35691278ae44b8a Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:52:01 +0200 Subject: [PATCH 09/35] Create opensearch_package_association.html.markdown --- ...ensearch_package_association.html.markdown | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 website/docs/r/opensearch_package_association.html.markdown diff --git a/website/docs/r/opensearch_package_association.html.markdown b/website/docs/r/opensearch_package_association.html.markdown new file mode 100644 index 000000000000..6627bf95603f --- /dev/null +++ b/website/docs/r/opensearch_package_association.html.markdown @@ -0,0 +1,70 @@ +--- +subcategory: "OpenSearch" +layout: "aws" +page_title: "AWS: aws_opensearch_package_association" +description: |- + Terraform resource for managing an AWS OpenSearch package association. +--- + +# Resource: aws_opensearch_package_association + +Manages an AWS Opensearch Package Association. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_opensearch_domain" "my_domain" { + domain_name = "my-opensearch-domain" + engine_version = "Elasticsearch_7.10" + + cluster_config { + instance_type = "r4.large.search" + } +} + +resource "aws_opensearch_package" "example" { + package_name = "example-txt" + package_source { + s3_bucket_name = aws_s3_bucket.my_opensearch_packages.bucket + s3_key = aws_s3_object.example.key + } + package_type = "TXT-DICTIONARY" +} + +resource "aws_opensearch_package_association" "example" { + package_id = aws_opensearch_package.example.id + domain_name = aws_opensearch_domain.my_domain.domain_name +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `package_id` - (Required, Forces new resource) Internal ID of the package to associate with a domain. +* `domain_name` - (Required, Forces new resource) Name of the domain to associate the package with. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `id` - The Id of the package association. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Package Associations using the Package Association ID. For example: + +```terraform +import { + to = aws_opensearch_package_association.foo + id = "package-association-id" +} +``` + +Using `terraform import`, import AWS Opensearch Package Associations using the Package Association ID. For example: + +```console +% terraform import aws_opensearch_package_association.foo package-association-id +``` From ed40fdcbe3d1cd6d952fb99939884cbbed29892e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 15:52:39 +0200 Subject: [PATCH 10/35] Create 33227.txt --- .changelog/33227.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/33227.txt diff --git a/.changelog/33227.txt b/.changelog/33227.txt new file mode 100644 index 000000000000..e46d348e9463 --- /dev/null +++ b/.changelog/33227.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +aws_opensearch_package +``` + +```release-note:new-resource +aws_opensearch_package_association +``` From 1b5dfd2711a463e70d08a4fd0d7cbc81af080ba3 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:19:28 +0200 Subject: [PATCH 11/35] Create package_test.go --- internal/service/opensearch/package_test.go | 98 +++++++++++++++++++++ 1 file changed, 98 insertions(+) create mode 100644 internal/service/opensearch/package_test.go diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go new file mode 100644 index 000000000000..9be031011d3b --- /dev/null +++ b/internal/service/opensearch/package_test.go @@ -0,0 +1,98 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package opensearch_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/opensearchservice" + 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" + tfopensearch "github.com/hashicorp/terraform-provider-aws/internal/service/opensearch" +) + +func TestAccOpenSearchPackage_basic(t *testing.T) { + ctx := acctest.Context(t) + var domain opensearchservice.DomainStatus + ri := sdkacctest.RandString(10) + name := fmt.Sprintf("tf-test-%s", ri) + resourceName := "aws_opensearch_package.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPackageConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_1", &domain), + resource.TestCheckResourceAttr(resourceName, "package_name", "example"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccOpenSearchPackage_disappears(t *testing.T) { + ctx := acctest.Context(t) + var domain opensearchservice.DomainStatus + ri := sdkacctest.RandString(10) + name := fmt.Sprintf("tf-test-%s", ri) + resourceName := "aws_opensearch_package.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPackageConfig(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_1", &domain), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccPackageConfig(name string) string { + return fmt.Sprintf(` +resource "local_file" "test" { + content = "test" + filename = "${path.module}/test.txt" +} + +resource "aws_s3_bucket" "opensearch_packages" { + bucket = "%s-1" +} + +resource "aws_s3_object" "example_txt" { + bucket = aws_s3_bucket.opensearch_packages.bucket + key = "example.txt" + source = local_file.test.filename + etag = filemd5(local_file.test.filename) +} + +resource "aws_opensearch_package" "example_txt" { + package_name = "example" + package_source { + s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket + s3_key = aws_s3_object.example_txt.key + } + package_type = "TXT-DICTIONARY" +} +`, name) +} From 13b137bbd229aa4f5c8fc33fbd5e3de43dbd596f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:24:27 +0200 Subject: [PATCH 12/35] chore: temp implement read --- internal/service/opensearch/package_association.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/internal/service/opensearch/package_association.go b/internal/service/opensearch/package_association.go index 8741f9d0a510..c76532da9ae1 100644 --- a/internal/service/opensearch/package_association.go +++ b/internal/service/opensearch/package_association.go @@ -21,6 +21,7 @@ import ( func ResourcePackageAssociation() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: ResourcePackageAssociationCreate, + ReadWithoutTimeout: ResourcePackageAssociationRead, DeleteWithoutTimeout: ResourcePackageAssociationDelete, Importer: &schema.ResourceImporter{ @@ -62,6 +63,14 @@ func ResourcePackageAssociationCreate(ctx context.Context, d *schema.ResourceDat return diags } +func ResourcePackageAssociationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + + // TODO: Implement read? + + return diags +} + func ResourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) From 0829b91f49f94226a703678db609c1a70d45bfc6 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:24:30 +0200 Subject: [PATCH 13/35] Create example-opensearch-custom-package.txt --- .../test-fixtures/example-opensearch-custom-package.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt diff --git a/internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt b/internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt new file mode 100644 index 000000000000..e69de29bb2d1 From 67a8e88481ab55b9833edacc277621c11b21915e Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:24:42 +0200 Subject: [PATCH 14/35] chore: use a test fixture for the custom opensearch packages --- internal/service/opensearch/package_test.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 9be031011d3b..75caa3283849 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -70,20 +70,15 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { func testAccPackageConfig(name string) string { return fmt.Sprintf(` -resource "local_file" "test" { - content = "test" - filename = "${path.module}/test.txt" -} - resource "aws_s3_bucket" "opensearch_packages" { bucket = "%s-1" } resource "aws_s3_object" "example_txt" { bucket = aws_s3_bucket.opensearch_packages.bucket - key = "example.txt" - source = local_file.test.filename - etag = filemd5(local_file.test.filename) + key = "example-opensearch-custom-package.txt" + source = "./test-fixtures/example-opensearch-custom-package.txt" + etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") } resource "aws_opensearch_package" "example_txt" { From 247bc965f8d665251a064dc00af2c5e5bff1f6e8 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:25:10 +0200 Subject: [PATCH 15/35] chore: remove domain check on custom package test --- internal/service/opensearch/package_test.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 75caa3283849..e2a55d356f40 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -16,7 +16,6 @@ import ( func TestAccOpenSearchPackage_basic(t *testing.T) { ctx := acctest.Context(t) - var domain opensearchservice.DomainStatus ri := sdkacctest.RandString(10) name := fmt.Sprintf("tf-test-%s", ri) resourceName := "aws_opensearch_package.test" @@ -30,7 +29,6 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { { Config: testAccPackageConfig(name), Check: resource.ComposeTestCheckFunc( - testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_1", &domain), resource.TestCheckResourceAttr(resourceName, "package_name", "example"), ), }, @@ -45,7 +43,6 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { func TestAccOpenSearchPackage_disappears(t *testing.T) { ctx := acctest.Context(t) - var domain opensearchservice.DomainStatus ri := sdkacctest.RandString(10) name := fmt.Sprintf("tf-test-%s", ri) resourceName := "aws_opensearch_package.test" @@ -59,7 +56,6 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { { Config: testAccPackageConfig(name), Check: resource.ComposeTestCheckFunc( - testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_1", &domain), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), ), ExpectNonEmptyPlan: true, From dc6c80c5cd91f4439f24fa134dc38ac5c2c1a845 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:26:42 +0200 Subject: [PATCH 16/35] chore: name aws_opensearch_package test --- internal/service/opensearch/package_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index e2a55d356f40..03d001927e5b 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -77,7 +77,7 @@ resource "aws_s3_object" "example_txt" { etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") } -resource "aws_opensearch_package" "example_txt" { +resource "aws_opensearch_package" "test" { package_name = "example" package_source { s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket From 279673a9c49c0c7bd90985b66898bb428166af81 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Thu, 7 Sep 2023 16:35:13 +0200 Subject: [PATCH 17/35] chore: ensure unique package names are used --- internal/service/opensearch/package_test.go | 13 ++++++++----- .../example-opensearch-custom-package.txt | 4 ++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 03d001927e5b..f4144eefac57 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -29,13 +29,16 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { { Config: testAccPackageConfig(name), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "package_name", "example"), + resource.TestCheckResourceAttr(resourceName, "package_name", name), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "package_source", // This isn't returned by the API + }, }, }, }) @@ -67,23 +70,23 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { func testAccPackageConfig(name string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "opensearch_packages" { - bucket = "%s-1" + bucket = "%s" } resource "aws_s3_object" "example_txt" { bucket = aws_s3_bucket.opensearch_packages.bucket - key = "example-opensearch-custom-package.txt" + key = "%s" source = "./test-fixtures/example-opensearch-custom-package.txt" etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") } resource "aws_opensearch_package" "test" { - package_name = "example" + package_name = "%s" package_source { s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket s3_key = aws_s3_object.example_txt.key } package_type = "TXT-DICTIONARY" } -`, name) +`, name, name, name) } diff --git a/internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt b/internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt index e69de29bb2d1..8249df1efa47 100644 --- a/internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt +++ b/internal/service/opensearch/test-fixtures/example-opensearch-custom-package.txt @@ -0,0 +1,4 @@ +danish, croissant, pastry +ice cream, gelato, frozen custard +sneaker, tennis shoe, running shoe +basketball shoe, hightop From a62c474f0da05ea394c6f71512394ea15acb3b2f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 21:39:16 +0200 Subject: [PATCH 18/35] Create package_association_test.go --- .../opensearch/package_association_test.go | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 internal/service/opensearch/package_association_test.go diff --git a/internal/service/opensearch/package_association_test.go b/internal/service/opensearch/package_association_test.go new file mode 100644 index 000000000000..288b80ce5375 --- /dev/null +++ b/internal/service/opensearch/package_association_test.go @@ -0,0 +1,110 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package opensearch_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/opensearchservice" + 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" + tfopensearch "github.com/hashicorp/terraform-provider-aws/internal/service/opensearch" +) + +func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { + ctx := acctest.Context(t) + ri := sdkacctest.RandString(10) + name := fmt.Sprintf("tf-test-%s", ri) + resourceName := "aws_opensearch_package_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPackageAssociationConfig(name), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "package_name", name), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "package_source", // This isn't returned by the API + }, + }, + }, + }) +} + +func TestAccOpenSearchPackageAssociation_disappears(t *testing.T) { + ctx := acctest.Context(t) + ri := sdkacctest.RandString(10) + name := fmt.Sprintf("tf-test-%s", ri) + resourceName := "aws_opensearch_package_association.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccPackageAssociationConfig(name), + Check: resource.ComposeTestCheckFunc( + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccPackageAssociationConfig(name string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "opensearch_packages" { + bucket = "%s" +} + +resource "aws_s3_object" "example_txt" { + bucket = aws_s3_bucket.opensearch_packages.bucket + key = "%s" + source = "./test-fixtures/example-opensearch-custom-package.txt" + etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") +} + +resource "aws_opensearch_package" "test" { + package_name = "%s" + package_source { + s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket + s3_key = aws_s3_object.example_txt.key + } + package_type = "TXT-DICTIONARY" +} + +resource "aws_opensearch_domain" "test" { + domain_name = "%s" + + cluster_config { + instance_type = "t3.small.search" # supported in both aws and aws-us-gov + } + + ebs_options { + ebs_enabled = true + volume_size = 10 + } +} + +resource "aws_opensearch_package_association" "test" { + package_id = aws_opensearch_package.test.id + domain_name = aws_opensearch_domain.test.domain_name +} +`, name, name, name, name) +} From 566ef5c45096f13c645c71af8c58d53d2ab5453f Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 21:39:28 +0200 Subject: [PATCH 19/35] chore: implement `ResourcePackageAssociationRead` --- .../service/opensearch/package_association.go | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/internal/service/opensearch/package_association.go b/internal/service/opensearch/package_association.go index c76532da9ae1..2a4acbb776d6 100644 --- a/internal/service/opensearch/package_association.go +++ b/internal/service/opensearch/package_association.go @@ -39,6 +39,10 @@ func ResourcePackageAssociation() *schema.Resource { Required: true, ForceNew: true, }, + "reference_path": { + Type: schema.TypeString, + Computed: true, + }, }, } } @@ -65,9 +69,19 @@ func ResourcePackageAssociationCreate(ctx context.Context, d *schema.ResourceDat func ResourcePackageAssociationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - // TODO: Implement read? + var domainName = d.Get("domain_name").(string) + var packageID = d.Get("package_id").(string) + + output, err := getAssociatedDomainPackage(ctx, domainName, packageID, conn) + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing OpenSearch Package for domain (%s): %s", domainName, err) + } + d.Set("package_id", aws.StringValue(output.PackageID)) + d.Set("package_type", aws.StringValue(output.ReferencePath)) + d.Set("available_package_version", aws.StringValue(output.PackageVersion)) return diags } @@ -90,3 +104,28 @@ func ResourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceDat return diags } + +func getAssociatedDomainPackage(ctx context.Context, domainID, packageID string, conn *opensearchservice.OpenSearchService) (*opensearchservice.DomainPackageDetails, error) { + input := &opensearchservice.ListPackagesForDomainInput{ + DomainName: aws.String(domainID), + } + for { + resp, err := conn.ListPackagesForDomainWithContext(ctx, input) + if err != nil { + return nil, err + } + if len(resp.DomainPackageDetailsList) == 0 { + return nil, fmt.Errorf("no packages found for domain %s", domainID) + } + for _, domainPackageDetails := range resp.DomainPackageDetailsList { + if aws.StringValue(domainPackageDetails.PackageID) == packageID { + return domainPackageDetails, nil + } + } + if resp.NextToken == nil { + break + } + input.NextToken = resp.NextToken + } + return nil, nil +} From 1d4a9f3b0c3122a4447df464c4d5d2c98b409541 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 21:46:42 +0200 Subject: [PATCH 20/35] chore: add resource attr pair checks --- internal/service/opensearch/package_association_test.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/internal/service/opensearch/package_association_test.go b/internal/service/opensearch/package_association_test.go index 288b80ce5375..69cb231b0ef1 100644 --- a/internal/service/opensearch/package_association_test.go +++ b/internal/service/opensearch/package_association_test.go @@ -19,6 +19,8 @@ func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { ri := sdkacctest.RandString(10) name := fmt.Sprintf("tf-test-%s", ri) resourceName := "aws_opensearch_package_association.test" + packageResourceName := "aws_opensearch_package.test" + domainResourceName := "aws_opensearch_domain.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, @@ -30,6 +32,8 @@ func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { Config: testAccPackageAssociationConfig(name), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr(resourceName, "package_name", name), + resource.TestCheckResourceAttrPair(resourceName, "package_id", packageResourceName, "id"), + resource.TestCheckResourceAttrPair(resourceName, "domain_name", domainResourceName, "domain_name"), ), }, { From 75ec8b9a29a2e023b2c8cff469839cdb5171bd30 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 21:51:07 +0200 Subject: [PATCH 21/35] chore: fix `aws_opensearch_package_association` import example --- website/docs/r/opensearch_package_association.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/opensearch_package_association.html.markdown b/website/docs/r/opensearch_package_association.html.markdown index 6627bf95603f..b93e7db01bfc 100644 --- a/website/docs/r/opensearch_package_association.html.markdown +++ b/website/docs/r/opensearch_package_association.html.markdown @@ -66,5 +66,5 @@ import { Using `terraform import`, import AWS Opensearch Package Associations using the Package Association ID. For example: ```console -% terraform import aws_opensearch_package_association.foo package-association-id +% terraform import aws_opensearch_package_association.foo package-association:- ``` From 10e8e96be7ee79a0c6146e0ff5e7538d90c615c1 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 22:04:13 +0200 Subject: [PATCH 22/35] chore: make gen --- internal/service/opensearch/service_package_gen.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/service/opensearch/service_package_gen.go b/internal/service/opensearch/service_package_gen.go index 96f66fa6e58a..0490d77a2494 100644 --- a/internal/service/opensearch/service_package_gen.go +++ b/internal/service/opensearch/service_package_gen.go @@ -58,6 +58,14 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka Factory: ResourceOutboundConnection, TypeName: "aws_opensearch_outbound_connection", }, + { + Factory: ResourcePackage, + TypeName: "aws_opensearch_package", + }, + { + Factory: ResourcePackageAssociation, + TypeName: "aws_opensearch_package_association", + }, } } From a6780a9839a3b82bf15b62183bdaac8d807d0158 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 22:09:18 +0200 Subject: [PATCH 23/35] chore: rebase and make gen --- internal/service/opensearch/service_package_gen.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/internal/service/opensearch/service_package_gen.go b/internal/service/opensearch/service_package_gen.go index be066c6c9dec..a10a8bd9ebe6 100644 --- a/internal/service/opensearch/service_package_gen.go +++ b/internal/service/opensearch/service_package_gen.go @@ -58,6 +58,14 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka Factory: ResourceOutboundConnection, TypeName: "aws_opensearch_outbound_connection", }, + { + Factory: ResourcePackage, + TypeName: "aws_opensearch_package", + }, + { + Factory: ResourcePackageAssociation, + TypeName: "aws_opensearch_package_association", + }, { Factory: ResourceVPCEndpoint, TypeName: "aws_opensearch_vpc_endpoint", From 61f2826c953a0f0047f7de767793c24323797e21 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 22:22:43 +0200 Subject: [PATCH 24/35] chore: add testAccCheckPackageDestroy --- internal/service/opensearch/find.go | 29 +++++++++++++++++++ internal/service/opensearch/package_test.go | 32 +++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/internal/service/opensearch/find.go b/internal/service/opensearch/find.go index 026019a345bc..17d75cc5bfe6 100644 --- a/internal/service/opensearch/find.go +++ b/internal/service/opensearch/find.go @@ -36,3 +36,32 @@ func FindDomainByName(ctx context.Context, conn *opensearchservice.OpenSearchSer return output.DomainStatus, nil } + +func FindPackageByName(ctx context.Context, conn *opensearchservice.OpenSearchService, id string) (*opensearchservice.PackageDetails, error) { + input := &opensearchservice.DescribePackagesInput{ + Filters: []*opensearchservice.DescribePackagesFilter{ + { + Name: aws.String("PackageID"), + Value: []*string{aws.String(id)}, + }, + }, + } + + output, err := conn.DescribePackagesWithContext(ctx, input) + if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || len(output.PackageDetailsList) == 0 { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.PackageDetailsList[0], nil +} diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index f4144eefac57..1356a4f02076 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -4,14 +4,18 @@ package opensearch_test import ( + "context" "fmt" "testing" "github.com/aws/aws-sdk-go/service/opensearchservice" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" tfopensearch "github.com/hashicorp/terraform-provider-aws/internal/service/opensearch" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccOpenSearchPackage_basic(t *testing.T) { @@ -24,7 +28,7 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckDomainDestroy(ctx), + CheckDestroy: testAccCheckPackageDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccPackageConfig(name), @@ -54,7 +58,7 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckDomainDestroy(ctx), + CheckDestroy: testAccCheckPackageDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccPackageConfig(name), @@ -90,3 +94,27 @@ resource "aws_opensearch_package" "test" { } `, name, name, name) } + +func testAccCheckPackageDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_opensearch_domain" { + continue + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchConn(ctx) + _, err := tfopensearch.FindPackageByName(ctx, conn, rs.Primary.Attributes["package_id"]) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("OpenSearch package %s still exists", rs.Primary.ID) + } + return nil + } +} From 91e7e2cc8bd49e4eb494b49a88601a7d5fa511b6 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 22:28:06 +0200 Subject: [PATCH 25/35] chore: run `make testacc-lint-fix` --- internal/service/opensearch/package_association_test.go | 8 ++++---- internal/service/opensearch/package_test.go | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/internal/service/opensearch/package_association_test.go b/internal/service/opensearch/package_association_test.go index 69cb231b0ef1..590c7636299e 100644 --- a/internal/service/opensearch/package_association_test.go +++ b/internal/service/opensearch/package_association_test.go @@ -81,25 +81,25 @@ resource "aws_s3_object" "example_txt" { bucket = aws_s3_bucket.opensearch_packages.bucket key = "%s" source = "./test-fixtures/example-opensearch-custom-package.txt" - etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") + etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") } resource "aws_opensearch_package" "test" { package_name = "%s" package_source { s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket - s3_key = aws_s3_object.example_txt.key + s3_key = aws_s3_object.example_txt.key } package_type = "TXT-DICTIONARY" } resource "aws_opensearch_domain" "test" { domain_name = "%s" - + cluster_config { instance_type = "t3.small.search" # supported in both aws and aws-us-gov } - + ebs_options { ebs_enabled = true volume_size = 10 diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 1356a4f02076..b4aca97ab595 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -81,14 +81,14 @@ resource "aws_s3_object" "example_txt" { bucket = aws_s3_bucket.opensearch_packages.bucket key = "%s" source = "./test-fixtures/example-opensearch-custom-package.txt" - etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") + etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") } resource "aws_opensearch_package" "test" { package_name = "%s" package_source { s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket - s3_key = aws_s3_object.example_txt.key + s3_key = aws_s3_object.example_txt.key } package_type = "TXT-DICTIONARY" } From 35c599dfb98de1ef9ccd3e4e7467e8f62e58fe97 Mon Sep 17 00:00:00 2001 From: Bruno Schaatsbergen Date: Mon, 18 Sep 2023 22:30:15 +0200 Subject: [PATCH 26/35] chore: fix extraneous set --- internal/service/opensearch/package.go | 10 +++++----- internal/service/opensearch/package_association.go | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index 054e0ce6be09..9d67ae8b0ff7 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -126,11 +126,11 @@ func ResourcePackageRead(ctx context.Context, d *schema.ResourceData, meta inter return sdkdiag.AppendErrorf(diags, "reading OpenSearch Package (%s): not found", d.Id()) } - d.Set("package_id", aws.StringValue(output.PackageDetailsList[0].PackageID)) - d.Set("package_name", aws.StringValue(output.PackageDetailsList[0].PackageName)) - d.Set("package_description", aws.StringValue(output.PackageDetailsList[0].PackageDescription)) - d.Set("package_type", aws.StringValue(output.PackageDetailsList[0].PackageType)) - d.Set("available_package_version", aws.StringValue(output.PackageDetailsList[0].AvailablePackageVersion)) + d.Set("package_id", output.PackageDetailsList[0].PackageID) + d.Set("package_name", output.PackageDetailsList[0].PackageName) + d.Set("package_description", output.PackageDetailsList[0].PackageDescription) + d.Set("package_type", output.PackageDetailsList[0].PackageType) + d.Set("available_package_version", output.PackageDetailsList[0].AvailablePackageVersion) return diags } diff --git a/internal/service/opensearch/package_association.go b/internal/service/opensearch/package_association.go index 2a4acbb776d6..062bc04f82a8 100644 --- a/internal/service/opensearch/package_association.go +++ b/internal/service/opensearch/package_association.go @@ -79,9 +79,9 @@ func ResourcePackageAssociationRead(ctx context.Context, d *schema.ResourceData, return sdkdiag.AppendErrorf(diags, "listing OpenSearch Package for domain (%s): %s", domainName, err) } - d.Set("package_id", aws.StringValue(output.PackageID)) - d.Set("package_type", aws.StringValue(output.ReferencePath)) - d.Set("available_package_version", aws.StringValue(output.PackageVersion)) + d.Set("package_id", output.PackageID) + d.Set("package_type", output.ReferencePath) + d.Set("available_package_version", output.PackageVersion) return diags } From 2f64e3c66fe2d3fe4dd45e62d1d4a1c4417eebbe Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 07:58:27 -0400 Subject: [PATCH 27/35] Fix terrafmt documentation errors. --- website/docs/r/opensearch_package.html.markdown | 4 ++-- website/docs/r/opensearch_package_association.html.markdown | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/opensearch_package.html.markdown b/website/docs/r/opensearch_package.html.markdown index 1770fdfebd05..a89a270ccce1 100644 --- a/website/docs/r/opensearch_package.html.markdown +++ b/website/docs/r/opensearch_package.html.markdown @@ -23,14 +23,14 @@ resource "aws_s3_object" "example" { bucket = aws_s3_bucket.my_opensearch_packages.bucket key = "example.txt" source = "./example.txt" - etag = filemd5("./example.txt") + etag = filemd5("./example.txt") } resource "aws_opensearch_package" "example" { package_name = "example-txt" package_source { s3_bucket_name = aws_s3_bucket.my_opensearch_packages.bucket - s3_key = aws_s3_object.example.key + s3_key = aws_s3_object.example.key } package_type = "TXT-DICTIONARY" } diff --git a/website/docs/r/opensearch_package_association.html.markdown b/website/docs/r/opensearch_package_association.html.markdown index b93e7db01bfc..d644bc5b2917 100644 --- a/website/docs/r/opensearch_package_association.html.markdown +++ b/website/docs/r/opensearch_package_association.html.markdown @@ -28,13 +28,13 @@ resource "aws_opensearch_package" "example" { package_name = "example-txt" package_source { s3_bucket_name = aws_s3_bucket.my_opensearch_packages.bucket - s3_key = aws_s3_object.example.key + s3_key = aws_s3_object.example.key } package_type = "TXT-DICTIONARY" } resource "aws_opensearch_package_association" "example" { - package_id = aws_opensearch_package.example.id + package_id = aws_opensearch_package.example.id domain_name = aws_opensearch_domain.my_domain.domain_name } ``` From df91e0de20b282bbe8bf03e607dc8b1993429f2c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 07:59:36 -0400 Subject: [PATCH 28/35] r/aws_opensearch_package: Alphabetize attributes. --- internal/service/opensearch/package.go | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index 9d67ae8b0ff7..f1e05ccb9fbe 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -34,6 +34,10 @@ func ResourcePackage() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "package_description": { + Type: schema.TypeString, + Optional: true, + }, "package_id": { Type: schema.TypeString, Computed: true, @@ -43,16 +47,6 @@ func ResourcePackage() *schema.Resource { Required: true, ForceNew: true, }, - "package_description": { - Type: schema.TypeString, - Optional: true, - }, - "package_type": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(opensearchservice.PackageType_Values(), false), - }, "package_source": { Type: schema.TypeList, Required: true, @@ -73,6 +67,12 @@ func ResourcePackage() *schema.Resource { }, }, }, + "package_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(opensearchservice.PackageType_Values(), false), + }, }, } } From 94b92dfea64cb6849be52c49ae7e934b2ee10018 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 08:19:10 -0400 Subject: [PATCH 29/35] r/aws_opensearch_package: Use 'FindPackageByID'. --- internal/service/opensearch/find.go | 29 ----- internal/service/opensearch/package.go | 111 ++++++++++++++------ internal/service/opensearch/package_test.go | 75 ++++++++----- 3 files changed, 126 insertions(+), 89 deletions(-) diff --git a/internal/service/opensearch/find.go b/internal/service/opensearch/find.go index 17d75cc5bfe6..026019a345bc 100644 --- a/internal/service/opensearch/find.go +++ b/internal/service/opensearch/find.go @@ -36,32 +36,3 @@ func FindDomainByName(ctx context.Context, conn *opensearchservice.OpenSearchSer return output.DomainStatus, nil } - -func FindPackageByName(ctx context.Context, conn *opensearchservice.OpenSearchService, id string) (*opensearchservice.PackageDetails, error) { - input := &opensearchservice.DescribePackagesInput{ - Filters: []*opensearchservice.DescribePackagesFilter{ - { - Name: aws.String("PackageID"), - Value: []*string{aws.String(id)}, - }, - }, - } - - output, err := conn.DescribePackagesWithContext(ctx, input) - if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil || len(output.PackageDetailsList) == 0 { - return nil, tfresource.NewEmptyResultError(input) - } - - return output.PackageDetailsList[0], nil -} diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index f1e05ccb9fbe..0a39b667fb10 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -11,19 +11,21 @@ import ( "github.com/aws/aws-sdk-go/service/opensearchservice" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "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" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) // @SDKResource("aws_opensearch_package") func ResourcePackage() *schema.Resource { return &schema.Resource{ - CreateWithoutTimeout: ResourcePackageCreate, - ReadWithoutTimeout: ResourcePackageRead, - UpdateWithoutTimeout: ResourcePackageUpdate, - DeleteWithoutTimeout: ResourcePackageDelete, + CreateWithoutTimeout: resourcePackageCreate, + ReadWithoutTimeout: resourcePackageRead, + UpdateWithoutTimeout: resourcePackageUpdate, + DeleteWithoutTimeout: resourcePackageDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -77,13 +79,14 @@ func ResourcePackage() *schema.Resource { } } -func ResourcePackageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + name := d.Get("package_name").(string) input := &opensearchservice.CreatePackageInput{ PackageDescription: aws.String(d.Get("package_description").(string)), - PackageName: aws.String(d.Get("package_name").(string)), + PackageName: aws.String(name), PackageType: aws.String(d.Get("package_type").(string)), } @@ -94,48 +97,40 @@ func ResourcePackageCreate(ctx context.Context, d *schema.ResourceData, meta int output, err := conn.CreatePackageWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating OpenSearch Package: %s", err) + return sdkdiag.AppendErrorf(diags, "creating OpenSearch Package (%s): %s", name, err) } d.SetId(aws.StringValue(output.PackageDetails.PackageID)) - return append(diags, ResourcePackageRead(ctx, d, meta)...) + return append(diags, resourcePackageRead(ctx, d, meta)...) } -func ResourcePackageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - input := &opensearchservice.DescribePackagesInput{ - Filters: []*opensearchservice.DescribePackagesFilter{ - { - Name: aws.String("PackageID"), - Value: []*string{aws.String(d.Id())}, - }, - }, - } + pkg, err := FindPackageByID(ctx, conn, d.Id()) - output, err := conn.DescribePackagesWithContext(ctx, input) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] OpenSearch Package (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } if err != nil { return sdkdiag.AppendErrorf(diags, "reading OpenSearch Package (%s): %s", d.Id(), err) } - if output == nil || len(output.PackageDetailsList) == 0 { - d.SetId("") - return sdkdiag.AppendErrorf(diags, "reading OpenSearch Package (%s): not found", d.Id()) - } - - d.Set("package_id", output.PackageDetailsList[0].PackageID) - d.Set("package_name", output.PackageDetailsList[0].PackageName) - d.Set("package_description", output.PackageDetailsList[0].PackageDescription) - d.Set("package_type", output.PackageDetailsList[0].PackageType) - d.Set("available_package_version", output.PackageDetailsList[0].AvailablePackageVersion) + d.Set("available_package_version", pkg.AvailablePackageVersion) + d.Set("package_description", pkg.PackageDescription) + d.Set("package_id", pkg.PackageID) + d.Set("package_name", pkg.PackageName) + d.Set("package_type", pkg.PackageType) return diags } -func ResourcePackageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) @@ -151,10 +146,10 @@ func ResourcePackageUpdate(ctx context.Context, d *schema.ResourceData, meta int return sdkdiag.AppendErrorf(diags, "updating OpenSearch Package (%s): %s", d.Id(), err) } - return append(diags, ResourcePackageRead(ctx, d, meta)...) + return append(diags, resourcePackageRead(ctx, d, meta)...) } -func ResourcePackageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) @@ -174,6 +169,60 @@ func ResourcePackageDelete(ctx context.Context, d *schema.ResourceData, meta int return diags } +func FindPackageByID(ctx context.Context, conn *opensearchservice.OpenSearchService, id string) (*opensearchservice.PackageDetails, error) { + input := &opensearchservice.DescribePackagesInput{ + Filters: []*opensearchservice.DescribePackagesFilter{ + { + Name: aws.String("PackageID"), + Value: aws.StringSlice([]string{id}), + }, + }, + } + + return findPackage(ctx, conn, input) +} + +func findPackage(ctx context.Context, conn *opensearchservice.OpenSearchService, input *opensearchservice.DescribePackagesInput) (*opensearchservice.PackageDetails, error) { + output, err := findPackages(ctx, conn, input) + + if err != nil { + return nil, err + } + + return tfresource.AssertSinglePtrResult(output) +} + +func findPackages(ctx context.Context, conn *opensearchservice.OpenSearchService, input *opensearchservice.DescribePackagesInput) ([]*opensearchservice.PackageDetails, error) { + var output []*opensearchservice.PackageDetails + + err := conn.DescribePackagesPagesWithContext(ctx, input, func(page *opensearchservice.DescribePackagesOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.PackageDetailsList { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} + func expandPackageSource(v interface{}) *opensearchservice.PackageSource { if v == nil { return nil diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index b4aca97ab595..7e070d6350ef 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -20,8 +20,7 @@ import ( func TestAccOpenSearchPackage_basic(t *testing.T) { ctx := acctest.Context(t) - ri := sdkacctest.RandString(10) - name := fmt.Sprintf("tf-test-%s", ri) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_opensearch_package.test" resource.ParallelTest(t, resource.TestCase{ @@ -31,9 +30,10 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { CheckDestroy: testAccCheckPackageDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageConfig(name), + Config: testAccPackageConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "package_name", name), + testAccCheckPackageExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "package_name", rName), ), }, { @@ -50,8 +50,7 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { func TestAccOpenSearchPackage_disappears(t *testing.T) { ctx := acctest.Context(t) - ri := sdkacctest.RandString(10) - name := fmt.Sprintf("tf-test-%s", ri) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_opensearch_package.test" resource.ParallelTest(t, resource.TestCase{ @@ -61,8 +60,9 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { CheckDestroy: testAccCheckPackageDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageConfig(name), + Config: testAccPackageConfig_basic(rName), Check: resource.ComposeTestCheckFunc( + testAccCheckPackageExists(ctx, resourceName), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), ), ExpectNonEmptyPlan: true, @@ -71,28 +71,19 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { }) } -func testAccPackageConfig(name string) string { - return fmt.Sprintf(` -resource "aws_s3_bucket" "opensearch_packages" { - bucket = "%s" -} +func testAccCheckPackageExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } -resource "aws_s3_object" "example_txt" { - bucket = aws_s3_bucket.opensearch_packages.bucket - key = "%s" - source = "./test-fixtures/example-opensearch-custom-package.txt" - etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") -} + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchConn(ctx) -resource "aws_opensearch_package" "test" { - package_name = "%s" - package_source { - s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket - s3_key = aws_s3_object.example_txt.key - } - package_type = "TXT-DICTIONARY" -} -`, name, name, name) + _, err := tfopensearch.FindPackageByID(ctx, conn, rs.Primary.ID) + + return err + } } func testAccCheckPackageDestroy(ctx context.Context) resource.TestCheckFunc { @@ -103,7 +94,8 @@ func testAccCheckPackageDestroy(ctx context.Context) resource.TestCheckFunc { } conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchConn(ctx) - _, err := tfopensearch.FindPackageByName(ctx, conn, rs.Primary.Attributes["package_id"]) + + _, err := tfopensearch.FindPackageByID(ctx, conn, rs.Primary.ID) if tfresource.NotFound(err) { continue @@ -113,8 +105,33 @@ func testAccCheckPackageDestroy(ctx context.Context) resource.TestCheckFunc { return err } - return fmt.Errorf("OpenSearch package %s still exists", rs.Primary.ID) + return fmt.Errorf("OpenSearch Package %s still exists", rs.Primary.ID) } + return nil } } + +func testAccPackageConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = %[1]q + source = "./test-fixtures/example-opensearch-custom-package.txt" + etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") +} + +resource "aws_opensearch_package" "test" { + package_name = %[1]q + package_source { + s3_bucket_name = aws_s3_bucket.test.bucket + s3_key = aws_s3_object.test.key + } + package_type = "TXT-DICTIONARY" +} +`, rName) +} From 291abd0833d48c912e79525647404bb9c397200b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 08:44:03 -0400 Subject: [PATCH 30/35] r/aws_opensearch_package_association: Use 'FindPackageAssociationByTwoPartKey'. --- .../service/opensearch/package_association.go | 112 ++++++++++++------ .../opensearch/package_association_test.go | 96 ++++++++++----- 2 files changed, 142 insertions(+), 66 deletions(-) diff --git a/internal/service/opensearch/package_association.go b/internal/service/opensearch/package_association.go index 062bc04f82a8..19506d1edede 100644 --- a/internal/service/opensearch/package_association.go +++ b/internal/service/opensearch/package_association.go @@ -12,17 +12,20 @@ import ( "github.com/aws/aws-sdk-go/service/opensearchservice" "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "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" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) // @SDKResource("aws_opensearch_package_association") func ResourcePackageAssociation() *schema.Resource { return &schema.Resource{ - CreateWithoutTimeout: ResourcePackageAssociationCreate, - ReadWithoutTimeout: ResourcePackageAssociationRead, - DeleteWithoutTimeout: ResourcePackageAssociationDelete, + CreateWithoutTimeout: resourcePackageAssociationCreate, + ReadWithoutTimeout: resourcePackageAssociationRead, + DeleteWithoutTimeout: resourcePackageAssociationDelete, Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, @@ -47,49 +50,57 @@ func ResourcePackageAssociation() *schema.Resource { } } -func ResourcePackageAssociationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageAssociationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) + domainName := d.Get("domain_name").(string) + packageID := d.Get("package_id").(string) + id := fmt.Sprintf("%s-%s", domainName, packageID) input := &opensearchservice.AssociatePackageInput{ - DomainName: aws.String(d.Get("domain_name").(string)), - PackageID: aws.String(d.Get("package_id").(string)), + DomainName: aws.String(domainName), + PackageID: aws.String(packageID), } - output, err := conn.AssociatePackageWithContext(ctx, input) + _, err := conn.AssociatePackageWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "associating OpenSearch package: %s", err) + return sdkdiag.AppendErrorf(diags, "creating OpenSearch Package Association (%s): %s", id, err) } - d.SetId(fmt.Sprintf("package-association:%s-%s", aws.StringValue(output.DomainPackageDetails.DomainName), aws.StringValue(output.DomainPackageDetails.PackageID))) + d.SetId(id) - return diags + return append(diags, resourcePackageAssociationRead(ctx, d, meta)...) } -func ResourcePackageAssociationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageAssociationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - var domainName = d.Get("domain_name").(string) - var packageID = d.Get("package_id").(string) + pkgAssociation, err := FindPackageAssociationByTwoPartKey(ctx, conn, d.Get("domain_name").(string), d.Get("package_id").(string)) + + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] OpenSearch Package Association (%s) not found, removing from state", d.Id()) + d.SetId("") + return diags + } - output, err := getAssociatedDomainPackage(ctx, domainName, packageID, conn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing OpenSearch Package for domain (%s): %s", domainName, err) + return sdkdiag.AppendErrorf(diags, "reading OpenSearch Package Association (%s): %s", d.Id(), err) } - d.Set("package_id", output.PackageID) - d.Set("package_type", output.ReferencePath) - d.Set("available_package_version", output.PackageVersion) + d.Set("domain_name", pkgAssociation.DomainName) + d.Set("package_id", pkgAssociation.PackageID) + d.Set("reference_path", pkgAssociation.ReferencePath) + return diags } -func ResourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func resourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - log.Printf("[DEBUG] Deleting OpenSearch Package: %s", d.Id()) + log.Printf("[DEBUG] Deleting OpenSearch Package Association: %s", d.Id()) _, err := conn.DissociatePackageWithContext(ctx, &opensearchservice.DissociatePackageInput{ PackageID: aws.String(d.Id()), }) @@ -99,33 +110,60 @@ func ResourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceDat } if err != nil { - return sdkdiag.AppendErrorf(diags, "dissociating OpenSearch Package (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "deleting OpenSearch Package Association (%s): %s", d.Id(), err) } return diags } -func getAssociatedDomainPackage(ctx context.Context, domainID, packageID string, conn *opensearchservice.OpenSearchService) (*opensearchservice.DomainPackageDetails, error) { +func FindPackageAssociationByTwoPartKey(ctx context.Context, conn *opensearchservice.OpenSearchService, domainName, packageID string) (*opensearchservice.DomainPackageDetails, error) { input := &opensearchservice.ListPackagesForDomainInput{ - DomainName: aws.String(domainID), + DomainName: aws.String(domainName), } - for { - resp, err := conn.ListPackagesForDomainWithContext(ctx, input) - if err != nil { - return nil, err - } - if len(resp.DomainPackageDetailsList) == 0 { - return nil, fmt.Errorf("no packages found for domain %s", domainID) + filter := func(v *opensearchservice.DomainPackageDetails) bool { + return aws.StringValue(v.PackageID) == packageID + } + + return findPackageAssociation(ctx, conn, input, filter) +} + +func findPackageAssociation(ctx context.Context, conn *opensearchservice.OpenSearchService, input *opensearchservice.ListPackagesForDomainInput, filter tfslices.Predicate[*opensearchservice.DomainPackageDetails]) (*opensearchservice.DomainPackageDetails, error) { + output, err := findPackageAssociations(ctx, conn, input, filter) + + if err != nil { + return nil, err + } + + return tfresource.AssertSinglePtrResult(output) +} + +func findPackageAssociations(ctx context.Context, conn *opensearchservice.OpenSearchService, input *opensearchservice.ListPackagesForDomainInput, filter tfslices.Predicate[*opensearchservice.DomainPackageDetails]) ([]*opensearchservice.DomainPackageDetails, error) { + var output []*opensearchservice.DomainPackageDetails + + err := conn.ListPackagesForDomainPagesWithContext(ctx, input, func(page *opensearchservice.ListPackagesForDomainOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - for _, domainPackageDetails := range resp.DomainPackageDetailsList { - if aws.StringValue(domainPackageDetails.PackageID) == packageID { - return domainPackageDetails, nil + + for _, v := range page.DomainPackageDetailsList { + if v != nil && filter(v) { + output = append(output, v) } } - if resp.NextToken == nil { - break + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } - input.NextToken = resp.NextToken } - return nil, nil + + if err != nil { + return nil, err + } + + return output, nil } diff --git a/internal/service/opensearch/package_association_test.go b/internal/service/opensearch/package_association_test.go index 590c7636299e..d9dfb360d22d 100644 --- a/internal/service/opensearch/package_association_test.go +++ b/internal/service/opensearch/package_association_test.go @@ -4,20 +4,24 @@ package opensearch_test import ( + "context" "fmt" "testing" "github.com/aws/aws-sdk-go/service/opensearchservice" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" tfopensearch "github.com/hashicorp/terraform-provider-aws/internal/service/opensearch" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { ctx := acctest.Context(t) - ri := sdkacctest.RandString(10) - name := fmt.Sprintf("tf-test-%s", ri) + domainName := testAccRandomDomainName() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_opensearch_package_association.test" packageResourceName := "aws_opensearch_package.test" domainResourceName := "aws_opensearch_domain.test" @@ -26,43 +30,36 @@ func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckDomainDestroy(ctx), + CheckDestroy: testAccCheckPackageAssociationDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageAssociationConfig(name), + Config: testAccPackageAssociationConfig_basic(rName, domainName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr(resourceName, "package_name", name), - resource.TestCheckResourceAttrPair(resourceName, "package_id", packageResourceName, "id"), + testAccCheckPackageAssociationExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "domain_name", domainResourceName, "domain_name"), + resource.TestCheckResourceAttrPair(resourceName, "package_id", packageResourceName, "id"), ), }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{ - "package_source", // This isn't returned by the API - }, - }, }, }) } func TestAccOpenSearchPackageAssociation_disappears(t *testing.T) { ctx := acctest.Context(t) - ri := sdkacctest.RandString(10) - name := fmt.Sprintf("tf-test-%s", ri) + domainName := testAccRandomDomainName() + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_opensearch_package_association.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckDomainDestroy(ctx), + CheckDestroy: testAccCheckPackageAssociationDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageAssociationConfig(name), + Config: testAccPackageAssociationConfig_basic(rName, domainName), Check: resource.ComposeTestCheckFunc( + testAccCheckPackageAssociationExists(ctx, resourceName), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), ), ExpectNonEmptyPlan: true, @@ -71,30 +68,71 @@ func TestAccOpenSearchPackageAssociation_disappears(t *testing.T) { }) } -func testAccPackageAssociationConfig(name string) string { +func testAccCheckPackageAssociationExists(ctx context.Context, n string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchConn(ctx) + + _, err := tfopensearch.FindPackageAssociationByTwoPartKey(ctx, conn, rs.Primary.Attributes["domain_name"], rs.Primary.Attributes["package_id"]) + + return err + } +} + +func testAccCheckPackageAssociationDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_opensearch_package_association" { + continue + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).OpenSearchConn(ctx) + + _, err := tfopensearch.FindPackageAssociationByTwoPartKey(ctx, conn, rs.Primary.Attributes["domain_name"], rs.Primary.Attributes["package_id"]) + + if tfresource.NotFound(err) { + continue + } + + if err != nil { + return err + } + + return fmt.Errorf("OpenSearch Package Association %s still exists", rs.Primary.ID) + } + + return nil + } +} + +func testAccPackageAssociationConfig_basic(rName, domainName string) string { return fmt.Sprintf(` -resource "aws_s3_bucket" "opensearch_packages" { - bucket = "%s" +resource "aws_s3_bucket" "test" { + bucket = %[1]q } -resource "aws_s3_object" "example_txt" { - bucket = aws_s3_bucket.opensearch_packages.bucket - key = "%s" +resource "aws_s3_object" "test" { + bucket = aws_s3_bucket.test.bucket + key = %[1]q source = "./test-fixtures/example-opensearch-custom-package.txt" etag = filemd5("./test-fixtures/example-opensearch-custom-package.txt") } resource "aws_opensearch_package" "test" { - package_name = "%s" + package_name = %[1]q package_source { - s3_bucket_name = aws_s3_bucket.opensearch_packages.bucket - s3_key = aws_s3_object.example_txt.key + s3_bucket_name = aws_s3_bucket.test.bucket + s3_key = aws_s3_object.test.key } package_type = "TXT-DICTIONARY" } resource "aws_opensearch_domain" "test" { - domain_name = "%s" + domain_name = %[2]q cluster_config { instance_type = "t3.small.search" # supported in both aws and aws-us-gov @@ -110,5 +148,5 @@ resource "aws_opensearch_package_association" "test" { package_id = aws_opensearch_package.test.id domain_name = aws_opensearch_domain.test.domain_name } -`, name, name, name, name) +`, rName, domainName) } From 18ade81e21690f5a0c8299adb41c0ac26f859053 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 08:44:58 -0400 Subject: [PATCH 31/35] Fix 'testAccCheckPackageDestroy'. --- internal/service/opensearch/package_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 7e070d6350ef..55581be9c5a8 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -89,7 +89,7 @@ func testAccCheckPackageExists(ctx context.Context, n string) resource.TestCheck func testAccCheckPackageDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_opensearch_domain" { + if rs.Type != "aws_opensearch_package" { continue } From eec0405db63c0b3020c3251439593efaed843a96 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 09:56:28 -0400 Subject: [PATCH 32/35] Fix 'ValidationException: 1 validation error detected: Value 'tf-acc-test-4027415160501002224' at 'packageName' failed to satisfy constraint: Member must have length less than or equal to 28'. --- internal/service/opensearch/package.go | 7 ++++--- .../opensearch/package_association_test.go | 13 ++++++------- internal/service/opensearch/package_test.go | 18 +++++++++++------- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/internal/service/opensearch/package.go b/internal/service/opensearch/package.go index 0a39b667fb10..c474ba0a44cc 100644 --- a/internal/service/opensearch/package.go +++ b/internal/service/opensearch/package.go @@ -45,9 +45,10 @@ func ResourcePackage() *schema.Resource { Computed: true, }, "package_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 32), }, "package_source": { Type: schema.TypeList, diff --git a/internal/service/opensearch/package_association_test.go b/internal/service/opensearch/package_association_test.go index d9dfb360d22d..31104394a80b 100644 --- a/internal/service/opensearch/package_association_test.go +++ b/internal/service/opensearch/package_association_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/opensearchservice" - sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -21,7 +20,7 @@ import ( func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { ctx := acctest.Context(t) domainName := testAccRandomDomainName() - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pkgName := testAccRandomDomainName() resourceName := "aws_opensearch_package_association.test" packageResourceName := "aws_opensearch_package.test" domainResourceName := "aws_opensearch_domain.test" @@ -33,7 +32,7 @@ func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckPackageAssociationDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageAssociationConfig_basic(rName, domainName), + Config: testAccPackageAssociationConfig_basic(pkgName, domainName), Check: resource.ComposeTestCheckFunc( testAccCheckPackageAssociationExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "domain_name", domainResourceName, "domain_name"), @@ -47,7 +46,7 @@ func TestAccOpenSearchPackageAssociation_basic(t *testing.T) { func TestAccOpenSearchPackageAssociation_disappears(t *testing.T) { ctx := acctest.Context(t) domainName := testAccRandomDomainName() - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pkgName := testAccRandomDomainName() resourceName := "aws_opensearch_package_association.test" resource.ParallelTest(t, resource.TestCase{ @@ -57,7 +56,7 @@ func TestAccOpenSearchPackageAssociation_disappears(t *testing.T) { CheckDestroy: testAccCheckPackageAssociationDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageAssociationConfig_basic(rName, domainName), + Config: testAccPackageAssociationConfig_basic(pkgName, domainName), Check: resource.ComposeTestCheckFunc( testAccCheckPackageAssociationExists(ctx, resourceName), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), @@ -109,7 +108,7 @@ func testAccCheckPackageAssociationDestroy(ctx context.Context) resource.TestChe } } -func testAccPackageAssociationConfig_basic(rName, domainName string) string { +func testAccPackageAssociationConfig_basic(pkgName, domainName string) string { return fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q @@ -148,5 +147,5 @@ resource "aws_opensearch_package_association" "test" { package_id = aws_opensearch_package.test.id domain_name = aws_opensearch_domain.test.domain_name } -`, rName, domainName) +`, pkgName, domainName) } diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 55581be9c5a8..58d2d093a5d7 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/aws/aws-sdk-go/service/opensearchservice" - sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -20,7 +19,7 @@ import ( func TestAccOpenSearchPackage_basic(t *testing.T) { ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pkgName := testAccRandomDomainName() resourceName := "aws_opensearch_package.test" resource.ParallelTest(t, resource.TestCase{ @@ -30,10 +29,15 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { CheckDestroy: testAccCheckPackageDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageConfig_basic(rName), - Check: resource.ComposeTestCheckFunc( + Config: testAccPackageConfig_basic(pkgName), + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckPackageExists(ctx, resourceName), - resource.TestCheckResourceAttr(resourceName, "package_name", rName), + resource.TestCheckResourceAttrSet(resourceName, "available_package_version"), + resource.TestCheckResourceAttr(resourceName, "package_description", ""), + resource.TestCheckResourceAttrSet(resourceName, "package_id"), + resource.TestCheckResourceAttr(resourceName, "package_name", pkgName), + resource.TestCheckResourceAttr(resourceName, "package_source.#", "1"), + resource.TestCheckResourceAttr(resourceName, "package_type", "TXT-DICTIONARY"), ), }, { @@ -50,7 +54,7 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { func TestAccOpenSearchPackage_disappears(t *testing.T) { ctx := acctest.Context(t) - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + pkgName := testAccRandomDomainName() resourceName := "aws_opensearch_package.test" resource.ParallelTest(t, resource.TestCase{ @@ -60,7 +64,7 @@ func TestAccOpenSearchPackage_disappears(t *testing.T) { CheckDestroy: testAccCheckPackageDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccPackageConfig_basic(rName), + Config: testAccPackageConfig_basic(pkgName), Check: resource.ComposeTestCheckFunc( testAccCheckPackageExists(ctx, resourceName), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), From 68678508d1a066593505ef325c692b9c0cc11a34 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 11:29:13 -0400 Subject: [PATCH 33/35] r/aws_opensearch_package_association: Add waiters. --- .../service/opensearch/package_association.go | 83 ++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/internal/service/opensearch/package_association.go b/internal/service/opensearch/package_association.go index 19506d1edede..49aa138b25ca 100644 --- a/internal/service/opensearch/package_association.go +++ b/internal/service/opensearch/package_association.go @@ -7,6 +7,7 @@ import ( "context" "fmt" "log" + "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/opensearchservice" @@ -31,6 +32,11 @@ func ResourcePackageAssociation() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + Schema: map[string]*schema.Schema{ "domain_name": { Type: schema.TypeString, @@ -70,6 +76,10 @@ func resourcePackageAssociationCreate(ctx context.Context, d *schema.ResourceDat d.SetId(id) + if _, err := waitPackageAssociationCreated(ctx, conn, domainName, packageID, d.Timeout(schema.TimeoutCreate)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for OpenSearch Package Association (%s) create: %s", d.Id(), err) + } + return append(diags, resourcePackageAssociationRead(ctx, d, meta)...) } @@ -77,7 +87,9 @@ func resourcePackageAssociationRead(ctx context.Context, d *schema.ResourceData, var diags diag.Diagnostics conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - pkgAssociation, err := FindPackageAssociationByTwoPartKey(ctx, conn, d.Get("domain_name").(string), d.Get("package_id").(string)) + domainName := d.Get("domain_name").(string) + packageID := d.Get("package_id").(string) + pkgAssociation, err := FindPackageAssociationByTwoPartKey(ctx, conn, domainName, packageID) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] OpenSearch Package Association (%s) not found, removing from state", d.Id()) @@ -101,8 +113,11 @@ func resourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceDat conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) log.Printf("[DEBUG] Deleting OpenSearch Package Association: %s", d.Id()) + domainName := d.Get("domain_name").(string) + packageID := d.Get("package_id").(string) _, err := conn.DissociatePackageWithContext(ctx, &opensearchservice.DissociatePackageInput{ - PackageID: aws.String(d.Id()), + DomainName: aws.String(domainName), + PackageID: aws.String(packageID), }) if tfawserr.ErrCodeEquals(err, opensearchservice.ErrCodeResourceNotFoundException) { @@ -113,6 +128,10 @@ func resourcePackageAssociationDelete(ctx context.Context, d *schema.ResourceDat return sdkdiag.AppendErrorf(diags, "deleting OpenSearch Package Association (%s): %s", d.Id(), err) } + if _, err := waitPackageAssociationDeleted(ctx, conn, domainName, packageID, d.Timeout(schema.TimeoutDelete)); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for OpenSearch Package Association (%s) delete: %s", d.Id(), err) + } + return diags } @@ -167,3 +186,63 @@ func findPackageAssociations(ctx context.Context, conn *opensearchservice.OpenSe return output, nil } + +func statusPackageAssociation(ctx context.Context, conn *opensearchservice.OpenSearchService, domainName, packageID string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindPackageAssociationByTwoPartKey(ctx, conn, domainName, packageID) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, aws.StringValue(output.DomainPackageStatus), nil + } +} + +func waitPackageAssociationCreated(ctx context.Context, conn *opensearchservice.OpenSearchService, domainName, packageID string, timeout time.Duration) (*opensearchservice.DomainPackageDetails, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{opensearchservice.DomainPackageStatusAssociating}, + Target: []string{opensearchservice.DomainPackageStatusActive}, + Refresh: statusPackageAssociation(ctx, conn, domainName, packageID), + Timeout: timeout, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*opensearchservice.DomainPackageDetails); ok { + if status, details := aws.StringValue(output.DomainPackageStatus), output.ErrorDetails; status == opensearchservice.DomainPackageStatusAssociationFailed && details != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(details.ErrorType), aws.StringValue(details.ErrorMessage))) + } + + return output, err + } + + return nil, err +} + +func waitPackageAssociationDeleted(ctx context.Context, conn *opensearchservice.OpenSearchService, domainName, packageID string, timeout time.Duration) (*opensearchservice.DomainPackageDetails, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{opensearchservice.DomainPackageStatusDissociating}, + Target: []string{}, + Refresh: statusPackageAssociation(ctx, conn, domainName, packageID), + Timeout: timeout, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*opensearchservice.DomainPackageDetails); ok { + if status, details := aws.StringValue(output.DomainPackageStatus), output.ErrorDetails; status == opensearchservice.DomainPackageStatusDissociationFailed && details != nil { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.StringValue(details.ErrorType), aws.StringValue(details.ErrorMessage))) + } + + return output, err + } + + return nil, err +} From 5b6706828532efface4850c614bc7db7f99e1ffb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 11:31:04 -0400 Subject: [PATCH 34/35] Correct acceptance tests. --- internal/service/opensearch/package_association_test.go | 2 +- internal/service/opensearch/package_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/opensearch/package_association_test.go b/internal/service/opensearch/package_association_test.go index 31104394a80b..38cfcce2fb19 100644 --- a/internal/service/opensearch/package_association_test.go +++ b/internal/service/opensearch/package_association_test.go @@ -59,7 +59,7 @@ func TestAccOpenSearchPackageAssociation_disappears(t *testing.T) { Config: testAccPackageAssociationConfig_basic(pkgName, domainName), Check: resource.ComposeTestCheckFunc( testAccCheckPackageAssociationExists(ctx, resourceName), - acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackage(), resourceName), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfopensearch.ResourcePackageAssociation(), resourceName), ), ExpectNonEmptyPlan: true, }, diff --git a/internal/service/opensearch/package_test.go b/internal/service/opensearch/package_test.go index 58d2d093a5d7..d31f9fdb907c 100644 --- a/internal/service/opensearch/package_test.go +++ b/internal/service/opensearch/package_test.go @@ -32,7 +32,7 @@ func TestAccOpenSearchPackage_basic(t *testing.T) { Config: testAccPackageConfig_basic(pkgName), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckPackageExists(ctx, resourceName), - resource.TestCheckResourceAttrSet(resourceName, "available_package_version"), + resource.TestCheckResourceAttr(resourceName, "available_package_version", ""), resource.TestCheckResourceAttr(resourceName, "package_description", ""), resource.TestCheckResourceAttrSet(resourceName, "package_id"), resource.TestCheckResourceAttr(resourceName, "package_name", pkgName), From 7cc7abc6d0378361b6d3a21db3296d7a1a312717 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 19 Sep 2023 11:35:23 -0400 Subject: [PATCH 35/35] Tweak documentation. --- .../docs/r/opensearch_package.html.markdown | 4 ++-- ...pensearch_package_association.html.markdown | 18 ++++-------------- 2 files changed, 6 insertions(+), 16 deletions(-) diff --git a/website/docs/r/opensearch_package.html.markdown b/website/docs/r/opensearch_package.html.markdown index a89a270ccce1..4360da88dce7 100644 --- a/website/docs/r/opensearch_package.html.markdown +++ b/website/docs/r/opensearch_package.html.markdown @@ -63,7 +63,7 @@ In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashico ```terraform import { - to = aws_opensearch_package.foo + to = aws_opensearch_package.example id = "package-id" } ``` @@ -71,5 +71,5 @@ import { Using `terraform import`, import AWS Opensearch Packages using the Package ID. For example: ```console -% terraform import aws_opensearch_package.foo package-id +% terraform import aws_opensearch_package.example package-id ``` diff --git a/website/docs/r/opensearch_package_association.html.markdown b/website/docs/r/opensearch_package_association.html.markdown index d644bc5b2917..db6ce09f93a8 100644 --- a/website/docs/r/opensearch_package_association.html.markdown +++ b/website/docs/r/opensearch_package_association.html.markdown @@ -52,19 +52,9 @@ This resource exports the following attributes in addition to the arguments abov * `id` - The Id of the package association. -## Import +## Timeouts -In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Package Associations using the Package Association ID. For example: +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): -```terraform -import { - to = aws_opensearch_package_association.foo - id = "package-association-id" -} -``` - -Using `terraform import`, import AWS Opensearch Package Associations using the Package Association ID. For example: - -```console -% terraform import aws_opensearch_package_association.foo package-association:- -``` +* `create` - (Default `10m`) +* `delete` - (Default `10m`)