Skip to content

Commit a7062a3

Browse files
authored
Merge pull request #44155 from tabito-hara/f-aws_opensearch_package-add_engine_version_argument
[Enhancement] aws_opensearch_package: Add `engine_version` argument and waiter to ensure package validation completes
2 parents 55e4e35 + 1deb81c commit a7062a3

File tree

5 files changed

+147
-3
lines changed

5 files changed

+147
-3
lines changed

.changelog/44155.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:enhancement
2+
resource/aws_opensearch_package: Add `engine_version` argument
3+
```
4+
5+
```release-note:enhancement
6+
resource/aws_opensearch_package: Add waiter to ensure package validation completes
7+
```

internal/service/opensearch/package.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ package opensearch
55

66
import (
77
"context"
8+
"fmt"
89
"log"
10+
"time"
911

12+
"github.com/YakDriver/regexache"
1013
"github.com/aws/aws-sdk-go-v2/aws"
1114
"github.com/aws/aws-sdk-go-v2/service/opensearch"
1215
awstypes "github.com/aws/aws-sdk-go-v2/service/opensearch/types"
@@ -39,6 +42,12 @@ func resourcePackage() *schema.Resource {
3942
Type: schema.TypeString,
4043
Computed: true,
4144
},
45+
names.AttrEngineVersion: {
46+
Type: schema.TypeString,
47+
Optional: true,
48+
ForceNew: true,
49+
ValidateFunc: validation.StringMatch(regexache.MustCompile(`^Elasticsearch_[0-9]{1}\.[0-9]{1,2}$|^OpenSearch_[0-9]{1,2}\.[0-9]{1,2}$`), "must be in the format 'Elasticsearch_X.Y' or 'OpenSearch_X.Y'"),
50+
},
4251
"package_description": {
4352
Type: schema.TypeString,
4453
Optional: true,
@@ -94,6 +103,10 @@ func resourcePackageCreate(ctx context.Context, d *schema.ResourceData, meta any
94103
PackageType: awstypes.PackageType(d.Get("package_type").(string)),
95104
}
96105

106+
if v, ok := d.GetOk(names.AttrEngineVersion); ok {
107+
input.EngineVersion = aws.String(v.(string))
108+
}
109+
97110
if v, ok := d.GetOk("package_source"); ok {
98111
input.PackageSource = expandPackageSource(v.([]any)[0].(map[string]any))
99112
}
@@ -106,6 +119,9 @@ func resourcePackageCreate(ctx context.Context, d *schema.ResourceData, meta any
106119

107120
d.SetId(aws.ToString(output.PackageDetails.PackageID))
108121

122+
if _, err := waitPackageValidationCompleted(ctx, conn, d.Id()); err != nil {
123+
return sdkdiag.AppendErrorf(diags, "waiting for package validation (%s) completed: %s", d.Id(), err)
124+
}
109125
return append(diags, resourcePackageRead(ctx, d, meta)...)
110126
}
111127

@@ -126,6 +142,7 @@ func resourcePackageRead(ctx context.Context, d *schema.ResourceData, meta any)
126142
}
127143

128144
d.Set("available_package_version", pkg.AvailablePackageVersion)
145+
d.Set(names.AttrEngineVersion, pkg.EngineVersion)
129146
d.Set("package_description", pkg.PackageDescription)
130147
d.Set("package_id", pkg.PackageID)
131148
d.Set("package_name", pkg.PackageName)
@@ -230,3 +247,46 @@ func expandPackageSource(v any) *awstypes.PackageSource {
230247
S3Key: aws.String(v.(map[string]any)["s3_key"].(string)),
231248
}
232249
}
250+
251+
func waitPackageValidationCompleted(ctx context.Context, conn *opensearch.Client, id string) (*opensearch.DescribePackagesOutput, error) {
252+
stateConf := &retry.StateChangeConf{
253+
Pending: []string{"COPYING", "VALIDATING"},
254+
Target: []string{"AVAILABLE"},
255+
Refresh: statusPackageValidation(ctx, conn, id),
256+
Timeout: 20 * time.Minute,
257+
MinTimeout: 15 * time.Second,
258+
Delay: 30 * time.Second,
259+
}
260+
261+
outputRaw, err := stateConf.WaitForStateContext(ctx)
262+
263+
if output, ok := outputRaw.(*opensearch.DescribePackagesOutput); ok {
264+
return output, err
265+
}
266+
267+
return nil, err
268+
}
269+
270+
func statusPackageValidation(ctx context.Context, conn *opensearch.Client, id string) retry.StateRefreshFunc {
271+
return func() (any, string, error) {
272+
output, err := findPackageByID(ctx, conn, id)
273+
274+
if tfresource.NotFound(err) {
275+
return nil, "", nil
276+
}
277+
278+
if err != nil {
279+
return nil, "", err
280+
}
281+
282+
if output == nil {
283+
return nil, "", nil
284+
}
285+
286+
if output.ErrorDetails != nil {
287+
return nil, string(output.PackageStatus), fmt.Errorf("package validation failed: %s, %s, %s", string(output.PackageStatus), aws.ToString(output.ErrorDetails.ErrorType), aws.ToString(output.ErrorDetails.ErrorMessage))
288+
}
289+
290+
return output, string(output.PackageStatus), nil
291+
}
292+
}

internal/service/opensearch/package_test.go

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"fmt"
99
"testing"
1010

11+
"github.com/YakDriver/regexache"
12+
awstypes "github.com/aws/aws-sdk-go-v2/service/opensearch/types"
1113
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
1214
"github.com/hashicorp/terraform-plugin-testing/terraform"
1315
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
@@ -32,12 +34,12 @@ func TestAccOpenSearchPackage_basic(t *testing.T) {
3234
Config: testAccPackageConfig_basic(pkgName),
3335
Check: resource.ComposeAggregateTestCheckFunc(
3436
testAccCheckPackageExists(ctx, resourceName),
35-
resource.TestCheckResourceAttr(resourceName, "available_package_version", ""),
37+
resource.TestCheckResourceAttr(resourceName, "available_package_version", "v1"),
3638
resource.TestCheckResourceAttr(resourceName, "package_description", ""),
3739
resource.TestCheckResourceAttrSet(resourceName, "package_id"),
3840
resource.TestCheckResourceAttr(resourceName, "package_name", pkgName),
3941
resource.TestCheckResourceAttr(resourceName, "package_source.#", "1"),
40-
resource.TestCheckResourceAttr(resourceName, "package_type", "TXT-DICTIONARY"),
42+
resource.TestCheckResourceAttr(resourceName, "package_type", string(awstypes.PackageTypeTxtDictionary)),
4143
),
4244
},
4345
{
@@ -53,6 +55,48 @@ func TestAccOpenSearchPackage_basic(t *testing.T) {
5355
})
5456
}
5557

58+
func TestAccOpenSearchPackage_packageTypeZipPlugin(t *testing.T) {
59+
ctx := acctest.Context(t)
60+
pkgName := testAccRandomDomainName()
61+
resourceName := "aws_opensearch_package.test"
62+
63+
resource.ParallelTest(t, resource.TestCase{
64+
PreCheck: func() { acctest.PreCheck(ctx, t) },
65+
ErrorCheck: acctest.ErrorCheck(t, names.OpenSearchServiceID),
66+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
67+
CheckDestroy: testAccCheckPackageDestroy(ctx),
68+
Steps: []resource.TestStep{
69+
{
70+
Config: testAccPackageConfig_packageTypeZipPlugin(pkgName, "OpenSearch_2.17"),
71+
Check: resource.ComposeAggregateTestCheckFunc(
72+
testAccCheckPackageExists(ctx, resourceName),
73+
resource.TestCheckResourceAttr(resourceName, "available_package_version", "v1"),
74+
resource.TestCheckResourceAttr(resourceName, names.AttrEngineVersion, "OpenSearch_2.17"),
75+
resource.TestCheckResourceAttr(resourceName, "package_description", ""),
76+
resource.TestCheckResourceAttrSet(resourceName, "package_id"),
77+
resource.TestCheckResourceAttr(resourceName, "package_name", pkgName),
78+
resource.TestCheckResourceAttr(resourceName, "package_source.#", "1"),
79+
resource.TestCheckResourceAttr(resourceName, "package_type", string(awstypes.PackageTypeZipPlugin)),
80+
),
81+
},
82+
{
83+
ResourceName: resourceName,
84+
ImportState: true,
85+
ImportStateVerify: true,
86+
ImportStateVerifyIgnore: []string{
87+
"available_package_version",
88+
"package_source", // This isn't returned by the API
89+
},
90+
},
91+
{
92+
// If engin_version is different from specified in the plugin zip file, it should return an error
93+
Config: testAccPackageConfig_packageTypeZipPlugin(pkgName, "OpenSearch_2.11"),
94+
ExpectError: regexache.MustCompile(`doesn't matches with the provided EngineVersion`),
95+
},
96+
},
97+
})
98+
}
99+
56100
func TestAccOpenSearchPackage_disappears(t *testing.T) {
57101
ctx := acctest.Context(t)
58102
pkgName := testAccRandomDomainName()
@@ -140,3 +184,35 @@ resource "aws_opensearch_package" "test" {
140184
}
141185
`, rName)
142186
}
187+
188+
func testAccPackageConfig_packageTypeZipPlugin(rName, engineVersion string) string {
189+
return fmt.Sprintf(`
190+
resource "aws_s3_bucket" "test" {
191+
bucket = %[1]q
192+
}
193+
194+
195+
# example-opensearch-plugin.zip was created from the sample repository provided by AWS using the following commands:
196+
# > git clone https://github.com/aws-samples/kr-tech-blog-sample-code.git
197+
# > cd kr-tech-blog-sample-code/opensearch_custom_plugin
198+
# > gradele build
199+
# > cp build/distributions/opensearch-custom-plugin-1.0.0.zip terraform-provider-aws/internal/service/opensearch/test-fixtures/example-opensearch-plugin.zip
200+
201+
resource "aws_s3_object" "test" {
202+
bucket = aws_s3_bucket.test.bucket
203+
key = %[1]q
204+
source = "./test-fixtures/example-opensearch-plugin.zip"
205+
etag = filemd5("./test-fixtures/example-opensearch-plugin.zip")
206+
}
207+
208+
resource "aws_opensearch_package" "test" {
209+
engine_version = %[2]q
210+
package_name = %[1]q
211+
package_source {
212+
s3_bucket_name = aws_s3_bucket.test.bucket
213+
s3_key = aws_s3_object.test.key
214+
}
215+
package_type = "ZIP-PLUGIN"
216+
}
217+
`, rName, engineVersion)
218+
}
Binary file not shown.

website/docs/r/opensearch_package.html.markdown

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ resource "aws_opensearch_package" "example" {
4141
This resource supports the following arguments:
4242

4343
* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).
44+
* `engine_version` - (Optional, Forces new resources) Engine version that the package is compatible with. This argument is required and only valid when `package_type` is `ZIP-PLUGIN`. Format: `OpenSearch_X.Y` or `Elasticsearch_X.Y`, where `X` and `Y` are the major and minor version numbers, respectively.
4445
* `package_name` - (Required, Forces new resource) Unique name for the package.
45-
* `package_type` - (Required, Forces new resource) The type of package.
46+
* `package_type` - (Required, Forces new resource) The type of package. Valid values are `TXT-DICTIONARY`, `ZIP-PLUGIN`, `PACKAGE-LICENSE` and `PACKAGE-CONFIG`.
4647
* `package_source` - (Required, Forces new resource) Configuration block for the package source options.
4748
* `package_description` - (Optional, Forces new resource) Description of the package.
4849

0 commit comments

Comments
 (0)