Skip to content

Commit 3000d8c

Browse files
authored
internal/fwserver: Move write-only nullification to earlier in PlanResourceChange (#1097)
* Move write-only nullification so that it happens before marking computed attributes as unknown * Add changelog entry
1 parent 7c9193d commit 3000d8c

File tree

3 files changed

+126
-12
lines changed

3 files changed

+126
-12
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
kind: BUG FIXES
2+
body: 'internal/fwserver: fixed bug where write-only attributes set in configuration would cause perpetual diffs for computed attributes.'
3+
time: 2025-02-19T15:27:52.52508-05:00
4+
custom:
5+
Issue: "1097"

internal/fwserver/server_planresourcechange.go

+12-12
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,18 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange
155155
resp.PlannedState.Raw = data.TerraformValue
156156
}
157157

158+
// Set any write-only attributes in the plan to null
159+
modifiedPlan, err := tftypes.Transform(resp.PlannedState.Raw, NullifyWriteOnlyAttributes(ctx, resp.PlannedState.Schema))
160+
if err != nil {
161+
resp.Diagnostics.AddError(
162+
"Error Modifying Planned State",
163+
"There was an unexpected error modifying the PlannedState. This is always a problem with the provider. Please report the following to the provider developer:\n\n"+err.Error(),
164+
)
165+
return
166+
}
167+
168+
resp.PlannedState.Raw = modifiedPlan
169+
158170
// After ensuring there are proposed changes, mark any computed attributes
159171
// that are null in the config as unknown in the plan, so providers have
160172
// the choice to update them.
@@ -339,18 +351,6 @@ func (s *Server) PlanResourceChange(ctx context.Context, req *PlanResourceChange
339351
)
340352
return
341353
}
342-
343-
// Set any write-only attributes in the plan to null
344-
modifiedPlan, err := tftypes.Transform(resp.PlannedState.Raw, NullifyWriteOnlyAttributes(ctx, resp.PlannedState.Schema))
345-
if err != nil {
346-
resp.Diagnostics.AddError(
347-
"Error Modifying Planned State",
348-
"There was an unexpected error modifying the PlannedState. This is always a problem with the provider. Please report the following to the provider developer:\n\n"+err.Error(),
349-
)
350-
return
351-
}
352-
353-
resp.PlannedState.Raw = modifiedPlan
354354
}
355355

356356
func MarkComputedNilsAsUnknown(ctx context.Context, config tftypes.Value, resourceSchema fwschema.Schema) func(*tftypes.AttributePath, tftypes.Value) (tftypes.Value, error) {

internal/fwserver/server_planresourcechange_test.go

+109
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,14 @@ func TestServerPlanResourceChange(t *testing.T) {
437437
},
438438
}
439439

440+
testSchemaTypeWriteOnly := tftypes.Object{
441+
AttributeTypes: map[string]tftypes.Type{
442+
"test_computed": tftypes.String,
443+
"test_required": tftypes.String,
444+
"test_write_only": tftypes.String,
445+
},
446+
}
447+
440448
testSchemaTypeDefault := tftypes.Object{
441449
AttributeTypes: map[string]tftypes.Type{
442450
"test_computed_bool": tftypes.Bool,
@@ -566,6 +574,21 @@ func TestServerPlanResourceChange(t *testing.T) {
566574
},
567575
}
568576

577+
testSchemaWriteOnly := schema.Schema{
578+
Attributes: map[string]schema.Attribute{
579+
"test_computed": schema.StringAttribute{
580+
Computed: true,
581+
},
582+
"test_required": schema.StringAttribute{
583+
Required: true,
584+
},
585+
"test_write_only": schema.StringAttribute{
586+
Optional: true,
587+
WriteOnly: true,
588+
},
589+
},
590+
}
591+
569592
testSchemaDefault := schema.Schema{
570593
Attributes: map[string]schema.Attribute{
571594
"test_computed_bool": schema.BoolAttribute{
@@ -1069,6 +1092,11 @@ func TestServerPlanResourceChange(t *testing.T) {
10691092
Schema: testSchema,
10701093
}
10711094

1095+
testEmptyStateWriteOnly := &tfsdk.State{
1096+
Raw: tftypes.NewValue(testSchemaType, nil),
1097+
Schema: testSchemaWriteOnly,
1098+
}
1099+
10721100
testEmptyStateDefault := &tfsdk.State{
10731101
Raw: tftypes.NewValue(testSchemaTypeDefault, nil),
10741102
Schema: testSchemaDefault,
@@ -1367,6 +1395,43 @@ func TestServerPlanResourceChange(t *testing.T) {
13671395
PlannedPrivate: testEmptyPrivate,
13681396
},
13691397
},
1398+
"create-mark-computed-config-nils-as-unknown-write-only": {
1399+
server: &fwserver.Server{
1400+
Provider: &testprovider.Provider{},
1401+
},
1402+
request: &fwserver.PlanResourceChangeRequest{
1403+
Config: &tfsdk.Config{
1404+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
1405+
"test_computed": tftypes.NewValue(tftypes.String, nil),
1406+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
1407+
"test_write_only": tftypes.NewValue(tftypes.String, "test-write-only-value"),
1408+
}),
1409+
Schema: testSchemaWriteOnly,
1410+
},
1411+
ProposedNewState: &tfsdk.Plan{
1412+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
1413+
"test_computed": tftypes.NewValue(tftypes.String, nil),
1414+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
1415+
"test_write_only": tftypes.NewValue(tftypes.String, "test-write-only-value"),
1416+
}),
1417+
Schema: testSchemaWriteOnly,
1418+
},
1419+
PriorState: testEmptyStateWriteOnly,
1420+
ResourceSchema: testSchemaWriteOnly,
1421+
Resource: &testprovider.Resource{},
1422+
},
1423+
expectedResponse: &fwserver.PlanResourceChangeResponse{
1424+
PlannedState: &tfsdk.State{
1425+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
1426+
"test_computed": tftypes.NewValue(tftypes.String, tftypes.UnknownValue),
1427+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
1428+
"test_write_only": tftypes.NewValue(tftypes.String, nil),
1429+
}),
1430+
Schema: testSchemaWriteOnly,
1431+
},
1432+
PlannedPrivate: testEmptyPrivate,
1433+
},
1434+
},
13701435
"create-set-default-values": {
13711436
server: &fwserver.Server{
13721437
Provider: &testprovider.Provider{},
@@ -3883,6 +3948,50 @@ func TestServerPlanResourceChange(t *testing.T) {
38833948
PlannedPrivate: testEmptyPrivate,
38843949
},
38853950
},
3951+
"update-mark-computed-config-nils-as-unknown-write-only": {
3952+
server: &fwserver.Server{
3953+
Provider: &testprovider.Provider{},
3954+
},
3955+
request: &fwserver.PlanResourceChangeRequest{
3956+
Config: &tfsdk.Config{
3957+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
3958+
"test_computed": tftypes.NewValue(tftypes.String, nil),
3959+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
3960+
"test_write_only": tftypes.NewValue(tftypes.String, "test-write-only-value"),
3961+
}),
3962+
Schema: testSchemaWriteOnly,
3963+
},
3964+
ProposedNewState: &tfsdk.Plan{
3965+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
3966+
"test_computed": tftypes.NewValue(tftypes.String, "prior-state-val"),
3967+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
3968+
"test_write_only": tftypes.NewValue(tftypes.String, "test-write-only-value"),
3969+
}),
3970+
Schema: testSchemaWriteOnly,
3971+
},
3972+
PriorState: &tfsdk.State{
3973+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
3974+
"test_computed": tftypes.NewValue(tftypes.String, "prior-state-val"),
3975+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
3976+
"test_write_only": tftypes.NewValue(tftypes.String, nil),
3977+
}),
3978+
Schema: testSchemaWriteOnly,
3979+
},
3980+
ResourceSchema: testSchemaWriteOnly,
3981+
Resource: &testprovider.Resource{},
3982+
},
3983+
expectedResponse: &fwserver.PlanResourceChangeResponse{
3984+
PlannedState: &tfsdk.State{
3985+
Raw: tftypes.NewValue(testSchemaTypeWriteOnly, map[string]tftypes.Value{
3986+
"test_computed": tftypes.NewValue(tftypes.String, "prior-state-val"),
3987+
"test_required": tftypes.NewValue(tftypes.String, "test-config-value"),
3988+
"test_write_only": tftypes.NewValue(tftypes.String, nil),
3989+
}),
3990+
Schema: testSchemaWriteOnly,
3991+
},
3992+
PlannedPrivate: testEmptyPrivate,
3993+
},
3994+
},
38863995
"update-set-default-values": {
38873996
server: &fwserver.Server{
38883997
Provider: &testprovider.Provider{},

0 commit comments

Comments
 (0)