From 4185a3f2d00b78860fd4ec67513151db4f49eba2 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Fri, 16 Aug 2024 18:16:22 -0400 Subject: [PATCH 01/34] newResourceResiliencyPolicy --- .../service/resiliencehub/exports_test.go | 9 + internal/service/resiliencehub/generate.go | 1 + .../resiliencehub/resiliency_policy.go | 651 ++++++++++++++++++ .../resiliencehub/resiliency_policy_test.go | 612 ++++++++++++++++ .../resiliencehub/service_package_gen.go | 10 +- internal/service/resiliencehub/tags_gen.go | 128 ++++ ...iliencehub_resiliency_policy.html.markdown | 134 ++++ 7 files changed, 1544 insertions(+), 1 deletion(-) create mode 100644 internal/service/resiliencehub/exports_test.go create mode 100644 internal/service/resiliencehub/resiliency_policy.go create mode 100644 internal/service/resiliencehub/resiliency_policy_test.go create mode 100644 internal/service/resiliencehub/tags_gen.go create mode 100644 website/docs/r/resiliencehub_resiliency_policy.html.markdown diff --git a/internal/service/resiliencehub/exports_test.go b/internal/service/resiliencehub/exports_test.go new file mode 100644 index 000000000000..d52ff9d16f7a --- /dev/null +++ b/internal/service/resiliencehub/exports_test.go @@ -0,0 +1,9 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resiliencehub + +// Exports for use in tests only. +var ( + ResourceResiliencyPolicy = newResourceResiliencyPolicy +) diff --git a/internal/service/resiliencehub/generate.go b/internal/service/resiliencehub/generate.go index fa6c2d1f1ed6..fe43e1481b65 100644 --- a/internal/service/resiliencehub/generate.go +++ b/internal/service/resiliencehub/generate.go @@ -1,6 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 +//go:generate go run ../../generate/tags/main.go -AWSSDKVersion=2 -ServiceTagsMap -KVTValues -SkipTypesImp -ListTags -ListTagsInIDElem=ResourceArn -ListTagsOutTagsElem=Tags -TagOp=TagResource -TagInIDElem=ResourceArn -UntagOp=UntagResource -UpdateTags //go:generate go run ../../generate/servicepackage/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go new file mode 100644 index 000000000000..86198565fe06 --- /dev/null +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -0,0 +1,651 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resiliencehub + +import ( + "context" + "errors" + "fmt" + "time" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resiliencehub" + awstypes "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-validators/int32validator" + "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/schema/validator" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "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" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_resiliencehub_resiliency_policy", name="Resiliency Policy") +// @Tags(identifierAttribute="arn") +func newResourceResiliencyPolicy(_ context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceResiliencyPolicy{} + + r.SetDefaultCreateTimeout(30 * time.Minute) + r.SetDefaultUpdateTimeout(30 * time.Minute) + r.SetDefaultDeleteTimeout(30 * time.Minute) + + return r, nil +} + +const ( + ResNameResiliencyPolicy = "Resiliency Policy" +) + +type resourceResiliencyPolicy struct { + framework.ResourceWithConfigure + framework.WithImportByID + framework.WithTimeouts +} + +func (r *resourceResiliencyPolicy) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) { + resp.TypeName = "aws_resiliencehub_resiliency_policy" +} + +func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + requiredObjAttrs := map[string]schema.Attribute{ + "rto_in_secs": schema.Int32Attribute{ + Description: "Recovery Time Objective (RTO) in seconds.", + Required: true, + PlanModifiers: []planmodifier.Int32{ + int32planmodifier.UseStateForUnknown(), + int32planmodifier.RequiresReplace(), + }, + Validators: []validator.Int32{ + int32validator.AtLeast(0), + }, + }, + "rpo_in_secs": schema.Int32Attribute{ + Description: "Recovery Point Objective (RPO) in seconds.", + Required: true, + PlanModifiers: []planmodifier.Int32{ + int32planmodifier.UseStateForUnknown(), + int32planmodifier.RequiresReplace(), + }, + Validators: []validator.Int32{ + int32validator.AtLeast(0), + }, + }, + } + + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrID: framework.IDAttribute(), + names.AttrARN: framework.ARNAttributeComputedOnly(), + "policy_name": schema.StringAttribute{ + Description: "The name of the policy.", + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.RegexMatches(regexache.MustCompile( + "^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), "Must match ^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), + }, + }, + "policy_description": schema.StringAttribute{ + Description: "The description for the policy.", + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + Validators: []validator.String{ + stringvalidator.LengthAtMost(500), + }, + }, + "data_location_constraint": schema.StringAttribute{ + Description: "Specifies a high-level geographical location constraint for where resilience policy data can be stored.", + CustomType: fwtypes.StringEnumType[awstypes.DataLocationConstraint](), + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "tier": schema.StringAttribute{ + Description: "The tier for the resiliency policy, ranging from the highest severity (MissionCritical) to lowest (NonCritical).", + CustomType: fwtypes.StringEnumType[awstypes.ResiliencyPolicyTier](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "estimated_cost_tier": schema.StringAttribute{ + Description: "Specifies the estimated cost tier of the resiliency policy.", + CustomType: fwtypes.StringEnumType[awstypes.EstimatedCostTier](), + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + }, + Blocks: map[string]schema.Block{ + "policy": schema.SingleNestedBlock{ + Description: "The resiliency failure policy.", + CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyPolicyModel](ctx), + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.RequiresReplace(), + }, + Validators: []validator.Object{ + objectvalidator.IsRequired(), + }, + Blocks: map[string]schema.Block{ + "az": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), + Description: "The RTO and RPO target to measure resiliency for potential availability zone disruptions.", + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.RequiresReplace(), + }, + Validators: []validator.Object{ + objectvalidator.IsRequired(), + }, + Attributes: requiredObjAttrs, + }, + "hardware": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), + Description: "The RTO and RPO target to measure resiliency for potential infrastructure disruptions.", + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.RequiresReplace(), + }, + Validators: []validator.Object{ + objectvalidator.IsRequired(), + }, + Attributes: requiredObjAttrs, + }, + "software": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), + Description: "The RTO and RPO target to measure resiliency for potential application disruptions.", + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.RequiresReplace(), + }, + Validators: []validator.Object{ + objectvalidator.IsRequired(), + }, + Attributes: requiredObjAttrs, + }, + "region": schema.SingleNestedBlock{ + CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), + Description: "The RTO and RPO target to measure resiliency for potential region disruptions.", + PlanModifiers: []planmodifier.Object{ + objectplanmodifier.RequiresReplace(), + }, + Validators: []validator.Object{ + objectvalidator.AlsoRequires( + path.MatchRelative().AtName("rto_in_secs"), + path.MatchRelative().AtName("rpo_in_secs"), + ), + }, + Attributes: map[string]schema.Attribute{ + "rto_in_secs": schema.Int32Attribute{ + Description: "Recovery Time Objective (RTO) in seconds.", + Optional: true, + PlanModifiers: []planmodifier.Int32{ + int32planmodifier.UseStateForUnknown(), + int32planmodifier.RequiresReplace(), + }, + Validators: []validator.Int32{ + int32validator.AtLeast(0), + }, + }, + "rpo_in_secs": schema.Int32Attribute{ + Description: "Recovery Point Objective (RPO) in seconds.", + Optional: true, + PlanModifiers: []planmodifier.Int32{ + int32planmodifier.UseStateForUnknown(), + int32planmodifier.RequiresReplace(), + }, + Validators: []validator.Int32{ + int32validator.AtLeast(0), + }, + }, + }, + }, + }, + }, + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + Update: true, + Delete: true, + }), + }, + } +} + +func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + var plan resourceResiliencyPolicyData + + conn := r.Meta().ResilienceHubClient(ctx) + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + planPolicyModel, diags := plan.Policy.ToPtr(ctx) + resp.Diagnostics.Append(diags...) + if diags.HasError() { + return + } + + in := &resiliencehub.CreateResiliencyPolicyInput{} + resp.Diagnostics.Append(flex.Expand(ctx, &plan, in, flex.WithIgnoredFieldNamesAppend("Policy"))...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(planPolicyModel.expandPolicy(ctx, in)...) + if resp.Diagnostics.HasError() { + return + } + + in.Tags = getTagsIn(ctx) + + out, err := conn.CreateResiliencyPolicy(ctx, in) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionCreating, ResNameResiliencyPolicy, "", err), + err.Error(), + ) + return + } + if out == nil || out.Policy == nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionCreating, ResNameResiliencyPolicy, "", nil), + errors.New("empty output").Error(), + ) + return + } + + plan.PolicyArn = flex.StringToFramework(ctx, out.Policy.PolicyArn) + plan.setId() + + createTimeout := r.CreateTimeout(ctx, plan.Timeouts) + created, err := waitResiliencyPolicyCreated(ctx, conn, plan.ID.ValueString(), createTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForCreation, ResNameResiliencyPolicy, plan.ID.ValueString(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(flex.Flatten(ctx, created, &plan, flex.WithIgnoredFieldNamesAppend("Policy"))...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(plan.flattenPolicy(ctx, created.Policy)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} + +func (r *resourceResiliencyPolicy) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + var state resourceResiliencyPolicyData + + conn := r.Meta().ResilienceHubClient(ctx) + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + out, err := findResiliencyPolicyByID(ctx, conn, state.ID.ValueString()) + if tfresource.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionSetting, ResNameResiliencyPolicy, state.ID.ValueString(), err), + err.Error(), + ) + return + } + + state.ID = flex.StringToFramework(ctx, out.PolicyArn) + + resp.Diagnostics.Append(flex.Flatten(ctx, out, &state, flex.WithIgnoredFieldNamesAppend("Policy"))...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(state.flattenPolicy(ctx, out.Policy)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) { + var plan, state resourceResiliencyPolicyData + + conn := r.Meta().ResilienceHubClient(ctx) + + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + if !plan.PolicyDescription.Equal(state.PolicyDescription) || + !plan.DataLocationConstraint.Equal(state.DataLocationConstraint) || + !plan.Tier.Equal(state.Tier) { + + in := &resiliencehub.UpdateResiliencyPolicyInput{ + PolicyArn: flex.StringFromFramework(ctx, plan.ID), + } + + if !plan.PolicyDescription.Equal(state.PolicyDescription) { + in.PolicyDescription = flex.StringFromFramework(ctx, plan.PolicyDescription) + } + + if !plan.DataLocationConstraint.Equal(state.DataLocationConstraint) { + in.DataLocationConstraint = plan.DataLocationConstraint.ValueEnum() + } + + if !plan.Tier.Equal(state.Tier) { + in.Tier = plan.Tier.ValueEnum() + } + + out, err := conn.UpdateResiliencyPolicy(ctx, in) + if err != nil { + resp.Diagnostics.AddError(fmt.Sprintf("reading Resilience Hub policy ID (%s)", plan.PolicyArn.String()), err.Error()) + return + } + + plan.ID = flex.StringToFramework(ctx, out.Policy.PolicyArn) + plan.setId() + + updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) + updated, err := waitResiliencyPolicyUpdated(ctx, conn, plan.ID.ValueString(), updateTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForUpdate, ResNameResiliencyPolicy, plan.PolicyArn.String(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(flex.Flatten(ctx, updated, &plan, flex.WithIgnoredFieldNamesAppend("Policy"))...) + if resp.Diagnostics.HasError() { + return + } + + resp.Diagnostics.Append(state.flattenPolicy(ctx, updated.Policy)...) + if resp.Diagnostics.HasError() { + return + } + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) +} + +func (r *resourceResiliencyPolicy) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + var state resourceResiliencyPolicyData + + conn := r.Meta().ResilienceHubClient(ctx) + + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + _, err := conn.DeleteResiliencyPolicy(ctx, &resiliencehub.DeleteResiliencyPolicyInput{ + PolicyArn: flex.StringFromFramework(ctx, state.ID), + }) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + if err != nil { + resp.Diagnostics.AddError(fmt.Sprintf("deleting Resilience Hub policy name (%s)", state.PolicyName.String()), err.Error()) + return + } + + deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) + _, err = waitResiliencyPolicyDeleted(ctx, conn, state.ID.ValueString(), deleteTimeout) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForDeletion, ResNameResiliencyPolicy, state.ID.String(), err), + err.Error(), + ) + return + } +} + +func (r *resourceResiliencyPolicy) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), req, resp) +} + +func (r *resourceResiliencyPolicy) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, request, response) +} + +const ( + resiliencyPolicyTypeAZ = "AZ" + resiliencyPolicyTypeHardware = "Hardware" + resiliencyPolicyTypeSoftware = "Software" + resiliencyPolicyTypeRegion = "Region" + statusChangePending = "Pending" + statusDeleting = "Deleting" + statusNormal = "Normal" + statusUpdated = "Updated" + statusCompleted = "Completed" +) + +func waitResiliencyPolicyCreated(ctx context.Context, conn *resiliencehub.Client, id string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{}, + Target: []string{statusCompleted}, + Refresh: statusResiliencyPolicy(ctx, conn, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*awstypes.ResiliencyPolicy); ok { + return out, err + } + + return nil, err +} + +func waitResiliencyPolicyUpdated(ctx context.Context, conn *resiliencehub.Client, id string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{}, + Target: []string{statusCompleted}, + Refresh: statusResiliencyPolicy(ctx, conn, id), + Timeout: timeout, + NotFoundChecks: 20, + ContinuousTargetOccurence: 2, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*awstypes.ResiliencyPolicy); ok { + return out, err + } + + return nil, err +} + +func waitResiliencyPolicyDeleted(ctx context.Context, conn *resiliencehub.Client, id string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { + stateConf := &retry.StateChangeConf{ + Pending: []string{}, + Target: []string{}, + Refresh: statusResiliencyPolicy(ctx, conn, id), + Timeout: timeout, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + if out, ok := outputRaw.(*awstypes.ResiliencyPolicy); ok { + return out, err + } + + return nil, err +} + +func statusResiliencyPolicy(ctx context.Context, conn *resiliencehub.Client, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + out, err := findResiliencyPolicyByID(ctx, conn, id) + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return out, statusCompleted, nil + } +} + +func findResiliencyPolicyByID(ctx context.Context, conn *resiliencehub.Client, id string) (*awstypes.ResiliencyPolicy, error) { + in := &resiliencehub.DescribeResiliencyPolicyInput{ + PolicyArn: aws.String(id), + } + + out, err := conn.DescribeResiliencyPolicy(ctx, in) + if err != nil { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: in, + } + } + + return nil, err + } + + if out == nil || out.Policy == nil { + return nil, tfresource.NewEmptyResultError(in) + } + + return out.Policy, nil +} + +func (r *resourceResiliencyPolicyData) setId() { + r.ID = r.PolicyArn +} + +func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *resiliencehub.CreateResiliencyPolicyInput) (diags diag.Diagnostics) { + + if in == nil { + return + } + + failurePolicy := make(map[string]awstypes.FailurePolicy) + + // Policy key case must be modified to align with key case in CreateResiliencyPolicy API documentation. + // See https://docs.aws.amazon.com/resilience-hub/latest/APIReference/API_CreateResiliencyPolicy.html + failurePolicyKeyMap := map[string]fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel]{ + resiliencyPolicyTypeAZ: m.AZ, + resiliencyPolicyTypeHardware: m.Hardware, + resiliencyPolicyTypeSoftware: m.Software, + resiliencyPolicyTypeRegion: m.Region} + + for k, v := range failurePolicyKeyMap { + if !v.IsNull() { + resObjModel, d := v.ToPtr(ctx) + diags.Append(d...) + if diags.HasError() { + return + } + failurePolicy[k] = awstypes.FailurePolicy{ + RpoInSecs: resObjModel.RpoInSecs.ValueInt32(), + RtoInSecs: resObjModel.RtoInSecs.ValueInt32(), + } + } + } + + in.Policy = failurePolicy + + return +} + +func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failurePolicy map[string]awstypes.FailurePolicy) (diags diag.Diagnostics) { + + if len(failurePolicy) == 0 { + m.Policy = fwtypes.NewObjectValueOfNull[resourceResiliencyPolicyModel](ctx) + return + } + + newResObjModel := func(policyType string, failurePolicy map[string]awstypes.FailurePolicy) fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] { + if pv, exists := failurePolicy[policyType]; exists { + return fwtypes.NewObjectValueOfMust(ctx, &resourceResiliencyObjectiveModel{ + RpoInSecs: types.Int32Value(pv.RpoInSecs), + RtoInSecs: types.Int32Value(pv.RtoInSecs)}) + } else { + return fwtypes.NewObjectValueOfNull[resourceResiliencyObjectiveModel](ctx) + + } + } + + m.Policy = fwtypes.NewObjectValueOfMust(ctx, &resourceResiliencyPolicyModel{ + newResObjModel(resiliencyPolicyTypeAZ, failurePolicy), + newResObjModel(resiliencyPolicyTypeHardware, failurePolicy), + newResObjModel(resiliencyPolicyTypeSoftware, failurePolicy), + newResObjModel(resiliencyPolicyTypeRegion, failurePolicy), + }) + + return +} + +type resourceResiliencyPolicyData struct { + DataLocationConstraint fwtypes.StringEnum[awstypes.DataLocationConstraint] `tfsdk:"data_location_constraint"` + EstimatedCostTier fwtypes.StringEnum[awstypes.EstimatedCostTier] `tfsdk:"estimated_cost_tier"` + ID types.String `tfsdk:"id"` + Policy fwtypes.ObjectValueOf[resourceResiliencyPolicyModel] `tfsdk:"policy"` + PolicyArn types.String `tfsdk:"arn"` + PolicyDescription types.String `tfsdk:"policy_description"` + PolicyName types.String `tfsdk:"policy_name"` + Tier fwtypes.StringEnum[awstypes.ResiliencyPolicyTier] `tfsdk:"tier"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +type resourceResiliencyPolicyModel struct { + AZ fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] `tfsdk:"az"` + Hardware fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] `tfsdk:"hardware"` + Software fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] `tfsdk:"software"` + Region fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] `tfsdk:"region"` +} + +type resourceResiliencyObjectiveModel struct { + RpoInSecs types.Int32 `tfsdk:"rpo_in_secs"` + RtoInSecs types.Int32 `tfsdk:"rto_in_secs"` +} diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go new file mode 100644 index 000000000000..35cf38fbfa51 --- /dev/null +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -0,0 +1,612 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resiliencehub_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resiliencehub" + "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" + 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" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + "github.com/hashicorp/terraform-provider-aws/names" + + tfresiliencehub "github.com/hashicorp/terraform-provider-aws/internal/service/resiliencehub" +) + +func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), + resource.TestCheckResourceAttrSet(resourceName, "arn"), + resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, "policy_description", rName), + resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2, policy3, policy4, policy5 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + updatedPolicyDescription := "updated policy desecription" + updatedDataLocationConstraint := "SameCountry" + updatedTier := "MissionCritical" + updatedPolicyObjValue := "86400" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, "policy_description", rName), + resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccResiliencyPolicyConfig_updatePolicydescription(rName, updatedPolicyDescription), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), + resource.TestCheckResourceAttr(resourceName, "policy_description", updatedPolicyDescription), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), + testAccCheckResiliencyPolicyNotRecreated(&policy2, &policy3), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", updatedDataLocationConstraint), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy4), + testAccCheckResiliencyPolicyNotRecreated(&policy3, &policy4), + resource.TestCheckResourceAttr(resourceName, "tier", updatedTier), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + Config: testAccResiliencyPolicyConfig_updatePolicy(rName, updatedPolicyObjValue), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy5), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedPolicyObjValue), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedPolicyObjValue), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + }, + }) +} + +func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), + resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.Value", "Other"), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccResiliencyPolicyConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + Config: testAccResiliencyPolicyConfig_tag2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), + resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + }, + }) +} + +func TestAccResilienceHubResiliencyPolicy_disappears(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfresiliencehub.ResourceResiliencyPolicy, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckResiliencyPolicyDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).ResilienceHubClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_resiliencehub_resiliency_policy" { + continue + } + + input := &resiliencehub.DescribeResiliencyPolicyInput{ + PolicyArn: aws.String(rs.Primary.ID), + } + _, err := conn.DescribeResiliencyPolicy(ctx, input) + if errs.IsA[*types.ResourceNotFoundException](err) { + return nil + } + if err != nil { + return create.Error(names.ResilienceHub, create.ErrActionCheckingDestroyed, tfresiliencehub.ResNameResiliencyPolicy, rs.Primary.ID, err) + } + + return create.Error(names.ResilienceHub, create.ErrActionCheckingDestroyed, tfresiliencehub.ResNameResiliencyPolicy, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckResiliencyPolicyExists(ctx context.Context, name string, policy *resiliencehub.DescribeResiliencyPolicyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.ResilienceHub, create.ErrActionCheckingExistence, tfresiliencehub.ResNameResiliencyPolicy, name, errors.New("not found")) + } + + if rs.Primary.ID == "" { + return create.Error(names.ResilienceHub, create.ErrActionCheckingExistence, tfresiliencehub.ResNameResiliencyPolicy, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).ResilienceHubClient(ctx) + resp, err := conn.DescribeResiliencyPolicy(ctx, &resiliencehub.DescribeResiliencyPolicyInput{ + PolicyArn: aws.String(rs.Primary.ID), + }) + + if err != nil { + return create.Error(names.ResilienceHub, create.ErrActionCheckingExistence, tfresiliencehub.ResNameResiliencyPolicy, rs.Primary.ID, err) + } + + *policy = *resp + + return nil + } +} + +func testAccPreCheck(ctx context.Context, t *testing.T) { + conn := acctest.Provider.Meta().(*conns.AWSClient).ResilienceHubClient(ctx) + + input := &resiliencehub.ListResiliencyPoliciesInput{} + _, err := conn.ListResiliencyPolicies(ctx, input) + + if acctest.PreCheckSkipError(err) { + t.Skipf("skipping acceptance testing: %s", err) + } + if err != nil { + t.Fatalf("unexpected PreCheck error: %s", err) + } +} + +func testAccCheckResiliencyPolicyNotRecreated(before, after *resiliencehub.DescribeResiliencyPolicyOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + if before, after := aws.ToString(before.Policy.PolicyArn), aws.ToString(after.Policy.PolicyArn); before != after { + return create.Error(names.ResilienceHub, create.ErrActionCheckingNotRecreated, tfresiliencehub.ResNameResiliencyPolicy, before, errors.New("recreated")) + } + + return nil + } +} + +func testAccResiliencyPolicyConfig_basic(rName string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[1]q + + tier = "NotApplicable" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + Name = %[1]q + Value = "Other" + } +} +`, rName) +} + +func testAccResiliencyPolicyConfig_updatePolicydescription(rName, resPolicyDescValue string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[2]q + + tier = "NotApplicable" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + Name = %[1]q + Value = "Other" + } +} +`, rName, resPolicyDescValue) +} + +func testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, resDataLocConstValue string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[1]q + + tier = "NotApplicable" + + data_location_constraint = %[2]q + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + Name = %[1]q + Value = "Other" + } +} +`, rName, resDataLocConstValue) +} + +func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[1]q + + tier = %[2]q + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + Name = %[1]q + Value = "Other" + } +} +`, rName, resTierValue) +} + +func testAccResiliencyPolicyConfig_updatePolicy(rName, resPolicyObjValue string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[1]q + + tier = "NotApplicable" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = %[2]q + rto_in_secs = %[2]q + } + az { + rpo_in_secs = %[2]q + rto_in_secs = %[2]q + } + hardware { + rpo_in_secs = %[2]q + rto_in_secs = %[2]q + } + software { + rpo_in_secs = %[2]q + rto_in_secs = %[2]q + } + } + + tags = { + Name = %[1]q + Value = "Other" + } +} +`, rName, resPolicyObjValue) +} + +func testAccResiliencyPolicyConfig_tags1(rName, tagKey1, tagValue1 string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[1]q + + tier = "NotApplicable" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1) +} + +func testAccResiliencyPolicyConfig_tag2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = %[1]q + + tier = "NotApplicable" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2) +} diff --git a/internal/service/resiliencehub/service_package_gen.go b/internal/service/resiliencehub/service_package_gen.go index 85401587ecd9..6cb1f1d7d1cf 100644 --- a/internal/service/resiliencehub/service_package_gen.go +++ b/internal/service/resiliencehub/service_package_gen.go @@ -19,7 +19,15 @@ func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.Serv } func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { - return []*types.ServicePackageFrameworkResource{} + return []*types.ServicePackageFrameworkResource{ + { + Factory: newResourceResiliencyPolicy, + Name: "Resiliency Policy", + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrARN, + }, + }, + } } func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePackageSDKDataSource { diff --git a/internal/service/resiliencehub/tags_gen.go b/internal/service/resiliencehub/tags_gen.go new file mode 100644 index 000000000000..7bb3ab0bfa19 --- /dev/null +++ b/internal/service/resiliencehub/tags_gen.go @@ -0,0 +1,128 @@ +// Code generated by internal/generate/tags/main.go; DO NOT EDIT. +package resiliencehub + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resiliencehub" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/logging" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/types/option" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// listTags lists resiliencehub service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func listTags(ctx context.Context, conn *resiliencehub.Client, identifier string, optFns ...func(*resiliencehub.Options)) (tftags.KeyValueTags, error) { + input := &resiliencehub.ListTagsForResourceInput{ + ResourceArn: aws.String(identifier), + } + + output, err := conn.ListTagsForResource(ctx, input, optFns...) + + if err != nil { + return tftags.New(ctx, nil), err + } + + return KeyValueTags(ctx, output.Tags), nil +} + +// ListTags lists resiliencehub service tags and set them in Context. +// It is called from outside this package. +func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { + tags, err := listTags(ctx, meta.(*conns.AWSClient).ResilienceHubClient(ctx), identifier) + + if err != nil { + return err + } + + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(tags) + } + + return nil +} + +// map[string]string handling + +// Tags returns resiliencehub service tags. +func Tags(tags tftags.KeyValueTags) map[string]string { + return tags.Map() +} + +// KeyValueTags creates tftags.KeyValueTags from resiliencehub service tags. +func KeyValueTags(ctx context.Context, tags map[string]string) tftags.KeyValueTags { + return tftags.New(ctx, tags) +} + +// getTagsIn returns resiliencehub service tags from Context. +// nil is returned if there are no input tags. +func getTagsIn(ctx context.Context) map[string]string { + if inContext, ok := tftags.FromContext(ctx); ok { + if tags := Tags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { + return tags + } + } + + return nil +} + +// setTagsOut sets resiliencehub service tags in Context. +func setTagsOut(ctx context.Context, tags map[string]string) { + if inContext, ok := tftags.FromContext(ctx); ok { + inContext.TagsOut = option.Some(KeyValueTags(ctx, tags)) + } +} + +// updateTags updates resiliencehub service tags. +// The identifier is typically the Amazon Resource Name (ARN), although +// it may also be a different identifier depending on the service. +func updateTags(ctx context.Context, conn *resiliencehub.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*resiliencehub.Options)) error { + oldTags := tftags.New(ctx, oldTagsMap) + newTags := tftags.New(ctx, newTagsMap) + + ctx = tflog.SetField(ctx, logging.KeyResourceId, identifier) + + removedTags := oldTags.Removed(newTags) + removedTags = removedTags.IgnoreSystem(names.ResilienceHub) + if len(removedTags) > 0 { + input := &resiliencehub.UntagResourceInput{ + ResourceArn: aws.String(identifier), + TagKeys: removedTags.Keys(), + } + + _, err := conn.UntagResource(ctx, input, optFns...) + + if err != nil { + return fmt.Errorf("untagging resource (%s): %w", identifier, err) + } + } + + updatedTags := oldTags.Updated(newTags) + updatedTags = updatedTags.IgnoreSystem(names.ResilienceHub) + if len(updatedTags) > 0 { + input := &resiliencehub.TagResourceInput{ + ResourceArn: aws.String(identifier), + Tags: Tags(updatedTags), + } + + _, err := conn.TagResource(ctx, input, optFns...) + + if err != nil { + return fmt.Errorf("tagging resource (%s): %w", identifier, err) + } + } + + return nil +} + +// UpdateTags updates resiliencehub service tags. +// It is called from outside this package. +func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { + return updateTags(ctx, meta.(*conns.AWSClient).ResilienceHubClient(ctx), identifier, oldTags, newTags) +} diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown new file mode 100644 index 000000000000..e7120d5baf41 --- /dev/null +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -0,0 +1,134 @@ +--- +subcategory: "Resilience Hub" +layout: "aws" +page_title: "AWS: aws_resiliencehub_resiliency_policy" +description: |- + Terraform resource for managing an AWS Resilience Hub Resiliency Policy. +--- + +# Resource: aws_resiliencehub_resiliency_policy + +Terraform resource for managing an AWS Resilience Hub Resiliency Policy. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_resiliencehub_resiliency_policy" "example" { + + policy_name = "testexample" + policy_description = "testexample" + + tier = "NonCritical" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 86400 + rto_in_secs = 86400 + } + az { + rpo_in_secs = 86400 + rto_in_secs = 86400 + } + hardware { + rpo_in_secs = 86400 + rto_in_secs = 86400 + } + software { + rpo_in_secs = 86400 + rto_in_secs = 86400 + } + } + +} +``` + +## Argument Reference + +The following arguments are required: + +* `policy_name` (String) Name of Resiliency Policy. +* `tier` (String) Resiliency Policy Tier. +* `policy` (Attributes) The type of resiliency policy to be created, including the recovery time objective (RTO) and recovery point objective (RPO) in seconds. See [`policy`](#policy). + +The following arguments are optional: + +* `policy_description` (String) Description of Resiliency Policy. +* `data_location_constraint` (String) Data Location Constraint of the Policy. +* `tags` - (Map Of String) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +### `policy` + +The following arguments are required: + +* `az` - (Attributes) Specifies Availability Zone failure policy. See [`policy.az`](#policy.az) +* `hardware` - (Attributes) Specifies Infrastructure failure policy. See [`policy.hardware`](#policy.hardware) +* `software` - (Attributes) Specifies Application failure policy. See [`policy.software`](#policy.software) + +The following arguments are optional: + +* `region` - (Attributes) Specifies Region failure policy. [`policy.region`](#policy.region) + +### `policy.az` + +The following arguments are required: + +* `rpo_in_secs` - (Number) RPO in seconds. +* `rto_in_secs` - (Number) RTO in seconds. + +### `policy.hardware` + +The following arguments are required: + +* `rpo_in_secs` - (Number) RPO in seconds. +* `rto_in_secs` - (Number) RTO in seconds. + +### `policy.software` + +The following arguments are required: + +* `rpo_in_secs` - (Number) RPO in seconds. +* `rto_in_secs` - (Number) RTO in seconds. + +### `policy.region` + +The following arguments are required: + +* `rpo_in_secs` - (Number) RPO in seconds. +* `rto_in_secs` - (Number) RTO in seconds. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `arn` - ARN of the Resiliency Policy. +* `id` - ID of the Resiliency Policy. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `30m`) +* `update` - (Default `30m`) +* `delete` - (Default `30m`) + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import Resilience Hub Resiliency Policy using the `arn`. For example: + +```terraform +import { + to = aws_resiliencehub_resiliency_policy.example + id = "arn:aws:resiliencehub:us-east-1:123456789012:resiliency-policy/8c1cfa29-d1dd-4421-aa68-c9f64cced4c2" +} +``` + +Using `terraform import`, import Resilience Hub Resiliency Policy using the `arn`. For example: + +```console +% terraform import aws_resiliencehub_resiliency_policy.example arn:aws:resiliencehub:us-east-1:123456789012:resiliency-policy/8c1cfa29-d1dd-4421-aa68-c9f64cced4c2 +``` From beaba3c0d13353e3d597158df085bf96bf9cfd0c Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sat, 17 Aug 2024 21:17:34 -0400 Subject: [PATCH 02/34] updatePolicyName --- .../resiliencehub/resiliency_policy.go | 10 ++- .../resiliencehub/resiliency_policy_test.go | 63 ++++++++++++++++--- 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 86198565fe06..c807b3cf914f 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -98,7 +98,7 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Description: "The name of the policy.", Required: true, PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), + stringplanmodifier.UseStateForUnknown(), }, Validators: []validator.String{ stringvalidator.RegexMatches(regexache.MustCompile( @@ -361,12 +361,17 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda if !plan.PolicyDescription.Equal(state.PolicyDescription) || !plan.DataLocationConstraint.Equal(state.DataLocationConstraint) || - !plan.Tier.Equal(state.Tier) { + !plan.Tier.Equal(state.Tier) || + !plan.PolicyName.Equal(state.PolicyName) { in := &resiliencehub.UpdateResiliencyPolicyInput{ PolicyArn: flex.StringFromFramework(ctx, plan.ID), } + if !plan.PolicyName.Equal(state.PolicyName) { + in.PolicyName = flex.StringFromFramework(ctx, plan.PolicyName) + } + if !plan.PolicyDescription.Equal(state.PolicyDescription) { in.PolicyDescription = flex.StringFromFramework(ctx, plan.PolicyDescription) } @@ -610,7 +615,6 @@ func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failur RtoInSecs: types.Int32Value(pv.RtoInSecs)}) } else { return fwtypes.NewObjectValueOfNull[resourceResiliencyObjectiveModel](ctx) - } } diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 35cf38fbfa51..2f75b3819d5c 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -82,10 +82,11 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var policy1, policy2, policy3, policy4, policy5 resiliencehub.DescribeResiliencyPolicyOutput + var policy1, policy2, policy3, policy4, policy5, policy6 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" + updatedPolicyName := "updated-policy-name" updatedPolicyDescription := "updated policy desecription" updatedDataLocationConstraint := "SameCountry" updatedTier := "MissionCritical" @@ -128,28 +129,37 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccResiliencyPolicyConfig_updatePolicydescription(rName, updatedPolicyDescription), + Config: testAccResiliencyPolicyConfig_updatePolicyName(updatedPolicyName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy_description", updatedPolicyDescription), + resource.TestCheckResourceAttr(resourceName, "policy_name", updatedPolicyName), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, { - Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), + Config: testAccResiliencyPolicyConfig_updatePolicyDescription(rName, updatedPolicyDescription), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), testAccCheckResiliencyPolicyNotRecreated(&policy2, &policy3), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", updatedDataLocationConstraint), + resource.TestCheckResourceAttr(resourceName, "policy_description", updatedPolicyDescription), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, { - Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), + Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy4), testAccCheckResiliencyPolicyNotRecreated(&policy3, &policy4), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", updatedDataLocationConstraint), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + ), + }, + { + Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy5), + testAccCheckResiliencyPolicyNotRecreated(&policy4, &policy5), resource.TestCheckResourceAttr(resourceName, "tier", updatedTier), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), @@ -157,7 +167,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { { Config: testAccResiliencyPolicyConfig_updatePolicy(rName, updatedPolicyObjValue), Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy5), + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy6), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedPolicyObjValue), @@ -384,7 +394,44 @@ resource "aws_resiliencehub_resiliency_policy" "test" { `, rName) } -func testAccResiliencyPolicyConfig_updatePolicydescription(rName, resPolicyDescValue string) string { +func testAccResiliencyPolicyConfig_updatePolicyName(rName string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + policy_name = %[1]q + + policy_description = "testAccResiliencyPolicyConfig_updatePolicyName" + + tier = "NotApplicable" + + data_location_constraint = "AnyLocation" + + policy { + region { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + az { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + hardware { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + software { + rpo_in_secs = 3600 + rto_in_secs = 3600 + } + } + + tags = { + Value = "Other" + } +} +`, rName) +} + +func testAccResiliencyPolicyConfig_updatePolicyDescription(rName, resPolicyDescValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { policy_name = %[1]q From db704a488bbc9761419e61efacc2e284cab9e4ab Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 13:11:37 -0400 Subject: [PATCH 03/34] updateWebDoc --- .../docs/r/resiliencehub_resiliency_policy.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index e7120d5baf41..eab0276be073 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -64,13 +64,13 @@ The following arguments are optional: The following arguments are required: -* `az` - (Attributes) Specifies Availability Zone failure policy. See [`policy.az`](#policy.az) -* `hardware` - (Attributes) Specifies Infrastructure failure policy. See [`policy.hardware`](#policy.hardware) -* `software` - (Attributes) Specifies Application failure policy. See [`policy.software`](#policy.software) +* `az` - (Attributes) Specifies Availability Zone failure policy. See [`policy.az`](#`policy.az`) +* `hardware` - (Attributes) Specifies Infrastructure failure policy. See [`policy.hardware`](#`policy.hardware`) +* `software` - (Attributes) Specifies Application failure policy. See [`policy.software`](#`policy.software`) The following arguments are optional: -* `region` - (Attributes) Specifies Region failure policy. [`policy.region`](#policy.region) +* `region` - (Attributes) Specifies Region failure policy. [`policy.region`](#`policy.region`) ### `policy.az` From 65d83169a18f2ac57d89508c38b3c813958065b9 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 13:22:03 -0400 Subject: [PATCH 04/34] updateWebDoc --- .../docs/r/resiliencehub_resiliency_policy.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index eab0276be073..46b116880e44 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -64,13 +64,13 @@ The following arguments are optional: The following arguments are required: -* `az` - (Attributes) Specifies Availability Zone failure policy. See [`policy.az`](#`policy.az`) -* `hardware` - (Attributes) Specifies Infrastructure failure policy. See [`policy.hardware`](#`policy.hardware`) -* `software` - (Attributes) Specifies Application failure policy. See [`policy.software`](#`policy.software`) +* `az` - (Attributes) Specifies Availability Zone failure policy. See [`policy.az`](#policyaz) +* `hardware` - (Attributes) Specifies Infrastructure failure policy. See [`policy.hardware`](#policyhardware) +* `software` - (Attributes) Specifies Application failure policy. See [`policy.software`](#policysoftware) The following arguments are optional: -* `region` - (Attributes) Specifies Region failure policy. [`policy.region`](#`policy.region`) +* `region` - (Attributes) Specifies Region failure policy. [`policy.region`](#policyregion) ### `policy.az` From cfe746d91339326bcd5d162675c8fab39aae9a6f Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 13:35:04 -0400 Subject: [PATCH 05/34] changelog --- .changelog/38913.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/38913.txt diff --git a/.changelog/38913.txt b/.changelog/38913.txt new file mode 100644 index 000000000000..6be39fcbbf4f --- /dev/null +++ b/.changelog/38913.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_resiliencehub_resiliency_policy +``` From 3a039db341e2287eaaf1c8774aca9025d12aa40b Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 13:40:24 -0400 Subject: [PATCH 06/34] fmt --- internal/service/resiliencehub/resiliency_policy_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 2f75b3819d5c..d4d2c4023606 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -652,7 +652,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tags = { %[2]q = %[3]q - %[4]q = %[5]q + %[4]q = %[5]q } } `, rName, tagKey1, tagValue1, tagKey2, tagValue2) From b3f7f395f99c07547abb1c3f6f0ed5a8f754e8d6 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 13:46:43 -0400 Subject: [PATCH 07/34] fmtTest --- .../resiliencehub/resiliency_policy_test.go | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index d4d2c4023606..12646f7551e2 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -359,7 +359,7 @@ func testAccCheckResiliencyPolicyNotRecreated(before, after *resiliencehub.Descr func testAccResiliencyPolicyConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[1]q @@ -388,7 +388,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tags = { Name = %[1]q - Value = "Other" + Value = "Other" } } `, rName) @@ -397,7 +397,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updatePolicyName(rName string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = "testAccResiliencyPolicyConfig_updatePolicyName" @@ -425,7 +425,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } tags = { - Value = "Other" + Value = "Other" } } `, rName) @@ -434,7 +434,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updatePolicyDescription(rName, resPolicyDescValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[2]q @@ -463,7 +463,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tags = { Name = %[1]q - Value = "Other" + Value = "Other" } } `, rName, resPolicyDescValue) @@ -472,7 +472,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, resDataLocConstValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[1]q @@ -501,7 +501,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tags = { Name = %[1]q - Value = "Other" + Value = "Other" } } `, rName, resDataLocConstValue) @@ -510,7 +510,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[1]q @@ -539,7 +539,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tags = { Name = %[1]q - Value = "Other" + Value = "Other" } } `, rName, resTierValue) @@ -548,7 +548,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updatePolicy(rName, resPolicyObjValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[1]q @@ -577,7 +577,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tags = { Name = %[1]q - Value = "Other" + Value = "Other" } } `, rName, resPolicyObjValue) @@ -586,7 +586,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_tags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[1]q @@ -623,7 +623,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_tag2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + policy_name = %[1]q policy_description = %[1]q From ad4a586771373b6972b9918dcf491a95b4d56e52 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 13:56:50 -0400 Subject: [PATCH 08/34] fmtTest --- .../service/resiliencehub/resiliency_policy_test.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 12646f7551e2..d6c145e30851 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -20,9 +20,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" "github.com/hashicorp/terraform-provider-aws/internal/errs" - "github.com/hashicorp/terraform-provider-aws/names" - tfresiliencehub "github.com/hashicorp/terraform-provider-aws/internal/service/resiliencehub" + "github.com/hashicorp/terraform-provider-aws/names" ) func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { @@ -387,7 +386,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } tags = { - Name = %[1]q + Name = %[1]q Value = "Other" } } @@ -462,7 +461,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } tags = { - Name = %[1]q + Name = %[1]q Value = "Other" } } @@ -500,7 +499,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } tags = { - Name = %[1]q + Name = %[1]q Value = "Other" } } @@ -538,7 +537,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } tags = { - Name = %[1]q + Name = %[1]q Value = "Other" } } @@ -576,7 +575,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } tags = { - Name = %[1]q + Name = %[1]q Value = "Other" } } From d8af59da38f51e07415ad68d84585282d664f6dc Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 14:04:05 -0400 Subject: [PATCH 09/34] extraSpace --- website/docs/r/resiliencehub_resiliency_policy.html.markdown | 4 ---- 1 file changed, 4 deletions(-) diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index 46b116880e44..3b2935c7fdc6 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -12,11 +12,8 @@ Terraform resource for managing an AWS Resilience Hub Resiliency Policy. ## Example Usage -### Basic Usage - ```terraform resource "aws_resiliencehub_resiliency_policy" "example" { - policy_name = "testexample" policy_description = "testexample" @@ -42,7 +39,6 @@ resource "aws_resiliencehub_resiliency_policy" "example" { rto_in_secs = 86400 } } - } ``` From 592137e29c3507e14489cbd32b6da432cc5b9b25 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 14:47:23 -0400 Subject: [PATCH 10/34] codeQuality --- .../service/resiliencehub/resiliency_policy.go | 18 ++++++++---------- .../resiliencehub/resiliency_policy_test.go | 8 ++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index c807b3cf914f..15f04d6b72c6 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -144,7 +144,7 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), }, Blocks: map[string]schema.Block{ - "policy": schema.SingleNestedBlock{ + names.AttrPolicy: schema.SingleNestedBlock{ Description: "The resiliency failure policy.", CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyPolicyModel](ctx), PlanModifiers: []planmodifier.Object{ @@ -187,7 +187,7 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche }, Attributes: requiredObjAttrs, }, - "region": schema.SingleNestedBlock{ + names.AttrRegion: schema.SingleNestedBlock{ CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), Description: "The RTO and RPO target to measure resiliency for potential region disruptions.", PlanModifiers: []planmodifier.Object{ @@ -363,7 +363,6 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda !plan.DataLocationConstraint.Equal(state.DataLocationConstraint) || !plan.Tier.Equal(state.Tier) || !plan.PolicyName.Equal(state.PolicyName) { - in := &resiliencehub.UpdateResiliencyPolicyInput{ PolicyArn: flex.StringFromFramework(ctx, plan.ID), } @@ -562,14 +561,13 @@ func findResiliencyPolicyByID(ctx context.Context, conn *resiliencehub.Client, i return out.Policy, nil } -func (r *resourceResiliencyPolicyData) setId() { - r.ID = r.PolicyArn +func (m *resourceResiliencyPolicyData) setId() { + m.ID = m.PolicyArn } func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *resiliencehub.CreateResiliencyPolicyInput) (diags diag.Diagnostics) { - if in == nil { - return + return diags } failurePolicy := make(map[string]awstypes.FailurePolicy) @@ -587,7 +585,7 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re resObjModel, d := v.ToPtr(ctx) diags.Append(d...) if diags.HasError() { - return + return diags } failurePolicy[k] = awstypes.FailurePolicy{ RpoInSecs: resObjModel.RpoInSecs.ValueInt32(), @@ -598,14 +596,14 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re in.Policy = failurePolicy - return + return diags } func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failurePolicy map[string]awstypes.FailurePolicy) (diags diag.Diagnostics) { if len(failurePolicy) == 0 { m.Policy = fwtypes.NewObjectValueOfNull[resourceResiliencyPolicyModel](ctx) - return + return diags } newResObjModel := func(policyType string, failurePolicy map[string]awstypes.FailurePolicy) fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] { diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index d6c145e30851..19054d39f4a0 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -38,7 +38,6 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) - acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), @@ -49,8 +48,8 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { Config: testAccResiliencyPolicyConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), - resource.TestCheckResourceAttrSet(resourceName, "arn"), - resource.TestCheckResourceAttrSet(resourceName, "id"), + resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), + resource.TestCheckResourceAttrSet(resourceName, names.AttrID), resource.TestCheckResourceAttr(resourceName, "policy_name", rName), resource.TestCheckResourceAttr(resourceName, "policy_description", rName), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), @@ -95,7 +94,6 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) - acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), @@ -196,7 +194,6 @@ func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) - acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), @@ -259,7 +256,6 @@ func TestAccResilienceHubResiliencyPolicy_disappears(t *testing.T) { PreCheck: func() { acctest.PreCheck(ctx, t) acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) - acctest.PreCheckPartitionHasService(t, names.ResilienceHubServiceID) testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), From 3c9bdfddae499e13c49ea48007b7f2eee2c102f2 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 15:11:21 -0400 Subject: [PATCH 11/34] flattenResp --- .../resiliencehub/resiliency_policy.go | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 15f04d6b72c6..9adc1685df6c 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -297,11 +297,8 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea if resp.Diagnostics.HasError() { return } - - resp.Diagnostics.Append(plan.flattenPolicy(ctx, created.Policy)...) - if resp.Diagnostics.HasError() { - return - } + + plan.flattenPolicy(ctx, created.Policy) resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) } @@ -336,10 +333,7 @@ func (r *resourceResiliencyPolicy) Read(ctx context.Context, req resource.ReadRe return } - resp.Diagnostics.Append(state.flattenPolicy(ctx, out.Policy)...) - if resp.Diagnostics.HasError() { - return - } + state.flattenPolicy(ctx, out.Policy) resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) } @@ -406,11 +400,8 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda if resp.Diagnostics.HasError() { return } - - resp.Diagnostics.Append(state.flattenPolicy(ctx, updated.Policy)...) - if resp.Diagnostics.HasError() { - return - } + + state.flattenPolicy(ctx, updated.Policy) } resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...) @@ -599,11 +590,9 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re return diags } -func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failurePolicy map[string]awstypes.FailurePolicy) (diags diag.Diagnostics) { - +func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failurePolicy map[string]awstypes.FailurePolicy) { if len(failurePolicy) == 0 { m.Policy = fwtypes.NewObjectValueOfNull[resourceResiliencyPolicyModel](ctx) - return diags } newResObjModel := func(policyType string, failurePolicy map[string]awstypes.FailurePolicy) fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] { @@ -622,8 +611,6 @@ func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failur newResObjModel(resiliencyPolicyTypeSoftware, failurePolicy), newResObjModel(resiliencyPolicyTypeRegion, failurePolicy), }) - - return } type resourceResiliencyPolicyData struct { From a85bcfaab7dd56301a467757e7db9779a455970c Mon Sep 17 00:00:00 2001 From: coderaycer Date: Sun, 18 Aug 2024 15:15:15 -0400 Subject: [PATCH 12/34] goFmt --- internal/service/resiliencehub/resiliency_policy.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 9adc1685df6c..3d38e2e51351 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -297,7 +297,7 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea if resp.Diagnostics.HasError() { return } - + plan.flattenPolicy(ctx, created.Policy) resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) @@ -400,7 +400,7 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda if resp.Diagnostics.HasError() { return } - + state.flattenPolicy(ctx, updated.Policy) } From 9a2bd2126dd288335a013297ddf6275255848d75 Mon Sep 17 00:00:00 2001 From: coderaycer Date: Wed, 4 Sep 2024 18:27:50 -0400 Subject: [PATCH 13/34] tftagsMap --- internal/service/resiliencehub/resiliency_policy.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 3d38e2e51351..5a958d530d8a 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -622,8 +622,8 @@ type resourceResiliencyPolicyData struct { PolicyDescription types.String `tfsdk:"policy_description"` PolicyName types.String `tfsdk:"policy_name"` Tier fwtypes.StringEnum[awstypes.ResiliencyPolicyTier] `tfsdk:"tier"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` + Tags tftags.Map `tfsdk:"tags"` + TagsAll tftags.Map `tfsdk:"tags_all"` Timeouts timeouts.Value `tfsdk:"timeouts"` } From 8de478cde488f0784722704937f9be3a12b07311 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 11:44:52 -0700 Subject: [PATCH 14/34] Removes unneeded `id` attribute --- .../resiliencehub/resiliency_policy.go | 53 ++++++++----------- .../resiliencehub/resiliency_policy_test.go | 45 ++++++++++------ ...iliencehub_resiliency_policy.html.markdown | 1 - 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 5a958d530d8a..6482c16c954e 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -56,7 +56,6 @@ const ( type resourceResiliencyPolicy struct { framework.ResourceWithConfigure - framework.WithImportByID framework.WithTimeouts } @@ -92,7 +91,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - names.AttrID: framework.IDAttribute(), names.AttrARN: framework.ARNAttributeComputedOnly(), "policy_name": schema.StringAttribute{ Description: "The name of the policy.", @@ -281,13 +279,12 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea } plan.PolicyArn = flex.StringToFramework(ctx, out.Policy.PolicyArn) - plan.setId() createTimeout := r.CreateTimeout(ctx, plan.Timeouts) - created, err := waitResiliencyPolicyCreated(ctx, conn, plan.ID.ValueString(), createTimeout) + created, err := waitResiliencyPolicyCreated(ctx, conn, plan.PolicyArn.ValueString(), createTimeout) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForCreation, ResNameResiliencyPolicy, plan.ID.ValueString(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForCreation, ResNameResiliencyPolicy, plan.PolicyArn.ValueString(), err), err.Error(), ) return @@ -313,20 +310,20 @@ func (r *resourceResiliencyPolicy) Read(ctx context.Context, req resource.ReadRe return } - out, err := findResiliencyPolicyByID(ctx, conn, state.ID.ValueString()) + out, err := findResiliencyPolicyByARN(ctx, conn, state.PolicyArn.ValueString()) if tfresource.NotFound(err) { resp.State.RemoveResource(ctx) return } if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionSetting, ResNameResiliencyPolicy, state.ID.ValueString(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionSetting, ResNameResiliencyPolicy, state.PolicyArn.ValueString(), err), err.Error(), ) return } - state.ID = flex.StringToFramework(ctx, out.PolicyArn) + state.PolicyArn = flex.StringToFramework(ctx, out.PolicyArn) resp.Diagnostics.Append(flex.Flatten(ctx, out, &state, flex.WithIgnoredFieldNamesAppend("Policy"))...) if resp.Diagnostics.HasError() { @@ -358,7 +355,7 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda !plan.Tier.Equal(state.Tier) || !plan.PolicyName.Equal(state.PolicyName) { in := &resiliencehub.UpdateResiliencyPolicyInput{ - PolicyArn: flex.StringFromFramework(ctx, plan.ID), + PolicyArn: flex.StringFromFramework(ctx, plan.PolicyArn), } if !plan.PolicyName.Equal(state.PolicyName) { @@ -383,11 +380,10 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda return } - plan.ID = flex.StringToFramework(ctx, out.Policy.PolicyArn) - plan.setId() + plan.PolicyArn = flex.StringToFramework(ctx, out.Policy.PolicyArn) updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) - updated, err := waitResiliencyPolicyUpdated(ctx, conn, plan.ID.ValueString(), updateTimeout) + updated, err := waitResiliencyPolicyUpdated(ctx, conn, plan.PolicyArn.ValueString(), updateTimeout) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForUpdate, ResNameResiliencyPolicy, plan.PolicyArn.String(), err), @@ -418,7 +414,7 @@ func (r *resourceResiliencyPolicy) Delete(ctx context.Context, req resource.Dele } _, err := conn.DeleteResiliencyPolicy(ctx, &resiliencehub.DeleteResiliencyPolicyInput{ - PolicyArn: flex.StringFromFramework(ctx, state.ID), + PolicyArn: flex.StringFromFramework(ctx, state.PolicyArn), }) if errs.IsA[*awstypes.ResourceNotFoundException](err) { @@ -431,10 +427,10 @@ func (r *resourceResiliencyPolicy) Delete(ctx context.Context, req resource.Dele } deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) - _, err = waitResiliencyPolicyDeleted(ctx, conn, state.ID.ValueString(), deleteTimeout) + _, err = waitResiliencyPolicyDeleted(ctx, conn, state.PolicyArn.ValueString(), deleteTimeout) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForDeletion, ResNameResiliencyPolicy, state.ID.String(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForDeletion, ResNameResiliencyPolicy, state.PolicyArn.String(), err), err.Error(), ) return @@ -442,7 +438,7 @@ func (r *resourceResiliencyPolicy) Delete(ctx context.Context, req resource.Dele } func (r *resourceResiliencyPolicy) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), req, resp) + resource.ImportStatePassthroughID(ctx, path.Root(names.AttrARN), req, resp) } func (r *resourceResiliencyPolicy) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { @@ -461,11 +457,11 @@ const ( statusCompleted = "Completed" ) -func waitResiliencyPolicyCreated(ctx context.Context, conn *resiliencehub.Client, id string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { +func waitResiliencyPolicyCreated(ctx context.Context, conn *resiliencehub.Client, arn string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { stateConf := &retry.StateChangeConf{ Pending: []string{}, Target: []string{statusCompleted}, - Refresh: statusResiliencyPolicy(ctx, conn, id), + Refresh: statusResiliencyPolicy(ctx, conn, arn), Timeout: timeout, NotFoundChecks: 20, ContinuousTargetOccurence: 2, @@ -479,11 +475,11 @@ func waitResiliencyPolicyCreated(ctx context.Context, conn *resiliencehub.Client return nil, err } -func waitResiliencyPolicyUpdated(ctx context.Context, conn *resiliencehub.Client, id string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { +func waitResiliencyPolicyUpdated(ctx context.Context, conn *resiliencehub.Client, arn string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { stateConf := &retry.StateChangeConf{ Pending: []string{}, Target: []string{statusCompleted}, - Refresh: statusResiliencyPolicy(ctx, conn, id), + Refresh: statusResiliencyPolicy(ctx, conn, arn), Timeout: timeout, NotFoundChecks: 20, ContinuousTargetOccurence: 2, @@ -497,11 +493,11 @@ func waitResiliencyPolicyUpdated(ctx context.Context, conn *resiliencehub.Client return nil, err } -func waitResiliencyPolicyDeleted(ctx context.Context, conn *resiliencehub.Client, id string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { +func waitResiliencyPolicyDeleted(ctx context.Context, conn *resiliencehub.Client, arn string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { stateConf := &retry.StateChangeConf{ Pending: []string{}, Target: []string{}, - Refresh: statusResiliencyPolicy(ctx, conn, id), + Refresh: statusResiliencyPolicy(ctx, conn, arn), Timeout: timeout, } @@ -513,9 +509,9 @@ func waitResiliencyPolicyDeleted(ctx context.Context, conn *resiliencehub.Client return nil, err } -func statusResiliencyPolicy(ctx context.Context, conn *resiliencehub.Client, id string) retry.StateRefreshFunc { +func statusResiliencyPolicy(ctx context.Context, conn *resiliencehub.Client, arn string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - out, err := findResiliencyPolicyByID(ctx, conn, id) + out, err := findResiliencyPolicyByARN(ctx, conn, arn) if tfresource.NotFound(err) { return nil, "", nil } @@ -528,9 +524,9 @@ func statusResiliencyPolicy(ctx context.Context, conn *resiliencehub.Client, id } } -func findResiliencyPolicyByID(ctx context.Context, conn *resiliencehub.Client, id string) (*awstypes.ResiliencyPolicy, error) { +func findResiliencyPolicyByARN(ctx context.Context, conn *resiliencehub.Client, arn string) (*awstypes.ResiliencyPolicy, error) { in := &resiliencehub.DescribeResiliencyPolicyInput{ - PolicyArn: aws.String(id), + PolicyArn: aws.String(arn), } out, err := conn.DescribeResiliencyPolicy(ctx, in) @@ -552,10 +548,6 @@ func findResiliencyPolicyByID(ctx context.Context, conn *resiliencehub.Client, i return out.Policy, nil } -func (m *resourceResiliencyPolicyData) setId() { - m.ID = m.PolicyArn -} - func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *resiliencehub.CreateResiliencyPolicyInput) (diags diag.Diagnostics) { if in == nil { return diags @@ -616,7 +608,6 @@ func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failur type resourceResiliencyPolicyData struct { DataLocationConstraint fwtypes.StringEnum[awstypes.DataLocationConstraint] `tfsdk:"data_location_constraint"` EstimatedCostTier fwtypes.StringEnum[awstypes.EstimatedCostTier] `tfsdk:"estimated_cost_tier"` - ID types.String `tfsdk:"id"` Policy fwtypes.ObjectValueOf[resourceResiliencyPolicyModel] `tfsdk:"policy"` PolicyArn types.String `tfsdk:"arn"` PolicyDescription types.String `tfsdk:"policy_description"` diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 19054d39f4a0..95504e548a3b 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -48,8 +48,7 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { Config: testAccResiliencyPolicyConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), - resource.TestCheckResourceAttrSet(resourceName, names.AttrARN), - resource.TestCheckResourceAttrSet(resourceName, names.AttrID), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+$`)), resource.TestCheckResourceAttr(resourceName, "policy_name", rName), resource.TestCheckResourceAttr(resourceName, "policy_description", rName), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), @@ -62,13 +61,14 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, }, }, }) @@ -121,9 +121,11 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { Config: testAccResiliencyPolicyConfig_updatePolicyName(updatedPolicyName), @@ -212,9 +214,11 @@ func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { Config: testAccResiliencyPolicyConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), @@ -284,7 +288,7 @@ func testAccCheckResiliencyPolicyDestroy(ctx context.Context) resource.TestCheck } input := &resiliencehub.DescribeResiliencyPolicyInput{ - PolicyArn: aws.String(rs.Primary.ID), + PolicyArn: aws.String(rs.Primary.Attributes[names.AttrARN]), } _, err := conn.DescribeResiliencyPolicy(ctx, input) if errs.IsA[*types.ResourceNotFoundException](err) { @@ -308,13 +312,13 @@ func testAccCheckResiliencyPolicyExists(ctx context.Context, name string, policy return create.Error(names.ResilienceHub, create.ErrActionCheckingExistence, tfresiliencehub.ResNameResiliencyPolicy, name, errors.New("not found")) } - if rs.Primary.ID == "" { + if rs.Primary.Attributes[names.AttrARN] == "" { return create.Error(names.ResilienceHub, create.ErrActionCheckingExistence, tfresiliencehub.ResNameResiliencyPolicy, name, errors.New("not set")) } conn := acctest.Provider.Meta().(*conns.AWSClient).ResilienceHubClient(ctx) resp, err := conn.DescribeResiliencyPolicy(ctx, &resiliencehub.DescribeResiliencyPolicyInput{ - PolicyArn: aws.String(rs.Primary.ID), + PolicyArn: aws.String(rs.Primary.Attributes[names.AttrARN]), }) if err != nil { @@ -327,6 +331,17 @@ func testAccCheckResiliencyPolicyExists(ctx context.Context, name string, policy } } +func testAccAttrImportStateIdFunc(resourceName, attrName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not found: %s", resourceName) + } + + return rs.Primary.Attributes[attrName], nil + } +} + func testAccPreCheck(ctx context.Context, t *testing.T) { conn := acctest.Provider.Meta().(*conns.AWSClient).ResilienceHubClient(ctx) diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index 3b2935c7fdc6..a0ef56d525e7 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -101,7 +101,6 @@ The following arguments are required: This resource exports the following attributes in addition to the arguments above: * `arn` - ARN of the Resiliency Policy. -* `id` - ID of the Resiliency Policy. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Timeouts From b57bd29562f0f9140262dc175b3811c3ec4c9029 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 11:54:28 -0700 Subject: [PATCH 15/34] Replaces `policy_name` with `name` --- .../resiliencehub/resiliency_policy.go | 4 +-- .../resiliencehub/resiliency_policy_test.go | 28 +++++++++---------- ...iliencehub_resiliency_policy.html.markdown | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 6482c16c954e..4f8af927c32a 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -92,7 +92,7 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ names.AttrARN: framework.ARNAttributeComputedOnly(), - "policy_name": schema.StringAttribute{ + names.AttrName: schema.StringAttribute{ Description: "The name of the policy.", Required: true, PlanModifiers: []planmodifier.String{ @@ -611,7 +611,7 @@ type resourceResiliencyPolicyData struct { Policy fwtypes.ObjectValueOf[resourceResiliencyPolicyModel] `tfsdk:"policy"` PolicyArn types.String `tfsdk:"arn"` PolicyDescription types.String `tfsdk:"policy_description"` - PolicyName types.String `tfsdk:"policy_name"` + PolicyName types.String `tfsdk:"name"` Tier fwtypes.StringEnum[awstypes.ResiliencyPolicyTier] `tfsdk:"tier"` Tags tftags.Map `tfsdk:"tags"` TagsAll tftags.Map `tfsdk:"tags_all"` diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 95504e548a3b..86ddf104ab51 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -49,7 +49,7 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+$`)), - resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, "policy_description", rName), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), @@ -104,7 +104,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { Config: testAccResiliencyPolicyConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, "policy_description", rName), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), @@ -132,7 +132,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy_name", updatedPolicyName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, updatedPolicyName), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, @@ -206,7 +206,7 @@ func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { Config: testAccResiliencyPolicyConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), resource.TestCheckResourceAttr(resourceName, "tags.Value", "Other"), @@ -224,7 +224,7 @@ func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { Config: testAccResiliencyPolicyConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), @@ -235,7 +235,7 @@ func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy_name", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), @@ -369,7 +369,7 @@ func testAccCheckResiliencyPolicyNotRecreated(before, after *resiliencehub.Descr func testAccResiliencyPolicyConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[1]q @@ -407,7 +407,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updatePolicyName(rName string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = "testAccResiliencyPolicyConfig_updatePolicyName" @@ -444,7 +444,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updatePolicyDescription(rName, resPolicyDescValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[2]q @@ -482,7 +482,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, resDataLocConstValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[1]q @@ -520,7 +520,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[1]q @@ -558,7 +558,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_updatePolicy(rName, resPolicyObjValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[1]q @@ -596,7 +596,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_tags1(rName, tagKey1, tagValue1 string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[1]q @@ -633,7 +633,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { func testAccResiliencyPolicyConfig_tag2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { - policy_name = %[1]q + name = %[1]q policy_description = %[1]q diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index a0ef56d525e7..d9632b6aca58 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -46,7 +46,7 @@ resource "aws_resiliencehub_resiliency_policy" "example" { The following arguments are required: -* `policy_name` (String) Name of Resiliency Policy. +* `name` (String) Name of Resiliency Policy. * `tier` (String) Resiliency Policy Tier. * `policy` (Attributes) The type of resiliency policy to be created, including the recovery time objective (RTO) and recovery point objective (RPO) in seconds. See [`policy`](#policy). From 887828bc07abae43b1ed62b96ce52f0c0d973322 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 12:01:00 -0700 Subject: [PATCH 16/34] Replaces `policy_description` with `description` --- .../resiliencehub/resiliency_policy.go | 20 ++++++++--------- .../resiliencehub/resiliency_policy_test.go | 22 +++++++++---------- ...iliencehub_resiliency_policy.html.markdown | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 4f8af927c32a..8d49a55dcbeb 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -92,25 +92,25 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ names.AttrARN: framework.ARNAttributeComputedOnly(), - names.AttrName: schema.StringAttribute{ - Description: "The name of the policy.", - Required: true, + names.AttrDescription: schema.StringAttribute{ + Description: "The description for the policy.", + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, Validators: []validator.String{ - stringvalidator.RegexMatches(regexache.MustCompile( - "^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), "Must match ^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), + stringvalidator.LengthAtMost(500), }, }, - "policy_description": schema.StringAttribute{ - Description: "The description for the policy.", - Optional: true, + names.AttrName: schema.StringAttribute{ + Description: "The name of the policy.", + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), }, Validators: []validator.String{ - stringvalidator.LengthAtMost(500), + stringvalidator.RegexMatches(regexache.MustCompile( + "^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), "Must match ^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), }, }, "data_location_constraint": schema.StringAttribute{ @@ -610,7 +610,7 @@ type resourceResiliencyPolicyData struct { EstimatedCostTier fwtypes.StringEnum[awstypes.EstimatedCostTier] `tfsdk:"estimated_cost_tier"` Policy fwtypes.ObjectValueOf[resourceResiliencyPolicyModel] `tfsdk:"policy"` PolicyArn types.String `tfsdk:"arn"` - PolicyDescription types.String `tfsdk:"policy_description"` + PolicyDescription types.String `tfsdk:"description"` PolicyName types.String `tfsdk:"name"` Tier fwtypes.StringEnum[awstypes.ResiliencyPolicyTier] `tfsdk:"tier"` Tags tftags.Map `tfsdk:"tags"` diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 86ddf104ab51..a8c6ffa931b0 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -50,7 +50,7 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+$`)), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, "policy_description", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), @@ -105,7 +105,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, "policy_description", rName), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), @@ -141,7 +141,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), testAccCheckResiliencyPolicyNotRecreated(&policy2, &policy3), - resource.TestCheckResourceAttr(resourceName, "policy_description", updatedPolicyDescription), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updatedPolicyDescription), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, @@ -371,7 +371,7 @@ func testAccResiliencyPolicyConfig_basic(rName string) string { resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[1]q + description = %[1]q tier = "NotApplicable" @@ -409,7 +409,7 @@ func testAccResiliencyPolicyConfig_updatePolicyName(rName string) string { resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = "testAccResiliencyPolicyConfig_updatePolicyName" + description = "testAccResiliencyPolicyConfig_updatePolicyName" tier = "NotApplicable" @@ -446,7 +446,7 @@ func testAccResiliencyPolicyConfig_updatePolicyDescription(rName, resPolicyDescV resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[2]q + description = %[2]q tier = "NotApplicable" @@ -484,7 +484,7 @@ func testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, resDataLo resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[1]q + description = %[1]q tier = "NotApplicable" @@ -522,7 +522,7 @@ func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[1]q + description = %[1]q tier = %[2]q @@ -560,7 +560,7 @@ func testAccResiliencyPolicyConfig_updatePolicy(rName, resPolicyObjValue string) resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[1]q + description = %[1]q tier = "NotApplicable" @@ -598,7 +598,7 @@ func testAccResiliencyPolicyConfig_tags1(rName, tagKey1, tagValue1 string) strin resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[1]q + description = %[1]q tier = "NotApplicable" @@ -635,7 +635,7 @@ func testAccResiliencyPolicyConfig_tag2(rName, tagKey1, tagValue1, tagKey2, tagV resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - policy_description = %[1]q + description = %[1]q tier = "NotApplicable" diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index d9632b6aca58..3d7e2d675be4 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -52,7 +52,7 @@ The following arguments are required: The following arguments are optional: -* `policy_description` (String) Description of Resiliency Policy. +* `description` (String) Description of Resiliency Policy. * `data_location_constraint` (String) Data Location Constraint of the Policy. * `tags` - (Map Of String) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. From f6d5e13d4b7bde05133df1c947ee034c1b5fa9a7 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 12:11:50 -0700 Subject: [PATCH 17/34] Removes optional attributes from `basic` test --- .../resiliencehub/resiliency_policy_test.go | 33 ++----------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index a8c6ffa931b0..0faaaa346c05 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -50,7 +50,7 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+$`)), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), + resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), @@ -105,7 +105,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), + resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), @@ -116,7 +116,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, @@ -202,24 +202,6 @@ func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ - { - Config: testAccResiliencyPolicyConfig_basic(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), - resource.TestCheckResourceAttr(resourceName, "tags.Name", rName), - resource.TestCheckResourceAttr(resourceName, "tags.Value", "Other"), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), - ImportStateVerify: true, - ImportStateVerifyIdentifierAttribute: names.AttrARN, - }, { Config: testAccResiliencyPolicyConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), Check: resource.ComposeTestCheckFunc( @@ -371,12 +353,8 @@ func testAccResiliencyPolicyConfig_basic(rName string) string { resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - description = %[1]q - tier = "NotApplicable" - data_location_constraint = "AnyLocation" - policy { region { rpo_in_secs = 3600 @@ -395,11 +373,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { rto_in_secs = 3600 } } - - tags = { - Name = %[1]q - Value = "Other" - } } `, rName) } From bc1115348199567fbd10049da52cecabe4fd5b5a Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 12:21:51 -0700 Subject: [PATCH 18/34] Tweaks `name` validation and updates documentation --- internal/service/resiliencehub/resiliency_policy.go | 4 ++-- website/docs/r/resiliencehub_resiliency_policy.html.markdown | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 8d49a55dcbeb..0039da250860 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -109,8 +109,8 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche stringplanmodifier.UseStateForUnknown(), }, Validators: []validator.String{ - stringvalidator.RegexMatches(regexache.MustCompile( - "^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), "Must match ^[A-Za-z0-9][A-Za-z0-9_\\-]{1,59}$"), + stringvalidator.LengthBetween(2, 60), + stringvalidator.RegexMatches(regexache.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]+$`), "Must start with an alphanumeric character and contain alphanumeric characters, underscores, or hyphens"), }, }, "data_location_constraint": schema.StringAttribute{ diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index 3d7e2d675be4..101514759eef 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -47,6 +47,8 @@ resource "aws_resiliencehub_resiliency_policy" "example" { The following arguments are required: * `name` (String) Name of Resiliency Policy. + Must be between 2 and 60 characters long. + Must start with an alphanumeric character and contain alphanumeric characters, underscores, or hyphens. * `tier` (String) Resiliency Policy Tier. * `policy` (Attributes) The type of resiliency policy to be created, including the recovery time objective (RTO) and recovery point objective (RPO) in seconds. See [`policy`](#policy). From d79f2676d86e383945849d825d5da6e1437bd1c5 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 12:24:34 -0700 Subject: [PATCH 19/34] Adds valid values for `tier` and `data_location_constraint` to documentation --- website/docs/r/resiliencehub_resiliency_policy.html.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index 101514759eef..d990de97fde9 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -50,12 +50,14 @@ The following arguments are required: Must be between 2 and 60 characters long. Must start with an alphanumeric character and contain alphanumeric characters, underscores, or hyphens. * `tier` (String) Resiliency Policy Tier. + Valid values are `MissionCritical`, `Critical`, `Important`, `CoreServices`, `NonCritical`, and `NotApplicable`. * `policy` (Attributes) The type of resiliency policy to be created, including the recovery time objective (RTO) and recovery point objective (RPO) in seconds. See [`policy`](#policy). The following arguments are optional: * `description` (String) Description of Resiliency Policy. * `data_location_constraint` (String) Data Location Constraint of the Policy. + Valid values are `AnyLocation`, `SameContinent`, and `SameCountry`. * `tags` - (Map Of String) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### `policy` From 11a3949c0ec35cbd49e7d00a100a2a804f7f90f7 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 12:26:11 -0700 Subject: [PATCH 20/34] Adds documentation for `estimated_cost_tier` --- website/docs/r/resiliencehub_resiliency_policy.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index d990de97fde9..bfabdc0e9b23 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -105,6 +105,7 @@ The following arguments are required: This resource exports the following attributes in addition to the arguments above: * `arn` - ARN of the Resiliency Policy. +* `estimated_cost_tier` - Estimated Cost Tier of the Resiliency Policy. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Timeouts From 86e8867782b003958672e4f15f2c7418feb42db3 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 13:33:29 -0700 Subject: [PATCH 21/34] Model tweaks --- .../resiliencehub/resiliency_policy.go | 44 +++++++++---------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 0039da250860..06b6f656da38 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -243,26 +243,27 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea return } + // "Policy" cannot be handled by AutoFlex, since the parameter in the AWS API is a map planPolicyModel, diags := plan.Policy.ToPtr(ctx) resp.Diagnostics.Append(diags...) if diags.HasError() { return } - in := &resiliencehub.CreateResiliencyPolicyInput{} - resp.Diagnostics.Append(flex.Expand(ctx, &plan, in, flex.WithIgnoredFieldNamesAppend("Policy"))...) + var in resiliencehub.CreateResiliencyPolicyInput + resp.Diagnostics.Append(flex.Expand(ctx, plan, &in, flex.WithIgnoredFieldNamesAppend("Policy"))...) if resp.Diagnostics.HasError() { return } - resp.Diagnostics.Append(planPolicyModel.expandPolicy(ctx, in)...) + resp.Diagnostics.Append(planPolicyModel.expandPolicy(ctx, &in)...) if resp.Diagnostics.HasError() { return } in.Tags = getTagsIn(ctx) - out, err := conn.CreateResiliencyPolicy(ctx, in) + out, err := conn.CreateResiliencyPolicy(ctx, &in) if err != nil { resp.Diagnostics.AddError( create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionCreating, ResNameResiliencyPolicy, "", err), @@ -278,13 +279,14 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea return } - plan.PolicyArn = flex.StringToFramework(ctx, out.Policy.PolicyArn) + // plan.PolicyARN = flex.StringToFramework(ctx, out.Policy.PolicyArn) + arn := aws.ToString(out.Policy.PolicyArn) createTimeout := r.CreateTimeout(ctx, plan.Timeouts) - created, err := waitResiliencyPolicyCreated(ctx, conn, plan.PolicyArn.ValueString(), createTimeout) + created, err := waitResiliencyPolicyCreated(ctx, conn, arn, createTimeout) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForCreation, ResNameResiliencyPolicy, plan.PolicyArn.ValueString(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForCreation, ResNameResiliencyPolicy, plan.PolicyARN.ValueString(), err), err.Error(), ) return @@ -310,21 +312,19 @@ func (r *resourceResiliencyPolicy) Read(ctx context.Context, req resource.ReadRe return } - out, err := findResiliencyPolicyByARN(ctx, conn, state.PolicyArn.ValueString()) + out, err := findResiliencyPolicyByARN(ctx, conn, state.PolicyARN.ValueString()) if tfresource.NotFound(err) { resp.State.RemoveResource(ctx) return } if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionSetting, ResNameResiliencyPolicy, state.PolicyArn.ValueString(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionSetting, ResNameResiliencyPolicy, state.PolicyARN.ValueString(), err), err.Error(), ) return } - state.PolicyArn = flex.StringToFramework(ctx, out.PolicyArn) - resp.Diagnostics.Append(flex.Flatten(ctx, out, &state, flex.WithIgnoredFieldNamesAppend("Policy"))...) if resp.Diagnostics.HasError() { return @@ -354,8 +354,8 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda !plan.DataLocationConstraint.Equal(state.DataLocationConstraint) || !plan.Tier.Equal(state.Tier) || !plan.PolicyName.Equal(state.PolicyName) { - in := &resiliencehub.UpdateResiliencyPolicyInput{ - PolicyArn: flex.StringFromFramework(ctx, plan.PolicyArn), + in := resiliencehub.UpdateResiliencyPolicyInput{ + PolicyArn: flex.StringFromFramework(ctx, plan.PolicyARN), } if !plan.PolicyName.Equal(state.PolicyName) { @@ -374,19 +374,17 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda in.Tier = plan.Tier.ValueEnum() } - out, err := conn.UpdateResiliencyPolicy(ctx, in) + _, err := conn.UpdateResiliencyPolicy(ctx, &in) if err != nil { - resp.Diagnostics.AddError(fmt.Sprintf("reading Resilience Hub policy ID (%s)", plan.PolicyArn.String()), err.Error()) + resp.Diagnostics.AddError(fmt.Sprintf("reading Resilience Hub policy ID (%s)", plan.PolicyARN.String()), err.Error()) return } - plan.PolicyArn = flex.StringToFramework(ctx, out.Policy.PolicyArn) - updateTimeout := r.UpdateTimeout(ctx, plan.Timeouts) - updated, err := waitResiliencyPolicyUpdated(ctx, conn, plan.PolicyArn.ValueString(), updateTimeout) + updated, err := waitResiliencyPolicyUpdated(ctx, conn, plan.PolicyARN.ValueString(), updateTimeout) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForUpdate, ResNameResiliencyPolicy, plan.PolicyArn.String(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForUpdate, ResNameResiliencyPolicy, plan.PolicyARN.String(), err), err.Error(), ) return @@ -414,7 +412,7 @@ func (r *resourceResiliencyPolicy) Delete(ctx context.Context, req resource.Dele } _, err := conn.DeleteResiliencyPolicy(ctx, &resiliencehub.DeleteResiliencyPolicyInput{ - PolicyArn: flex.StringFromFramework(ctx, state.PolicyArn), + PolicyArn: flex.StringFromFramework(ctx, state.PolicyARN), }) if errs.IsA[*awstypes.ResourceNotFoundException](err) { @@ -427,10 +425,10 @@ func (r *resourceResiliencyPolicy) Delete(ctx context.Context, req resource.Dele } deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts) - _, err = waitResiliencyPolicyDeleted(ctx, conn, state.PolicyArn.ValueString(), deleteTimeout) + _, err = waitResiliencyPolicyDeleted(ctx, conn, state.PolicyARN.ValueString(), deleteTimeout) if err != nil { resp.Diagnostics.AddError( - create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForDeletion, ResNameResiliencyPolicy, state.PolicyArn.String(), err), + create.ProblemStandardMessage(names.ResilienceHub, create.ErrActionWaitingForDeletion, ResNameResiliencyPolicy, state.PolicyARN.String(), err), err.Error(), ) return @@ -609,7 +607,7 @@ type resourceResiliencyPolicyData struct { DataLocationConstraint fwtypes.StringEnum[awstypes.DataLocationConstraint] `tfsdk:"data_location_constraint"` EstimatedCostTier fwtypes.StringEnum[awstypes.EstimatedCostTier] `tfsdk:"estimated_cost_tier"` Policy fwtypes.ObjectValueOf[resourceResiliencyPolicyModel] `tfsdk:"policy"` - PolicyArn types.String `tfsdk:"arn"` + PolicyARN types.String `tfsdk:"arn"` PolicyDescription types.String `tfsdk:"description"` PolicyName types.String `tfsdk:"name"` Tier fwtypes.StringEnum[awstypes.ResiliencyPolicyTier] `tfsdk:"tier"` From 1dc8030d97cd4ac7e627371498a82a35257b9745 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 14:09:28 -0700 Subject: [PATCH 22/34] `policy.region` is optional --- .../resiliencehub/resiliency_policy_test.go | 28 +++---------------- 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 0faaaa346c05..2a285d7444b8 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -57,8 +57,8 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", "3600"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), ), @@ -112,8 +112,8 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", "3600"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0), @@ -356,10 +356,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tier = "NotApplicable" policy { - region { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } az { rpo_in_secs = 3600 rto_in_secs = 3600 @@ -389,10 +385,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { data_location_constraint = "AnyLocation" policy { - region { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } az { rpo_in_secs = 3600 rto_in_secs = 3600 @@ -426,10 +418,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { data_location_constraint = "AnyLocation" policy { - region { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } az { rpo_in_secs = 3600 rto_in_secs = 3600 @@ -464,10 +452,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { data_location_constraint = %[2]q policy { - region { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } az { rpo_in_secs = 3600 rto_in_secs = 3600 @@ -502,10 +486,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { data_location_constraint = "AnyLocation" policy { - region { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } az { rpo_in_secs = 3600 rto_in_secs = 3600 From 49ca804ec30b631b70cdb4c7321d521877e737d6 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Thu, 17 Oct 2024 14:13:37 -0700 Subject: [PATCH 23/34] Uses AWS SDK constants for policy type key --- .../resiliencehub/resiliency_policy.go | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 06b6f656da38..30da33d0f36c 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -444,15 +444,11 @@ func (r *resourceResiliencyPolicy) ModifyPlan(ctx context.Context, request resou } const ( - resiliencyPolicyTypeAZ = "AZ" - resiliencyPolicyTypeHardware = "Hardware" - resiliencyPolicyTypeSoftware = "Software" - resiliencyPolicyTypeRegion = "Region" - statusChangePending = "Pending" - statusDeleting = "Deleting" - statusNormal = "Normal" - statusUpdated = "Updated" - statusCompleted = "Completed" + statusChangePending = "Pending" + statusDeleting = "Deleting" + statusNormal = "Normal" + statusUpdated = "Updated" + statusCompleted = "Completed" ) func waitResiliencyPolicyCreated(ctx context.Context, conn *resiliencehub.Client, arn string, timeout time.Duration) (*awstypes.ResiliencyPolicy, error) { @@ -555,11 +551,11 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re // Policy key case must be modified to align with key case in CreateResiliencyPolicy API documentation. // See https://docs.aws.amazon.com/resilience-hub/latest/APIReference/API_CreateResiliencyPolicy.html - failurePolicyKeyMap := map[string]fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel]{ - resiliencyPolicyTypeAZ: m.AZ, - resiliencyPolicyTypeHardware: m.Hardware, - resiliencyPolicyTypeSoftware: m.Software, - resiliencyPolicyTypeRegion: m.Region} + failurePolicyKeyMap := map[awstypes.TestType]fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel]{ + awstypes.TestTypeAz: m.AZ, + awstypes.TestTypeHardware: m.Hardware, + awstypes.TestTypeSoftware: m.Software, + awstypes.TestTypeRegion: m.Region} for k, v := range failurePolicyKeyMap { if !v.IsNull() { @@ -568,7 +564,7 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re if diags.HasError() { return diags } - failurePolicy[k] = awstypes.FailurePolicy{ + failurePolicy[string(k)] = awstypes.FailurePolicy{ RpoInSecs: resObjModel.RpoInSecs.ValueInt32(), RtoInSecs: resObjModel.RtoInSecs.ValueInt32(), } @@ -585,8 +581,8 @@ func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failur m.Policy = fwtypes.NewObjectValueOfNull[resourceResiliencyPolicyModel](ctx) } - newResObjModel := func(policyType string, failurePolicy map[string]awstypes.FailurePolicy) fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] { - if pv, exists := failurePolicy[policyType]; exists { + newResObjModel := func(policyType awstypes.TestType, failurePolicy map[string]awstypes.FailurePolicy) fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] { + if pv, exists := failurePolicy[string(policyType)]; exists { return fwtypes.NewObjectValueOfMust(ctx, &resourceResiliencyObjectiveModel{ RpoInSecs: types.Int32Value(pv.RpoInSecs), RtoInSecs: types.Int32Value(pv.RtoInSecs)}) @@ -596,10 +592,10 @@ func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failur } m.Policy = fwtypes.NewObjectValueOfMust(ctx, &resourceResiliencyPolicyModel{ - newResObjModel(resiliencyPolicyTypeAZ, failurePolicy), - newResObjModel(resiliencyPolicyTypeHardware, failurePolicy), - newResObjModel(resiliencyPolicyTypeSoftware, failurePolicy), - newResObjModel(resiliencyPolicyTypeRegion, failurePolicy), + newResObjModel(awstypes.TestTypeAz, failurePolicy), + newResObjModel(awstypes.TestTypeHardware, failurePolicy), + newResObjModel(awstypes.TestTypeSoftware, failurePolicy), + newResObjModel(awstypes.TestTypeRegion, failurePolicy), }) } From 3dd0936478068b517558e96638a35f80ac82a03c Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 10:32:26 -0700 Subject: [PATCH 24/34] Separates `description` test --- .../resiliencehub/resiliency_policy_test.go | 91 ++++++++++++++++--- 1 file changed, 80 insertions(+), 11 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 2a285d7444b8..2f1e451c0ff8 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -13,9 +13,13 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/resiliencehub" "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" + "github.com/hashicorp/terraform-plugin-testing/compare" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/statecheck" "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/create" @@ -85,7 +89,6 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { resourceName := "aws_resiliencehub_resiliency_policy.test" updatedPolicyName := "updated-policy-name" - updatedPolicyDescription := "updated policy desecription" updatedDataLocationConstraint := "SameCountry" updatedTier := "MissionCritical" updatedPolicyObjValue := "86400" @@ -136,15 +139,6 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), }, - { - Config: testAccResiliencyPolicyConfig_updatePolicyDescription(rName, updatedPolicyDescription), - Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), - testAccCheckResiliencyPolicyNotRecreated(&policy2, &policy3), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updatedPolicyDescription), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), - ), - }, { Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), Check: resource.ComposeTestCheckFunc( @@ -182,6 +176,81 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { }) } +func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + const ( + initial = "initial" + updated = "updated" + ) + + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_description(rName, initial), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, initial), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_description(rName, updated), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updated), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -406,7 +475,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { `, rName) } -func testAccResiliencyPolicyConfig_updatePolicyDescription(rName, resPolicyDescValue string) string { +func testAccResiliencyPolicyConfig_description(rName, resPolicyDescValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q From c9086e2bffa50419233c4a4c574b0c46b3d5964e Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 10:54:25 -0700 Subject: [PATCH 25/34] Separates `name` test --- .../resiliencehub/resiliency_policy_test.go | 124 +++++++++++------- 1 file changed, 76 insertions(+), 48 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 2f1e451c0ff8..f76ddf10ff1f 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -84,11 +84,10 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var policy1, policy2, policy3, policy4, policy5, policy6 resiliencehub.DescribeResiliencyPolicyOutput + var policy1, policy2, policy3, policy4 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - updatedPolicyName := "updated-policy-name" updatedDataLocationConstraint := "SameCountry" updatedTier := "MissionCritical" updatedPolicyObjValue := "86400" @@ -131,19 +130,10 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_updatePolicyName(updatedPolicyName), + Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), - resource.TestCheckResourceAttr(resourceName, names.AttrName, updatedPolicyName), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), - ), - }, - { - Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), - Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy4), - testAccCheckResiliencyPolicyNotRecreated(&policy3, &policy4), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", updatedDataLocationConstraint), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), @@ -151,8 +141,8 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { { Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy5), - testAccCheckResiliencyPolicyNotRecreated(&policy4, &policy5), + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), + testAccCheckResiliencyPolicyNotRecreated(&policy2, &policy3), resource.TestCheckResourceAttr(resourceName, "tier", updatedTier), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), @@ -160,7 +150,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { { Config: testAccResiliencyPolicyConfig_updatePolicy(rName, updatedPolicyObjValue), Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy6), + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy4), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedPolicyObjValue), @@ -251,6 +241,77 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { }) } +func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_basic(rNameUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -442,39 +503,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { `, rName) } -func testAccResiliencyPolicyConfig_updatePolicyName(rName string) string { - return fmt.Sprintf(` -resource "aws_resiliencehub_resiliency_policy" "test" { - name = %[1]q - - description = "testAccResiliencyPolicyConfig_updatePolicyName" - - tier = "NotApplicable" - - data_location_constraint = "AnyLocation" - - policy { - az { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } - hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } - software { - rpo_in_secs = 3600 - rto_in_secs = 3600 - } - } - - tags = { - Value = "Other" - } -} -`, rName) -} - func testAccResiliencyPolicyConfig_description(rName, resPolicyDescValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { From 2425ad45738740629c8649ed2aae4767fb2a1672 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 10:59:19 -0700 Subject: [PATCH 26/34] Separates `data_location_constraint` test --- .../resiliencehub/resiliency_policy_test.go | 105 +++++++++++++----- 1 file changed, 76 insertions(+), 29 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index f76ddf10ff1f..3752a7d3aa10 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -13,6 +13,7 @@ import ( "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/resiliencehub" "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" + awstypes "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" "github.com/hashicorp/terraform-plugin-testing/compare" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" @@ -84,11 +85,10 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var policy1, policy2, policy3, policy4 resiliencehub.DescribeResiliencyPolicyOutput + var policy1, policy2, policy3 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - updatedDataLocationConstraint := "SameCountry" updatedTier := "MissionCritical" updatedPolicyObjValue := "86400" @@ -130,19 +130,10 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, updatedDataLocationConstraint), + Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", updatedDataLocationConstraint), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), - ), - }, - { - Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), - Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), - testAccCheckResiliencyPolicyNotRecreated(&policy2, &policy3), resource.TestCheckResourceAttr(resourceName, "tier", updatedTier), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), ), @@ -150,7 +141,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { { Config: testAccResiliencyPolicyConfig_updatePolicy(rName, updatedPolicyObjValue), Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy4), + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedPolicyObjValue), @@ -312,6 +303,76 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { }) } +func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameContinent), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameContinent)), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameCountry), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameCountry)), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -512,8 +573,6 @@ resource "aws_resiliencehub_resiliency_policy" "test" { tier = "NotApplicable" - data_location_constraint = "AnyLocation" - policy { az { rpo_in_secs = 3600 @@ -528,22 +587,15 @@ resource "aws_resiliencehub_resiliency_policy" "test" { rto_in_secs = 3600 } } - - tags = { - Name = %[1]q - Value = "Other" - } } `, rName, resPolicyDescValue) } -func testAccResiliencyPolicyConfig_updateDataLocationConstraint(rName, resDataLocConstValue string) string { +func testAccResiliencyPolicyConfig_dataLocationConstraint(rName string, dataLocationConstraint awstypes.DataLocationConstraint) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - description = %[1]q - tier = "NotApplicable" data_location_constraint = %[2]q @@ -562,13 +614,8 @@ resource "aws_resiliencehub_resiliency_policy" "test" { rto_in_secs = 3600 } } - - tags = { - Name = %[1]q - Value = "Other" - } } -`, rName, resDataLocConstValue) +`, rName, dataLocationConstraint) } func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string { From 55b6285b852f4098abe8fb71a934e53beb5b871a Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 11:01:23 -0700 Subject: [PATCH 27/34] Alphabetical order --- .../resiliencehub/resiliency_policy.go | 18 +++--- .../resiliencehub/resiliency_policy_test.go | 58 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 30da33d0f36c..00de489815d4 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -92,6 +92,15 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ names.AttrARN: framework.ARNAttributeComputedOnly(), + "data_location_constraint": schema.StringAttribute{ + Description: "Specifies a high-level geographical location constraint for where resilience policy data can be stored.", + CustomType: fwtypes.StringEnumType[awstypes.DataLocationConstraint](), + Computed: true, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, names.AttrDescription: schema.StringAttribute{ Description: "The description for the policy.", Optional: true, @@ -113,15 +122,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche stringvalidator.RegexMatches(regexache.MustCompile(`^[A-Za-z0-9][A-Za-z0-9_-]+$`), "Must start with an alphanumeric character and contain alphanumeric characters, underscores, or hyphens"), }, }, - "data_location_constraint": schema.StringAttribute{ - Description: "Specifies a high-level geographical location constraint for where resilience policy data can be stored.", - CustomType: fwtypes.StringEnumType[awstypes.DataLocationConstraint](), - Computed: true, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, "tier": schema.StringAttribute{ Description: "The tier for the resiliency policy, ranging from the highest severity (MissionCritical) to lowest (NonCritical).", CustomType: fwtypes.StringEnumType[awstypes.ResiliencyPolicyTier](), diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 3752a7d3aa10..d6747e1d41b2 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -157,7 +157,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { }) } -func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -167,11 +167,6 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - const ( - initial = "initial" - updated = "updated" - ) - expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ @@ -185,10 +180,10 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_description(rName, initial), + Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameContinent), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, initial), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameContinent)), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -207,10 +202,10 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_description(rName, updated), + Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameCountry), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updated), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameCountry)), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -232,7 +227,7 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { }) } -func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -240,9 +235,13 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" + const ( + initial = "initial" + updated = "updated" + ) + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ @@ -256,10 +255,10 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_basic(rName), + Config: testAccResiliencyPolicyConfig_description(rName, initial), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, initial), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -278,10 +277,10 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_basic(rNameUpdated), + Config: testAccResiliencyPolicyConfig_description(rName, updated), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updated), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -303,7 +302,7 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { }) } -func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -311,6 +310,7 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) @@ -326,10 +326,10 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameContinent), + Config: testAccResiliencyPolicyConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameContinent)), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -348,10 +348,10 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameCountry), + Config: testAccResiliencyPolicyConfig_basic(rNameUpdated), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameCountry)), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -564,15 +564,15 @@ resource "aws_resiliencehub_resiliency_policy" "test" { `, rName) } -func testAccResiliencyPolicyConfig_description(rName, resPolicyDescValue string) string { +func testAccResiliencyPolicyConfig_dataLocationConstraint(rName string, dataLocationConstraint awstypes.DataLocationConstraint) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - description = %[2]q - tier = "NotApplicable" + data_location_constraint = %[2]q + policy { az { rpo_in_secs = 3600 @@ -588,17 +588,17 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } } } -`, rName, resPolicyDescValue) +`, rName, dataLocationConstraint) } -func testAccResiliencyPolicyConfig_dataLocationConstraint(rName string, dataLocationConstraint awstypes.DataLocationConstraint) string { +func testAccResiliencyPolicyConfig_description(rName, resPolicyDescValue string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - tier = "NotApplicable" + description = %[2]q - data_location_constraint = %[2]q + tier = "NotApplicable" policy { az { @@ -615,7 +615,7 @@ resource "aws_resiliencehub_resiliency_policy" "test" { } } } -`, rName, dataLocationConstraint) +`, rName, resPolicyDescValue) } func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string { From 7965b05b5de5b7d169219f47f6967f3ee4abcc71 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 11:26:20 -0700 Subject: [PATCH 28/34] Separates `tier` test --- .../resiliencehub/resiliency_policy_test.go | 95 +++++++++++++++---- 1 file changed, 74 insertions(+), 21 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index d6747e1d41b2..79ea290c2a52 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -85,11 +85,10 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { t.Skip("skipping long-running test in short mode") } - var policy1, policy2, policy3 resiliencehub.DescribeResiliencyPolicyOutput + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - updatedTier := "MissionCritical" updatedPolicyObjValue := "86400" resource.ParallelTest(t, resource.TestCase{ @@ -129,19 +128,10 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIdentifierAttribute: names.AttrARN, }, - { - Config: testAccResiliencyPolicyConfig_updateTier(rName, updatedTier), - Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - testAccCheckResiliencyPolicyNotRecreated(&policy1, &policy2), - resource.TestCheckResourceAttr(resourceName, "tier", updatedTier), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), - ), - }, { Config: testAccResiliencyPolicyConfig_updatePolicy(rName, updatedPolicyObjValue), Check: resource.ComposeTestCheckFunc( - testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy3), + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedPolicyObjValue), resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedPolicyObjValue), @@ -373,6 +363,76 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { }) } +func TestAccResilienceHubResiliencyPolicy_tier(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_tier(rName, awstypes.ResiliencyPolicyTierMissionCritical), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, "tier", string(awstypes.ResiliencyPolicyTierMissionCritical)), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_tier(rName, awstypes.ResiliencyPolicyTierCoreServices), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, "tier", string(awstypes.ResiliencyPolicyTierCoreServices)), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + func TestAccResilienceHubResiliencyPolicy_tags(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { @@ -618,13 +678,11 @@ resource "aws_resiliencehub_resiliency_policy" "test" { `, rName, resPolicyDescValue) } -func testAccResiliencyPolicyConfig_updateTier(rName, resTierValue string) string { +func testAccResiliencyPolicyConfig_tier(rName string, tier awstypes.ResiliencyPolicyTier) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - description = %[1]q - tier = %[2]q data_location_constraint = "AnyLocation" @@ -643,13 +701,8 @@ resource "aws_resiliencehub_resiliency_policy" "test" { rto_in_secs = 3600 } } - - tags = { - Name = %[1]q - Value = "Other" - } } -`, rName, resTierValue) +`, rName, tier) } func testAccResiliencyPolicyConfig_updatePolicy(rName, resPolicyObjValue string) string { From 4bb73d772382fba8177f208d7fe2ecbccc74b59a Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 12:20:51 -0700 Subject: [PATCH 29/34] Separates `policy` tests --- .../resiliencehub/resiliency_policy_test.go | 326 ++++++++++++++---- 1 file changed, 255 insertions(+), 71 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 79ea290c2a52..c8bdd6221c8e 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -79,7 +79,7 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { }) } -func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -89,7 +89,7 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - updatedPolicyObjValue := "86400" + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -102,24 +102,19 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_basic(rName), + Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameContinent), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), - resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", "3600"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameContinent)), ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, }, { ResourceName: resourceName, @@ -129,25 +124,32 @@ func TestAccResilienceHubResiliencyPolicy_update(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_updatePolicy(rName, updatedPolicyObjValue), + Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameCountry), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedPolicyObjValue), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedPolicyObjValue), - acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, names.ResilienceHubServiceID, regexache.MustCompile(`resiliency-policy/.+`)), + resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameCountry)), ), + ConfigStateChecks: []statecheck.StateCheck{ + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, }, }, }) } -func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -157,6 +159,11 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" + const ( + initial = "initial" + updated = "updated" + ) + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ @@ -170,10 +177,10 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameContinent), + Config: testAccResiliencyPolicyConfig_description(rName, initial), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameContinent)), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, initial), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -192,10 +199,10 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_dataLocationConstraint(rName, awstypes.DataLocationConstraintSameCountry), + Config: testAccResiliencyPolicyConfig_description(rName, updated), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "data_location_constraint", string(awstypes.DataLocationConstraintSameCountry)), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updated), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -217,7 +224,7 @@ func TestAccResilienceHubResiliencyPolicy_dataLocationConstraint(t *testing.T) { }) } -func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -225,13 +232,9 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - const ( - initial = "initial" - updated = "updated" - ) - expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) resource.ParallelTest(t, resource.TestCase{ @@ -245,10 +248,10 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_description(rName, initial), + Config: testAccResiliencyPolicyConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, initial), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -267,10 +270,10 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_description(rName, updated), + Config: testAccResiliencyPolicyConfig_basic(rNameUpdated), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, updated), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -292,7 +295,7 @@ func TestAccResilienceHubResiliencyPolicy_description(t *testing.T) { }) } -func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { +func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { ctx := acctest.Context(t) if testing.Short() { t.Skip("skipping long-running test in short mode") @@ -300,10 +303,14 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - rNameUpdated := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) + expectARNChange := statecheck.CompareValue(compare.ValuesDiffer()) + + const ( + initialDuration = "3600" + updatedDuration = "86400" + ) resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { @@ -316,13 +323,20 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccResiliencyPolicyConfig_basic(rName), + Config: testAccResiliencyPolicyConfig_policy(rName, initialDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", initialDuration), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", initialDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ @@ -338,17 +352,171 @@ func TestAccResilienceHubResiliencyPolicy_name(t *testing.T) { ImportStateVerifyIdentifierAttribute: names.AttrARN, }, { - Config: testAccResiliencyPolicyConfig_basic(rNameUpdated), + Config: testAccResiliencyPolicyConfig_policy(rName, updatedDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rNameUpdated), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_policyWithRegion(rName, updatedDuration), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + }, + }) +} + +func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { + ctx := acctest.Context(t) + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + + var policy1, policy2 resiliencehub.DescribeResiliencyPolicyOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_resiliencehub_resiliency_policy.test" + + expectARNChange := statecheck.CompareValue(compare.ValuesDiffer()) + + const ( + initialDuration = "3600" + updatedDuration = "86400" + ) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionNot(t, names.USGovCloudPartitionID) + testAccPreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.ResilienceHubServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckResiliencyPolicyDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccResiliencyPolicyConfig_policyWithRegion(rName, initialDuration), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", initialDuration), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_policyWithRegion(rName, updatedDuration), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + }, + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAttrImportStateIdFunc(resourceName, names.AttrARN), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: names.AttrARN, + }, + { + Config: testAccResiliencyPolicyConfig_policy(rName, updatedDuration), + Check: resource.ComposeTestCheckFunc( + testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + ), + ConfigStateChecks: []statecheck.StateCheck{ + expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + }, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), }, }, }, @@ -705,42 +873,58 @@ resource "aws_resiliencehub_resiliency_policy" "test" { `, rName, tier) } -func testAccResiliencyPolicyConfig_updatePolicy(rName, resPolicyObjValue string) string { +func testAccResiliencyPolicyConfig_policy(rName, duration string) string { return fmt.Sprintf(` resource "aws_resiliencehub_resiliency_policy" "test" { name = %[1]q - description = %[1]q - tier = "NotApplicable" - data_location_constraint = "AnyLocation" - policy { - region { - rpo_in_secs = %[2]q - rto_in_secs = %[2]q - } az { - rpo_in_secs = %[2]q - rto_in_secs = %[2]q + rpo_in_secs = %[2]s + rto_in_secs = %[2]s } hardware { - rpo_in_secs = %[2]q - rto_in_secs = %[2]q + rpo_in_secs = %[2]s + rto_in_secs = %[2]s } software { - rpo_in_secs = %[2]q - rto_in_secs = %[2]q + rpo_in_secs = %[2]s + rto_in_secs = %[2]s } } +} +`, rName, duration) +} - tags = { - Name = %[1]q - Value = "Other" +func testAccResiliencyPolicyConfig_policyWithRegion(rName, duration string) string { + return fmt.Sprintf(` +resource "aws_resiliencehub_resiliency_policy" "test" { + name = %[1]q + + tier = "NotApplicable" + + policy { + az { + rpo_in_secs = %[2]s + rto_in_secs = %[2]s + } + hardware { + rpo_in_secs = %[2]s + rto_in_secs = %[2]s + } + region { + rpo_in_secs = %[2]s + rto_in_secs = %[2]s + } + software { + rpo_in_secs = %[2]s + rto_in_secs = %[2]s + } } } -`, rName, resPolicyObjValue) +`, rName, duration) } func testAccResiliencyPolicyConfig_tags1(rName, tagKey1, tagValue1 string) string { From 921bb61cf95aa4eefd971a4e203d0cf5bec946b0 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 12:21:40 -0700 Subject: [PATCH 30/34] No longer recreates resource when `policy` changes --- .../resiliencehub/resiliency_policy.go | 73 ++++++++----------- .../resiliencehub/resiliency_policy_test.go | 24 +++--- 2 files changed, 44 insertions(+), 53 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 00de489815d4..520ae6825e8e 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -22,7 +22,6 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" @@ -70,7 +69,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Required: true, PlanModifiers: []planmodifier.Int32{ int32planmodifier.UseStateForUnknown(), - int32planmodifier.RequiresReplace(), }, Validators: []validator.Int32{ int32validator.AtLeast(0), @@ -81,7 +79,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Required: true, PlanModifiers: []planmodifier.Int32{ int32planmodifier.UseStateForUnknown(), - int32planmodifier.RequiresReplace(), }, Validators: []validator.Int32{ int32validator.AtLeast(0), @@ -134,9 +131,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Description: "Specifies the estimated cost tier of the resiliency policy.", CustomType: fwtypes.StringEnumType[awstypes.EstimatedCostTier](), Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, }, names.AttrTags: tftags.TagsAttribute(), names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), @@ -145,9 +139,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche names.AttrPolicy: schema.SingleNestedBlock{ Description: "The resiliency failure policy.", CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyPolicyModel](ctx), - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.RequiresReplace(), - }, Validators: []validator.Object{ objectvalidator.IsRequired(), }, @@ -155,9 +146,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche "az": schema.SingleNestedBlock{ CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), Description: "The RTO and RPO target to measure resiliency for potential availability zone disruptions.", - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.RequiresReplace(), - }, Validators: []validator.Object{ objectvalidator.IsRequired(), }, @@ -166,9 +154,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche "hardware": schema.SingleNestedBlock{ CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), Description: "The RTO and RPO target to measure resiliency for potential infrastructure disruptions.", - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.RequiresReplace(), - }, Validators: []validator.Object{ objectvalidator.IsRequired(), }, @@ -177,9 +162,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche "software": schema.SingleNestedBlock{ CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), Description: "The RTO and RPO target to measure resiliency for potential application disruptions.", - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.RequiresReplace(), - }, Validators: []validator.Object{ objectvalidator.IsRequired(), }, @@ -188,9 +170,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche names.AttrRegion: schema.SingleNestedBlock{ CustomType: fwtypes.NewObjectTypeOf[resourceResiliencyObjectiveModel](ctx), Description: "The RTO and RPO target to measure resiliency for potential region disruptions.", - PlanModifiers: []planmodifier.Object{ - objectplanmodifier.RequiresReplace(), - }, Validators: []validator.Object{ objectvalidator.AlsoRequires( path.MatchRelative().AtName("rto_in_secs"), @@ -203,7 +182,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Optional: true, PlanModifiers: []planmodifier.Int32{ int32planmodifier.UseStateForUnknown(), - int32planmodifier.RequiresReplace(), }, Validators: []validator.Int32{ int32validator.AtLeast(0), @@ -214,7 +192,6 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Optional: true, PlanModifiers: []planmodifier.Int32{ int32planmodifier.UseStateForUnknown(), - int32planmodifier.RequiresReplace(), }, Validators: []validator.Int32{ int32validator.AtLeast(0), @@ -256,10 +233,12 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea return } - resp.Diagnostics.Append(planPolicyModel.expandPolicy(ctx, &in)...) + p, d := planPolicyModel.expandPolicy(ctx) + resp.Diagnostics.Append(d...) if resp.Diagnostics.HasError() { return } + in.Policy = p in.Tags = getTagsIn(ctx) @@ -279,7 +258,6 @@ func (r *resourceResiliencyPolicy) Create(ctx context.Context, req resource.Crea return } - // plan.PolicyARN = flex.StringToFramework(ctx, out.Policy.PolicyArn) arn := aws.ToString(out.Policy.PolicyArn) createTimeout := r.CreateTimeout(ctx, plan.Timeouts) @@ -350,18 +328,17 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda return } - if !plan.PolicyDescription.Equal(state.PolicyDescription) || - !plan.DataLocationConstraint.Equal(state.DataLocationConstraint) || - !plan.Tier.Equal(state.Tier) || - !plan.PolicyName.Equal(state.PolicyName) { + diff, d := flex.Calculate(ctx, plan, state) + resp.Diagnostics.Append(d...) + if resp.Diagnostics.HasError() { + return + } + + if diff.HasChanges() { in := resiliencehub.UpdateResiliencyPolicyInput{ PolicyArn: flex.StringFromFramework(ctx, plan.PolicyARN), } - if !plan.PolicyName.Equal(state.PolicyName) { - in.PolicyName = flex.StringFromFramework(ctx, plan.PolicyName) - } - if !plan.PolicyDescription.Equal(state.PolicyDescription) { in.PolicyDescription = flex.StringFromFramework(ctx, plan.PolicyDescription) } @@ -370,6 +347,24 @@ func (r *resourceResiliencyPolicy) Update(ctx context.Context, req resource.Upda in.DataLocationConstraint = plan.DataLocationConstraint.ValueEnum() } + if !plan.Policy.Equal(state.Policy) { + planPolicyModel, d := plan.Policy.ToPtr(ctx) + resp.Diagnostics.Append(d...) + if d.HasError() { + return + } + p, d := planPolicyModel.expandPolicy(ctx) + resp.Diagnostics.Append(d...) + if d.HasError() { + return + } + in.Policy = p + } + + if !plan.PolicyName.Equal(state.PolicyName) { + in.PolicyName = flex.StringFromFramework(ctx, plan.PolicyName) + } + if !plan.Tier.Equal(state.Tier) { in.Tier = plan.Tier.ValueEnum() } @@ -542,11 +537,7 @@ func findResiliencyPolicyByARN(ctx context.Context, conn *resiliencehub.Client, return out.Policy, nil } -func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *resiliencehub.CreateResiliencyPolicyInput) (diags diag.Diagnostics) { - if in == nil { - return diags - } - +func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context) (result map[string]awstypes.FailurePolicy, diags diag.Diagnostics) { failurePolicy := make(map[string]awstypes.FailurePolicy) // Policy key case must be modified to align with key case in CreateResiliencyPolicy API documentation. @@ -562,7 +553,7 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re resObjModel, d := v.ToPtr(ctx) diags.Append(d...) if diags.HasError() { - return diags + return result, diags } failurePolicy[string(k)] = awstypes.FailurePolicy{ RpoInSecs: resObjModel.RpoInSecs.ValueInt32(), @@ -571,9 +562,9 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context, in *re } } - in.Policy = failurePolicy + result = failurePolicy - return diags + return result, diags } func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failurePolicy map[string]awstypes.FailurePolicy) { diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index c8bdd6221c8e..36a0da2196b5 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -305,7 +305,7 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - expectARNChange := statecheck.CompareValue(compare.ValuesDiffer()) + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) const ( initialDuration = "3600" @@ -336,7 +336,7 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", initialDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ @@ -365,11 +365,11 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), }, }, }, @@ -394,11 +394,11 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), }, }, }, @@ -423,7 +423,7 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_resiliencehub_resiliency_policy.test" - expectARNChange := statecheck.CompareValue(compare.ValuesDiffer()) + expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) const ( initialDuration = "3600" @@ -454,7 +454,7 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", initialDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ @@ -483,11 +483,11 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), }, }, }, @@ -512,11 +512,11 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ - expectARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), + expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), }, ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionReplace), + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), }, }, }, From 3b16d83727db8908c0956af9a58ebdaf22fde380 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 12:43:28 -0700 Subject: [PATCH 31/34] Adds sweeper --- internal/service/resiliencehub/sweep.go | 42 +++++++++++++++++++++++++ internal/sweep/register_gen_test.go | 2 ++ 2 files changed, 44 insertions(+) create mode 100644 internal/service/resiliencehub/sweep.go diff --git a/internal/service/resiliencehub/sweep.go b/internal/service/resiliencehub/sweep.go new file mode 100644 index 000000000000..bebcc58f761b --- /dev/null +++ b/internal/service/resiliencehub/sweep.go @@ -0,0 +1,42 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package resiliencehub + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/resiliencehub" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/sweep" + "github.com/hashicorp/terraform-provider-aws/internal/sweep/awsv2" + "github.com/hashicorp/terraform-provider-aws/internal/sweep/framework" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func RegisterSweepers() { + awsv2.Register("aws_resiliencehub_resiliency_policy", sweepResiliencyPolicy) +} + +func sweepResiliencyPolicy(ctx context.Context, client *conns.AWSClient) ([]sweep.Sweepable, error) { + conn := client.ResilienceHubClient(ctx) + + var sweepResources []sweep.Sweepable + + pages := resiliencehub.NewListResiliencyPoliciesPaginator(conn, &resiliencehub.ListResiliencyPoliciesInput{}) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + if err != nil { + return nil, err + } + + for _, policies := range page.ResiliencyPolicies { + sweepResources = append(sweepResources, framework.NewSweepResource(newResourceResiliencyPolicy, client, + framework.NewAttribute(names.AttrARN, aws.ToString(policies.PolicyArn)), + )) + } + } + + return sweepResources, nil +} diff --git a/internal/sweep/register_gen_test.go b/internal/sweep/register_gen_test.go index 918c6ebcd8ac..f0a66ba8bd73 100644 --- a/internal/sweep/register_gen_test.go +++ b/internal/sweep/register_gen_test.go @@ -124,6 +124,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/internal/service/rds" "github.com/hashicorp/terraform-provider-aws/internal/service/redshift" "github.com/hashicorp/terraform-provider-aws/internal/service/redshiftserverless" + "github.com/hashicorp/terraform-provider-aws/internal/service/resiliencehub" "github.com/hashicorp/terraform-provider-aws/internal/service/resourceexplorer2" "github.com/hashicorp/terraform-provider-aws/internal/service/resourcegroups" "github.com/hashicorp/terraform-provider-aws/internal/service/route53" @@ -289,6 +290,7 @@ func registerSweepers() { rds.RegisterSweepers() redshift.RegisterSweepers() redshiftserverless.RegisterSweepers() + resiliencehub.RegisterSweepers() resourceexplorer2.RegisterSweepers() resourcegroups.RegisterSweepers() route53.RegisterSweepers() From bd18b5788e381a38f69b4071310446a2129018be Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 12:43:45 -0700 Subject: [PATCH 32/34] Restricts parallelism to 10 --- .teamcity/components/generated/services_all.kt | 2 +- internal/generate/teamcity/acctest_services.hcl | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.teamcity/components/generated/services_all.kt b/.teamcity/components/generated/services_all.kt index c1b84d0d0433..90ac07084298 100644 --- a/.teamcity/components/generated/services_all.kt +++ b/.teamcity/components/generated/services_all.kt @@ -186,7 +186,7 @@ val services = mapOf( "redshiftdata" to ServiceSpec("Redshift Data"), "redshiftserverless" to ServiceSpec("Redshift Serverless"), "rekognition" to ServiceSpec("Rekognition"), - "resiliencehub" to ServiceSpec("Resilience Hub"), + "resiliencehub" to ServiceSpec("Resilience Hub", parallelismOverride = 10), "resourceexplorer2" to ServiceSpec("Resource Explorer"), "resourcegroups" to ServiceSpec("Resource Groups"), "resourcegroupstaggingapi" to ServiceSpec("Resource Groups Tagging"), diff --git a/internal/generate/teamcity/acctest_services.hcl b/internal/generate/teamcity/acctest_services.hcl index 93d0712638d9..02371378470f 100644 --- a/internal/generate/teamcity/acctest_services.hcl +++ b/internal/generate/teamcity/acctest_services.hcl @@ -219,6 +219,10 @@ service "redshift" { vpc_lock = true } +service "resiliencehub" { + parallelism = 10 +} + service "route53" { vpc_lock = true } From 36748a8e30ab72573c9f213ce914b3189909b9cb Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 12:46:48 -0700 Subject: [PATCH 33/34] Cleanup --- internal/service/resiliencehub/resiliency_policy_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 36a0da2196b5..478d5190d253 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -12,7 +12,6 @@ import ( "github.com/YakDriver/regexache" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/service/resiliencehub" - "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" awstypes "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" "github.com/hashicorp/terraform-plugin-testing/compare" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" @@ -692,7 +691,7 @@ func testAccCheckResiliencyPolicyDestroy(ctx context.Context) resource.TestCheck PolicyArn: aws.String(rs.Primary.Attributes[names.AttrARN]), } _, err := conn.DescribeResiliencyPolicy(ctx, input) - if errs.IsA[*types.ResourceNotFoundException](err) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil } if err != nil { From 03aacc4f88e33f9c431235a4c5573066306ba2a9 Mon Sep 17 00:00:00 2001 From: Graham Davison Date: Fri, 18 Oct 2024 14:21:52 -0700 Subject: [PATCH 34/34] Converts durations from seconds to Go duration --- .../resiliencehub/resiliency_policy.go | 82 +++---- .../resiliencehub/resiliency_policy_test.go | 228 +++++++++--------- ...iliencehub_resiliency_policy.html.markdown | 42 ++-- 3 files changed, 180 insertions(+), 172 deletions(-) diff --git a/internal/service/resiliencehub/resiliency_policy.go b/internal/service/resiliencehub/resiliency_policy.go index 520ae6825e8e..5c7571d5019f 100644 --- a/internal/service/resiliencehub/resiliency_policy.go +++ b/internal/service/resiliencehub/resiliency_policy.go @@ -14,14 +14,13 @@ import ( "github.com/aws/aws-sdk-go-v2/service/resiliencehub" awstypes "github.com/aws/aws-sdk-go-v2/service/resiliencehub/types" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" - "github.com/hashicorp/terraform-plugin-framework-validators/int32validator" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/int32planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" @@ -64,24 +63,20 @@ func (r *resourceResiliencyPolicy) Metadata(_ context.Context, req resource.Meta func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { requiredObjAttrs := map[string]schema.Attribute{ - "rto_in_secs": schema.Int32Attribute{ - Description: "Recovery Time Objective (RTO) in seconds.", + "rto": schema.StringAttribute{ + Description: "Recovery Time Objective (RTO) as a Go duration.", + CustomType: timetypes.GoDurationType{}, Required: true, - PlanModifiers: []planmodifier.Int32{ - int32planmodifier.UseStateForUnknown(), - }, - Validators: []validator.Int32{ - int32validator.AtLeast(0), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - "rpo_in_secs": schema.Int32Attribute{ - Description: "Recovery Point Objective (RPO) in seconds.", + "rpo": schema.StringAttribute{ + Description: "Recovery Point Objective (RPO) as a Go duration.", + CustomType: timetypes.GoDurationType{}, Required: true, - PlanModifiers: []planmodifier.Int32{ - int32planmodifier.UseStateForUnknown(), - }, - Validators: []validator.Int32{ - int32validator.AtLeast(0), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, } @@ -172,29 +167,25 @@ func (r *resourceResiliencyPolicy) Schema(ctx context.Context, req resource.Sche Description: "The RTO and RPO target to measure resiliency for potential region disruptions.", Validators: []validator.Object{ objectvalidator.AlsoRequires( - path.MatchRelative().AtName("rto_in_secs"), - path.MatchRelative().AtName("rpo_in_secs"), + path.MatchRelative().AtName("rto"), + path.MatchRelative().AtName("rpo"), ), }, Attributes: map[string]schema.Attribute{ - "rto_in_secs": schema.Int32Attribute{ - Description: "Recovery Time Objective (RTO) in seconds.", + "rto": schema.StringAttribute{ + Description: "Recovery Time Objective (RTO) as a Go duration.", + CustomType: timetypes.GoDurationType{}, Optional: true, - PlanModifiers: []planmodifier.Int32{ - int32planmodifier.UseStateForUnknown(), - }, - Validators: []validator.Int32{ - int32validator.AtLeast(0), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, - "rpo_in_secs": schema.Int32Attribute{ - Description: "Recovery Point Objective (RPO) in seconds.", + "rpo": schema.StringAttribute{ + Description: "Recovery Point Objective (RPO) as a Go duration.", + CustomType: timetypes.GoDurationType{}, Optional: true, - PlanModifiers: []planmodifier.Int32{ - int32planmodifier.UseStateForUnknown(), - }, - Validators: []validator.Int32{ - int32validator.AtLeast(0), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), }, }, }, @@ -546,18 +537,26 @@ func (m *resourceResiliencyPolicyModel) expandPolicy(ctx context.Context) (resul awstypes.TestTypeAz: m.AZ, awstypes.TestTypeHardware: m.Hardware, awstypes.TestTypeSoftware: m.Software, - awstypes.TestTypeRegion: m.Region} - + awstypes.TestTypeRegion: m.Region, + } for k, v := range failurePolicyKeyMap { if !v.IsNull() { resObjModel, d := v.ToPtr(ctx) diags.Append(d...) - if diags.HasError() { + if d.HasError() { + return result, diags + } + rpo, d := resObjModel.Rpo.ValueGoDuration() + if d.HasError() { + return result, diags + } + rto, d := resObjModel.Rto.ValueGoDuration() + if d.HasError() { return result, diags } failurePolicy[string(k)] = awstypes.FailurePolicy{ - RpoInSecs: resObjModel.RpoInSecs.ValueInt32(), - RtoInSecs: resObjModel.RtoInSecs.ValueInt32(), + RpoInSecs: int32(rpo.Seconds()), + RtoInSecs: int32(rto.Seconds()), } } } @@ -575,8 +574,9 @@ func (m *resourceResiliencyPolicyData) flattenPolicy(ctx context.Context, failur newResObjModel := func(policyType awstypes.TestType, failurePolicy map[string]awstypes.FailurePolicy) fwtypes.ObjectValueOf[resourceResiliencyObjectiveModel] { if pv, exists := failurePolicy[string(policyType)]; exists { return fwtypes.NewObjectValueOfMust(ctx, &resourceResiliencyObjectiveModel{ - RpoInSecs: types.Int32Value(pv.RpoInSecs), - RtoInSecs: types.Int32Value(pv.RtoInSecs)}) + Rpo: timetypes.NewGoDurationValue(time.Duration(pv.RpoInSecs) * time.Second), + Rto: timetypes.NewGoDurationValue(time.Duration(pv.RtoInSecs) * time.Second), + }) } else { return fwtypes.NewObjectValueOfNull[resourceResiliencyObjectiveModel](ctx) } @@ -611,6 +611,6 @@ type resourceResiliencyPolicyModel struct { } type resourceResiliencyObjectiveModel struct { - RpoInSecs types.Int32 `tfsdk:"rpo_in_secs"` - RtoInSecs types.Int32 `tfsdk:"rto_in_secs"` + Rpo timetypes.GoDuration `tfsdk:"rpo"` + Rto timetypes.GoDuration `tfsdk:"rto"` } diff --git a/internal/service/resiliencehub/resiliency_policy_test.go b/internal/service/resiliencehub/resiliency_policy_test.go index 478d5190d253..b0bc5fb6a617 100644 --- a/internal/service/resiliencehub/resiliency_policy_test.go +++ b/internal/service/resiliencehub/resiliency_policy_test.go @@ -57,14 +57,14 @@ func TestAccResilienceHubResiliencyPolicy_basic(t *testing.T) { resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), resource.TestCheckResourceAttr(resourceName, "tier", "NotApplicable"), resource.TestCheckResourceAttr(resourceName, "data_location_constraint", "AnyLocation"), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", "3600"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", "3600"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", "3600"), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", "1h0m0s"), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", "1h0m0s"), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", "1h0m0s"), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", "1h0m0s"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", "1h0m0s"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", "1h0m0s"), ), }, { @@ -307,8 +307,8 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) const ( - initialDuration = "3600" - updatedDuration = "86400" + initialDuration = "1h0m0s" + updatedDuration = "24h0m0s" ) resource.ParallelTest(t, resource.TestCase{ @@ -325,14 +325,14 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { Config: testAccResiliencyPolicyConfig_policy(rName, initialDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", initialDuration), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", initialDuration), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", initialDuration), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -354,14 +354,14 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { Config: testAccResiliencyPolicyConfig_policy(rName, updatedDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", updatedDuration), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -383,14 +383,14 @@ func TestAccResilienceHubResiliencyPolicy_policy(t *testing.T) { Config: testAccResiliencyPolicyConfig_policyWithRegion(rName, updatedDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -425,8 +425,8 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { expectNoARNChange := statecheck.CompareValue(compare.ValuesSame()) const ( - initialDuration = "3600" - updatedDuration = "86400" + initialDuration = "1h0m0s" + updatedDuration = "24h0m0s" ) resource.ParallelTest(t, resource.TestCase{ @@ -443,14 +443,14 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { Config: testAccResiliencyPolicyConfig_policyWithRegion(rName, initialDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy1), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", initialDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", initialDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", initialDuration), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -472,14 +472,14 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { Config: testAccResiliencyPolicyConfig_policyWithRegion(rName, updatedDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.region.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.region.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.region.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -501,14 +501,14 @@ func TestAccResilienceHubResiliencyPolicy_policyWithRegion(t *testing.T) { Config: testAccResiliencyPolicyConfig_policy(rName, updatedDuration), Check: resource.ComposeTestCheckFunc( testAccCheckResiliencyPolicyExists(ctx, resourceName, &policy2), - resource.TestCheckResourceAttr(resourceName, "policy.az.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.az.rto_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto_in_secs", updatedDuration), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo_in_secs"), - resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto_in_secs"), - resource.TestCheckResourceAttr(resourceName, "policy.software.rpo_in_secs", updatedDuration), - resource.TestCheckResourceAttr(resourceName, "policy.software.rto_in_secs", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.az.rto", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.hardware.rto", updatedDuration), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rpo"), + resource.TestCheckNoResourceAttr(resourceName, "policy.region.rto"), + resource.TestCheckResourceAttr(resourceName, "policy.software.rpo", updatedDuration), + resource.TestCheckResourceAttr(resourceName, "policy.software.rto", updatedDuration), ), ConfigStateChecks: []statecheck.StateCheck{ expectNoARNChange.AddStateValue(resourceName, tfjsonpath.New(names.AttrARN)), @@ -775,16 +775,16 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { az { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } software { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } } } @@ -802,16 +802,16 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { az { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } software { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } } } @@ -829,16 +829,16 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { az { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } software { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } } } @@ -856,16 +856,16 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { az { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } software { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } } } @@ -881,16 +881,16 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { az { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } hardware { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } software { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } } } @@ -906,20 +906,20 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { az { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } hardware { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } region { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } software { - rpo_in_secs = %[2]s - rto_in_secs = %[2]s + rpo = %[2]q + rto = %[2]q } } } @@ -939,20 +939,20 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { region { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } az { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } software { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } } @@ -976,20 +976,20 @@ resource "aws_resiliencehub_resiliency_policy" "test" { policy { region { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } az { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } hardware { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } software { - rpo_in_secs = 3600 - rto_in_secs = 3600 + rpo = "1h0m0s" + rto = "1h0m0s" } } diff --git a/website/docs/r/resiliencehub_resiliency_policy.html.markdown b/website/docs/r/resiliencehub_resiliency_policy.html.markdown index bfabdc0e9b23..3ddee6e8db0c 100644 --- a/website/docs/r/resiliencehub_resiliency_policy.html.markdown +++ b/website/docs/r/resiliencehub_resiliency_policy.html.markdown @@ -23,20 +23,20 @@ resource "aws_resiliencehub_resiliency_policy" "example" { policy { region { - rpo_in_secs = 86400 - rto_in_secs = 86400 + rpo = "24h" + rto = "24h" } az { - rpo_in_secs = 86400 - rto_in_secs = 86400 + rpo = "24h" + rto = "24h" } hardware { - rpo_in_secs = 86400 - rto_in_secs = 86400 + rpo = "24h" + rto = "24h" } software { - rpo_in_secs = 86400 - rto_in_secs = 86400 + rpo = "24h" + rto = "24h" } } } @@ -76,30 +76,38 @@ The following arguments are optional: The following arguments are required: -* `rpo_in_secs` - (Number) RPO in seconds. -* `rto_in_secs` - (Number) RTO in seconds. +* `rpo` - (Number) Recovery Point Objective (RPO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. +* `rto` - (Number) Recovery Time Objective (RTO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. ### `policy.hardware` The following arguments are required: -* `rpo_in_secs` - (Number) RPO in seconds. -* `rto_in_secs` - (Number) RTO in seconds. +* `rpo` - (Number) Recovery Point Objective (RPO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. +* `rto` - (Number) Recovery Time Objective (RTO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. ### `policy.software` The following arguments are required: -* `rpo_in_secs` - (Number) RPO in seconds. -* `rto_in_secs` - (Number) RTO in seconds. +* `rpo` - (Number) Recovery Point Objective (RPO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. +* `rto` - (Number) Recovery Time Objective (RTO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. ### `policy.region` The following arguments are required: -* `rpo_in_secs` - (Number) RPO in seconds. -* `rto_in_secs` - (Number) RTO in seconds. - +* `rpo` - (Number) Recovery Point Objective (RPO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. +* `rto` - (Number) Recovery Time Objective (RTO) as a Go duration. + Represented by a string such as `1h`, `2h45m`, or `30m15s`. + ## Attribute Reference This resource exports the following attributes in addition to the arguments above: