Skip to content

Commit df6e49f

Browse files
committed
refactor: Use new create-only plan modifier in all resources
1 parent cb6ddf1 commit df6e49f

File tree

5 files changed

+20
-49
lines changed

5 files changed

+20
-49
lines changed

internal/common/customplanmodifier/create_only.go

Lines changed: 10 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,36 +22,6 @@ func CreateOnlyBoolPlanModifier() planmodifier.Bool {
2222
return &createOnlyAttributePlanModifier{}
2323
}
2424

25-
// Plan modifier that implements create-only behavior for multiple attribute types
26-
type createOnlyAttributePlanModifier struct{}
27-
28-
func (d *createOnlyAttributePlanModifier) Description(ctx context.Context) string {
29-
return d.MarkdownDescription(ctx)
30-
}
31-
32-
func (d *createOnlyAttributePlanModifier) MarkdownDescription(ctx context.Context) string {
33-
return "Ensures that update operations fail when attempting to modify a create-only attribute."
34-
}
35-
36-
func (d *createOnlyAttributePlanModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) {
37-
validateCreateOnly(req.PlanValue, req.StateValue, req.Path, &resp.Diagnostics)
38-
}
39-
40-
func (d *createOnlyAttributePlanModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
41-
validateCreateOnly(req.PlanValue, req.StateValue, req.Path, &resp.Diagnostics)
42-
}
43-
44-
// validateCreateOnly checks if an attribute value has changed and adds an error if it has
45-
func validateCreateOnly(planValue, stateValue attr.Value, attrPath path.Path, diagnostics *diag.Diagnostics,
46-
) {
47-
if !stateValue.IsNull() && !stateValue.Equal(planValue) {
48-
diagnostics.AddError(
49-
fmt.Sprintf("%s cannot be updated", attrPath),
50-
fmt.Sprintf("%s cannot be updated", attrPath),
51-
)
52-
}
53-
}
54-
5525
type CreateOnlyModifier interface {
5626
planmodifier.String
5727
planmodifier.Bool
@@ -66,35 +36,35 @@ func CreateOnlyAttributePlanModifier() CreateOnlyModifier {
6636
return &createOnlyAttributePlanModifier{}
6737
}
6838

69-
// CreateOnlyAttributePlanModifierWithBoolDefault sets a default value on create operation that will show in the plan.
39+
// CreateOnlyBoolWithDefaultPlanModifier sets a default value on create operation that will show in the plan.
7040
// This avoids any custom logic in the resource "Create" handler.
7141
// On update the default has no impact and the UseStateForUnknown behavior is observed instead.
7242
// Always use Optional+Computed when using a default value.
73-
func CreateOnlyAttributePlanModifierWithBoolDefault(b bool) CreateOnlyModifier {
74-
return &createOnlyAttributePlanModifierWithBoolDefault{defaultBool: &b}
43+
func CreateOnlyBoolWithDefaultPlanModifier(b bool) CreateOnlyModifier {
44+
return &createOnlyAttributePlanModifier{defaultBool: &b}
7545
}
7646

77-
type createOnlyAttributePlanModifierWithBoolDefault struct {
47+
type createOnlyAttributePlanModifier struct {
7848
defaultBool *bool
7949
}
8050

81-
func (d *createOnlyAttributePlanModifierWithBoolDefault) Description(ctx context.Context) string {
51+
func (d *createOnlyAttributePlanModifier) Description(ctx context.Context) string {
8252
return d.MarkdownDescription(ctx)
8353
}
8454

85-
func (d *createOnlyAttributePlanModifierWithBoolDefault) MarkdownDescription(ctx context.Context) string {
55+
func (d *createOnlyAttributePlanModifier) MarkdownDescription(ctx context.Context) string {
8656
return "Ensures the update operation fails when updating an attribute. If the read after import don't equal the configuration value it will also raise an error."
8757
}
8858

8959
func isCreate(t *tfsdk.State) bool {
9060
return t.Raw.IsNull()
9161
}
9262

93-
func (d *createOnlyAttributePlanModifierWithBoolDefault) UseDefault() bool {
63+
func (d *createOnlyAttributePlanModifier) UseDefault() bool {
9464
return d.defaultBool != nil
9565
}
9666

97-
func (d *createOnlyAttributePlanModifierWithBoolDefault) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
67+
func (d *createOnlyAttributePlanModifier) PlanModifyBool(ctx context.Context, req planmodifier.BoolRequest, resp *planmodifier.BoolResponse) {
9868
if isCreate(&req.State) {
9969
if !IsKnown(req.PlanValue) && d.UseDefault() {
10070
resp.PlanValue = types.BoolPointerValue(d.defaultBool)
@@ -109,7 +79,7 @@ func (d *createOnlyAttributePlanModifierWithBoolDefault) PlanModifyBool(ctx cont
10979
}
11080
}
11181

112-
func (d *createOnlyAttributePlanModifierWithBoolDefault) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) {
82+
func (d *createOnlyAttributePlanModifier) PlanModifyString(ctx context.Context, req planmodifier.StringRequest, resp *planmodifier.StringResponse) {
11383
if isCreate(&req.State) {
11484
return
11585
}
@@ -128,7 +98,7 @@ func isUpdated(state, plan attr.Value) bool {
12898
return !state.Equal(plan)
12999
}
130100

131-
func (d *createOnlyAttributePlanModifierWithBoolDefault) addDiags(diags *diag.Diagnostics, attrPath path.Path, stateValue attr.Value) {
101+
func (d *createOnlyAttributePlanModifier) addDiags(diags *diag.Diagnostics, attrPath path.Path, stateValue attr.Value) {
132102
message := fmt.Sprintf("%s cannot be updated or set after import, remove it from the configuration or use the state value (see below).", attrPath)
133103
detail := fmt.Sprintf("The current state value is %s", stateValue)
134104
diags.AddError(message, detail)

internal/service/flexcluster/resource.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,7 @@ func (r *rs) Create(ctx context.Context, req resource.CreateRequest, resp *resou
8080
flexClusterResp, err := CreateFlexCluster(ctx, projectID, clusterName, flexClusterReq, connV2.FlexClustersApi, &createTimeout)
8181

8282
// Handle timeout with cleanup logic
83-
deleteOnCreateTimeout := cleanup.ResolveDeleteOnCreateTimeout(tfModel.DeleteOnCreateTimeout)
84-
err = cleanup.HandleCreateTimeout(deleteOnCreateTimeout, err, func(ctxCleanup context.Context) error {
83+
err = cleanup.HandleCreateTimeout(tfModel.DeleteOnCreateTimeout.ValueBool(), err, func(ctxCleanup context.Context) error {
8584
cleanResp, cleanErr := r.Client.AtlasV2.FlexClustersApi.DeleteFlexCluster(ctxCleanup, projectID, clusterName).Execute()
8685
if validate.StatusNotFound(cleanResp) {
8786
return nil

internal/service/flexcluster/resource_schema.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ func ResourceSchema(ctx context.Context) schema.Schema {
5959
"region_name": schema.StringAttribute{
6060
Required: true,
6161
PlanModifiers: []planmodifier.String{
62-
customplanmodifier.CreateOnlyStringPlanModifier(),
62+
customplanmodifier.CreateOnlyAttributePlanModifier(),
6363
},
6464
MarkdownDescription: "Human-readable label that identifies the geographic location of your MongoDB flex cluster. The region you choose can affect network latency for clients accessing your databases. For a complete list of region names, see [AWS](https://docs.atlas.mongodb.com/reference/amazon-aws/#std-label-amazon-aws), [GCP](https://docs.atlas.mongodb.com/reference/google-gcp/), and [Azure](https://docs.atlas.mongodb.com/reference/microsoft-azure/).",
6565
},
@@ -148,8 +148,9 @@ func ResourceSchema(ctx context.Context) schema.Schema {
148148
},
149149
"delete_on_create_timeout": schema.BoolAttribute{
150150
Optional: true,
151+
Computed: true,
151152
PlanModifiers: []planmodifier.Bool{
152-
customplanmodifier.CreateOnlyBoolPlanModifier(),
153+
customplanmodifier.CreateOnlyBoolWithDefaultPlanModifier(true),
153154
},
154155
MarkdownDescription: "Indicates whether to delete the resource being created if a timeout is reached when waiting for completion. When set to `true` and timeout occurs, it triggers the deletion and returns immediately without waiting for deletion to complete. When set to `false`, the timeout will not trigger resource deletion. If you suspect a transient error when the value is `true`, wait before retrying to allow resource deletion to finish. Default is `true`.",
155156
},

internal/service/flexcluster/resource_test.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,11 @@ func basicTestCase(t *testing.T) *resource.TestCase {
104104
Check: checksFlexCluster(projectID, clusterName, false, true),
105105
},
106106
{
107-
ResourceName: resourceName,
108-
ImportStateIdFunc: acc.ImportStateIDFuncProjectIDClusterName(resourceName, "project_id", "name"),
109-
ImportState: true,
110-
ImportStateVerify: true,
107+
ResourceName: resourceName,
108+
ImportStateIdFunc: acc.ImportStateIDFuncProjectIDClusterName(resourceName, "project_id", "name"),
109+
ImportState: true,
110+
ImportStateVerify: true,
111+
ImportStateVerifyIgnore: []string{"delete_on_create_timeout"},
111112
},
112113
},
113114
}

internal/service/project/resource_project_schema.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func ResourceSchema(ctx context.Context) schema.Schema {
6161
// Provider produced invalid plan: planned an invalid value for a non-computed attribute.
6262
Optional: true,
6363
Computed: true,
64-
PlanModifiers: []planmodifier.Bool{customplanmodifier.CreateOnlyAttributePlanModifierWithBoolDefault(true)},
64+
PlanModifiers: []planmodifier.Bool{customplanmodifier.CreateOnlyBoolWithDefaultPlanModifier(true)},
6565
},
6666
"is_collect_database_specifics_statistics_enabled": schema.BoolAttribute{
6767
Computed: true,

0 commit comments

Comments
 (0)