diff --git a/.changelog/38995.txt b/.changelog/38995.txt new file mode 100644 index 000000000000..1ef0a1304440 --- /dev/null +++ b/.changelog/38995.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +data-source/aws_opensearchserverless_collection: Add `failure_code` and `failure_reason` attributes +``` \ No newline at end of file diff --git a/internal/service/opensearchserverless/access_policy.go b/internal/service/opensearchserverless/access_policy.go index 5d8441709fa1..cbe2eba04ca5 100644 --- a/internal/service/opensearchserverless/access_policy.go +++ b/internal/service/opensearchserverless/access_policy.go @@ -30,7 +30,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource +// @FrameworkResource(name="Access Policy) func newResourceAccessPolicy(_ context.Context) (resource.ResourceWithConfigure, error) { return &resourceAccessPolicy{}, nil } diff --git a/internal/service/opensearchserverless/collection.go b/internal/service/opensearchserverless/collection.go index 53e663675676..e2dfcda3c8e5 100644 --- a/internal/service/opensearchserverless/collection.go +++ b/internal/service/opensearchserverless/collection.go @@ -5,6 +5,7 @@ package opensearchserverless import ( "context" + "fmt" "time" "github.com/YakDriver/regexache" @@ -330,6 +331,10 @@ func waitCollectionCreated(ctx context.Context, conn *opensearchserverless.Clien outputRaw, err := stateConf.WaitForStateContext(ctx) if output, ok := outputRaw.(*awstypes.CollectionDetail); ok { + if output.Status == awstypes.CollectionStatusFailed { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.ToString(output.FailureCode), aws.ToString(output.FailureMessage))) + } + return output, err } @@ -349,6 +354,10 @@ func waitCollectionDeleted(ctx context.Context, conn *opensearchserverless.Clien outputRaw, err := stateConf.WaitForStateContext(ctx) if output, ok := outputRaw.(*awstypes.CollectionDetail); ok { + if output.Status == awstypes.CollectionStatusFailed { + tfresource.SetLastError(err, fmt.Errorf("%s: %s", aws.ToString(output.FailureCode), aws.ToString(output.FailureMessage))) + } + return output, err } diff --git a/internal/service/opensearchserverless/collection_data_source.go b/internal/service/opensearchserverless/collection_data_source.go index f9e4c1e1ef3b..3d6bab186431 100644 --- a/internal/service/opensearchserverless/collection_data_source.go +++ b/internal/service/opensearchserverless/collection_data_source.go @@ -55,6 +55,12 @@ func (d *dataSourceCollection) Schema(_ context.Context, _ datasource.SchemaRequ names.AttrDescription: schema.StringAttribute{ Computed: true, }, + "failure_message": schema.StringAttribute{ + Computed: true, + }, + "failure_code": schema.StringAttribute{ + Computed: true, + }, names.AttrID: schema.StringAttribute{ Optional: true, Computed: true, @@ -160,6 +166,8 @@ type dataSourceCollectionData struct { ARN types.String `tfsdk:"arn"` CollectionEndpoint types.String `tfsdk:"collection_endpoint"` CreatedDate types.String `tfsdk:"created_date"` + FailureMessage types.String `tfsdk:"failure_message"` + FailureCode types.String `tfsdk:"failure_code"` DashboardEndpoint types.String `tfsdk:"dashboard_endpoint"` Description types.String `tfsdk:"description"` ID types.String `tfsdk:"id"` diff --git a/internal/service/opensearchserverless/find.go b/internal/service/opensearchserverless/find.go index 6c09290565d2..b75868cff1d6 100644 --- a/internal/service/opensearchserverless/find.go +++ b/internal/service/opensearchserverless/find.go @@ -5,7 +5,6 @@ package opensearchserverless import ( "context" - "errors" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/opensearchserverless" @@ -21,15 +20,15 @@ func findAccessPolicyByNameAndType(ctx context.Context, conn *opensearchserverle Type: types.AccessPolicyType(policyType), } out, err := conn.GetAccessPolicy(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, } + } + if err != nil { return nil, err } @@ -45,23 +44,19 @@ func findCollectionByID(ctx context.Context, conn *opensearchserverless.Client, Ids: []string{id}, } out, err := conn.BatchGetCollection(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } - return nil, err + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } } - if out == nil || out.CollectionDetails == nil || len(out.CollectionDetails) == 0 { - return nil, tfresource.NewEmptyResultError(in) + if err != nil { + return nil, err } - return &out.CollectionDetails[0], nil + return tfresource.AssertSingleValueResult(out.CollectionDetails) } func findCollectionByName(ctx context.Context, conn *opensearchserverless.Client, name string) (*types.CollectionDetail, error) { @@ -69,27 +64,19 @@ func findCollectionByName(ctx context.Context, conn *opensearchserverless.Client Names: []string{name}, } out, err := conn.BatchGetCollection(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } - } - return nil, err - } - - if out == nil || out.CollectionDetails == nil || len(out.CollectionDetails) == 0 { - return nil, tfresource.NewEmptyResultError(in) + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } } - if len(out.CollectionDetails) > 1 { - return nil, tfresource.NewTooManyResultsError(len(out.CollectionDetails), in) + if err != nil { + return nil, err } - return &out.CollectionDetails[0], nil + return tfresource.AssertSingleValueResult(out.CollectionDetails) } func findSecurityConfigByID(ctx context.Context, conn *opensearchserverless.Client, id string) (*types.SecurityConfigDetail, error) { @@ -97,15 +84,15 @@ func findSecurityConfigByID(ctx context.Context, conn *opensearchserverless.Clie Id: aws.String(id), } out, err := conn.GetSecurityConfig(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, } + } + if err != nil { return nil, err } @@ -122,15 +109,15 @@ func findSecurityPolicyByNameAndType(ctx context.Context, conn *opensearchserver Type: types.SecurityPolicyType(policyType), } out, err := conn.GetSecurityPolicy(ctx, in) - if err != nil { - var nfe *types.ResourceNotFoundException - if errors.As(err, &nfe) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: in, - } + + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, } + } + if err != nil { return nil, err } @@ -163,13 +150,5 @@ func findLifecyclePolicyByNameAndType(ctx context.Context, conn *opensearchserve return nil, err } - if out == nil || out.LifecyclePolicyDetails == nil || len(out.LifecyclePolicyDetails) == 0 { - return nil, tfresource.NewEmptyResultError(in) - } - - if len(out.LifecyclePolicyDetails) > 1 { - return nil, tfresource.NewTooManyResultsError(len(out.LifecyclePolicyDetails), in) - } - - return &out.LifecyclePolicyDetails[0], nil + return tfresource.AssertSingleValueResult(out.LifecyclePolicyDetails) } diff --git a/internal/service/opensearchserverless/security_policy.go b/internal/service/opensearchserverless/security_policy.go index a962c98f730c..e2e273488ac8 100644 --- a/internal/service/opensearchserverless/security_policy.go +++ b/internal/service/opensearchserverless/security_policy.go @@ -11,8 +11,8 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/opensearchserverless" + "github.com/aws/aws-sdk-go-v2/service/opensearchserverless/document" awstypes "github.com/aws/aws-sdk-go-v2/service/opensearchserverless/types" - "github.com/hashicorp/terraform-plugin-framework-jsontypes/jsontypes" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" @@ -22,26 +22,26 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/id" "github.com/hashicorp/terraform-provider-aws/internal/create" - "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" "github.com/hashicorp/terraform-provider-aws/internal/framework" "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource +// @FrameworkResource(name="Security Policy") func newResourceSecurityPolicy(_ context.Context) (resource.ResourceWithConfigure, error) { return &resourceSecurityPolicy{}, nil } type resourceSecurityPolicyData struct { - Description types.String `tfsdk:"description"` - ID types.String `tfsdk:"id"` - Name types.String `tfsdk:"name"` - Policy jsontypes.Normalized `tfsdk:"policy"` - PolicyVersion types.String `tfsdk:"policy_version"` - Type types.String `tfsdk:"type"` + Description types.String `tfsdk:"description"` + ID types.String `tfsdk:"id"` + Name types.String `tfsdk:"name"` + Policy fwtypes.SmithyJSON[document.Interface] `tfsdk:"policy"` + PolicyVersion types.String `tfsdk:"policy_version"` + Type fwtypes.StringEnum[awstypes.SecurityPolicyType] `tfsdk:"type"` } const ( @@ -76,7 +76,7 @@ func (r *resourceSecurityPolicy) Schema(ctx context.Context, req resource.Schema }, }, names.AttrPolicy: schema.StringAttribute{ - CustomType: jsontypes.NormalizedType{}, + CustomType: fwtypes.NewSmithyJSONType(ctx, document.NewLazyDocument), Required: true, Validators: []validator.String{ stringvalidator.LengthBetween(1, 20480), @@ -89,10 +89,8 @@ func (r *resourceSecurityPolicy) Schema(ctx context.Context, req resource.Schema }, }, names.AttrType: schema.StringAttribute{ - Required: true, - Validators: []validator.String{ - enum.FrameworkValidate[awstypes.SecurityPolicyType](), - }, + CustomType: fwtypes.StringEnumType[awstypes.SecurityPolicyType](), + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -182,8 +180,13 @@ func (r *resourceSecurityPolicy) Update(ctx context.Context, req resource.Update return } - if !plan.Description.Equal(state.Description) || - !plan.Policy.Equal(state.Policy) { + diff, diags := flex.Calculate(ctx, plan, state) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + if diff.HasChanges() { input := &opensearchserverless.UpdateSecurityPolicyInput{} resp.Diagnostics.Append(flex.Expand(ctx, plan, input)...) @@ -220,7 +223,7 @@ func (r *resourceSecurityPolicy) Delete(ctx context.Context, req resource.Delete _, err := conn.DeleteSecurityPolicy(ctx, &opensearchserverless.DeleteSecurityPolicyInput{ ClientToken: aws.String(id.UniqueId()), Name: state.Name.ValueStringPointer(), - Type: awstypes.SecurityPolicyType(state.Type.ValueString()), + Type: state.Type.ValueEnum(), }) if err != nil { var nfe *awstypes.ResourceNotFoundException @@ -245,7 +248,7 @@ func (r *resourceSecurityPolicy) ImportState(ctx context.Context, req resource.I state := resourceSecurityPolicyData{ ID: types.StringValue(parts[0]), Name: types.StringValue(parts[0]), - Type: types.StringValue(parts[1]), + Type: fwtypes.StringEnumValue(awstypes.SecurityPolicyType(parts[1])), } diags := resp.State.Set(ctx, &state) diff --git a/internal/service/opensearchserverless/security_policy_data_source.go b/internal/service/opensearchserverless/security_policy_data_source.go index c4aa9017292e..1ac13df479f4 100644 --- a/internal/service/opensearchserverless/security_policy_data_source.go +++ b/internal/service/opensearchserverless/security_policy_data_source.go @@ -19,7 +19,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_opensearchserverless_security_policy") +// @SDKDataSource("aws_opensearchserverless_security_policy", name="Security Policy") func DataSourceSecurityPolicy() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceSecurityPolicyRead, diff --git a/internal/service/opensearchserverless/service_package_gen.go b/internal/service/opensearchserverless/service_package_gen.go index 0e23ad545cf3..2c16ac2432a3 100644 --- a/internal/service/opensearchserverless/service_package_gen.go +++ b/internal/service/opensearchserverless/service_package_gen.go @@ -39,6 +39,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic return []*types.ServicePackageFrameworkResource{ { Factory: newResourceAccessPolicy, + Name: "Access Policy", }, { Factory: newResourceCollection, @@ -57,6 +58,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic }, { Factory: newResourceSecurityPolicy, + Name: "Security Policy", }, { Factory: newVPCEndpointResource, @@ -70,6 +72,7 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac { Factory: DataSourceSecurityPolicy, TypeName: "aws_opensearchserverless_security_policy", + Name: "Security Policy", }, { Factory: dataSourceVPCEndpoint, diff --git a/website/docs/d/opensearchserverless_collection.html.markdown b/website/docs/d/opensearchserverless_collection.html.markdown index b729fdee8627..6d0a1d67c773 100644 --- a/website/docs/d/opensearchserverless_collection.html.markdown +++ b/website/docs/d/opensearchserverless_collection.html.markdown @@ -36,6 +36,8 @@ This data source exports the following attributes in addition to the arguments a * `created_date` - Date the Collection was created. * `dashboard_endpoint` - Collection-specific endpoint used to access OpenSearch Dashboards. * `description` - Description of the collection. +* `failure_code` - A failure code associated with the collection. +* `failure_reason` - A failure reason associated with the collection. * `kms_key_arn` - The ARN of the Amazon Web Services KMS key used to encrypt the collection. * `last_modified_date` - Date the Collection was last modified. * `standby_replicas` - Indicates whether standby replicas should be used for a collection.