Skip to content

Commit ace6ca3

Browse files
austinvallebflad
andauthored
website: Add data consistency error migration docs for "planned value does not match config value" (#831)
* move docs from sdk PR * Update website/docs/plugin/framework/migrating/resources/crud.mdx Co-authored-by: Brian Flad <[email protected]> * removed state example --------- Co-authored-by: Brian Flad <[email protected]>
1 parent 832bdbc commit ace6ca3

File tree

3 files changed

+133
-3
lines changed

3 files changed

+133
-3
lines changed

website/docs/plugin/framework/migrating/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ As you complete the migration, we recommend that you follow Test Driven Developm
3636
Take the following steps when you migrate a provider from SDKv2 to the Framework:
3737

3838
- Ensure all [tests](/terraform/plugin/framework/migrating/testing#testing-migration) pass.
39-
- Consider [finding SDKv2 resource data consistency errors](/terraform/plugin/sdkv2/resources/data-consistency-errors), which might affect migrating to the Framework. Some errors can be resolved and verified with SDKv2 code before migration, if desired, otherwise resolving these errors must be part of the migration.
39+
- Consider [finding SDKv2 resource data consistency errors](/terraform/plugin/sdkv2/resources/data-consistency-errors), which might affect migrating to the Framework. Some errors can be resolved and verified with SDKv2 code before migration, if desired, otherwise resolving these errors must be [part of the migration](/terraform/plugin/framework/migrating/resources/crud#resolving-data-consistency-errors).
4040
- [Serve the provider](/terraform/plugin/framework/migrating/providers#serving-the-provider) via the Framework.
4141
- Implement [muxing](/terraform/plugin/framework/migrating/mux), if you plan to migrate the provider iteratively.
4242
- Update the [provider definition](/terraform/plugin/framework/migrating/providers#provider-definition) to use the Framework.

website/docs/plugin/framework/migrating/resources/crud.mdx

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ function. In the Framework, you must implement each of the CRUD lifecycle functi
7373
`schema.ResourceData`. In the Framework, you get attribute values from the configuration and plan by accessing
7474
`Config` and `Plan` on `resource.CreateRequest`. You set attribute values in Terraform's state by mutating `State`
7575
on `resource.CreateResponse`.
76-
- In SDKv2, certain resource schema definition and data consistency errors are only visible as Terraform warning logs by default. After migration, these errors will always be visible to practitioners and prevent further Terraform operations. The [SDKv2 resource data consistency errors documentation](/terraform/plugin/sdkv2/resources/data-consistency-errors) discusses how to find and potentially resolve these.
76+
- In SDKv2, certain resource schema definition and data consistency errors are only visible as Terraform warning logs by default. After migration, these errors will always be visible to practitioners and prevent further Terraform operations. The [SDKv2 resource data consistency errors documentation](/terraform/plugin/sdkv2/resources/data-consistency-errors) discusses how to find these errors in SDKv2 resources and potential solutions **prior** to migrating. See the [Resolving Data Consistency Errors](#resolving-data-consistency-errors) section for Plugin Framework solutions **during** migration.
7777
7878
## Example
7979
@@ -126,3 +126,133 @@ func (r *exampleResource) Create(ctx context.Context, req resource.CreateRequest
126126
resp.Diagnostics.Append(diags...)
127127
}
128128
```
129+
130+
## Resolving Data Consistency Errors
131+
<Note>
132+
133+
See the [SDKv2 data consistency errors documentation](/terraform/plugin/sdkv2/resources/data-consistency-errors) for background info, debugging tips, and potential SDKv2 solutions.
134+
135+
</Note>
136+
137+
### Planned Value does not match Config Value
138+
139+
If an SDKv2 resource is raising this type of error or [warning log](/terraform/plugin/sdkv2/resources/data-consistency-errors#checking-for-warning-logs):
140+
141+
```text
142+
TIMESTAMP [WARN] Provider "TYPE" produced an invalid plan for ADDRESS, but we are tolerating it because it is using the legacy plugin SDK.
143+
The following problems may be the cause of any confusing errors from downstream operations:
144+
- .ATTRIBUTE: planned value cty.StringVal("VALUE") does not match config value cty.StringVal("value")
145+
```
146+
147+
This occurs for attribute schema definitions that are `Optional: true` and `Computed: true`; where the planned value, returned by the provider, does not match the attribute's config value or prior state value. For example, value's for an attribute of type string must match byte-for-byte.
148+
149+
An example root cause of this issue could be from API normalization, such as a JSON string being returned from an API and stored in state with differing whitespace then what was originally in config.
150+
151+
#### SDKv2 Example
152+
153+
Here is an example of an SDKv2 resource schema and terraform config that simulates this data consistency error:
154+
155+
```go
156+
func thingResource() *schema.Resource {
157+
return &schema.Resource{
158+
// ...
159+
Schema: map[string]*schema.Schema{
160+
"word": {
161+
Type: schema.TypeString,
162+
Optional: true,
163+
Computed: true,
164+
StateFunc: func(word interface{}) string {
165+
// This simulates an API returning the 'word' attribute as all uppercase,
166+
// which is stored to state even if it doesn't match the config or prior value.
167+
return strings.ToUpper(word.(string))
168+
},
169+
},
170+
},
171+
}
172+
}
173+
```
174+
175+
```hcl
176+
resource "examplecloud_thing" "this" {
177+
word = "value"
178+
}
179+
```
180+
181+
A [warning log](/terraform/plugin/sdkv2/resources/data-consistency-errors#checking-for-warning-logs) will be produced and the resulting state after applying a new resource will be `VALUE` instead of `value`.
182+
183+
#### Migrating to Plugin Framework
184+
185+
When a resource with this behavior and prior state is migrated to Plugin Framework, depending on the business logic, you could potentially see:
186+
187+
- Resource drift in the plan; Terraform will always detect a change between the config and state value. If no [modification](/terraform/plugin/framework/resources/plan-modification) is implemented, you could see drift in the plan:
188+
```hcl
189+
resource "examplecloud_thing" "this" {
190+
word = "value"
191+
}
192+
```
193+
```text
194+
examplecloud_thing.this: Refreshing state...
195+
196+
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
197+
~ update in-place
198+
199+
Terraform will perform the following actions:
200+
201+
# examplecloud_thing.this will be updated in-place
202+
~ resource "examplecloud_thing" "this" {
203+
~ word = "VALUE" -> "value"
204+
}
205+
206+
Plan: 0 to add, 1 to change, 0 to destroy.
207+
```
208+
- If you mimic the original SDKv2 behavior of storing a different value from config/prior value into state in the `Update` method, you will see an error like below:
209+
```text
210+
examplecloud_thing.this: Modifying...
211+
212+
│ Error: Provider produced inconsistent result after apply
213+
214+
│ When applying changes to examplecloud_thing.this, provider "provider[\"TYPE\"]" produced an unexpected
215+
new value: .word: was cty.StringVal("value"), but now cty.StringVal("VALUE").
216+
217+
│ This is a bug in the provider, which should be reported in the provider's own issue tracker.
218+
```
219+
220+
#### Recommended Solution
221+
To solve this issue, the provider code must preserve the config value or prior state value when producing the new state. The recommended way to implement this logic is by creating a [custom type](/terraform/plugin/framework/handling-data/types/custom) with [semantic equality logic](/terraform/plugin/framework/handling-data/types/custom#semantic-equality). A custom type can be shared across multiple resource attributes and will ensure that the semantic equality logic is invoked during the `Read`, `Create`, and `Update` methods respectively.
222+
223+
For the above example, the semantic equality implementation below would resolve the resource drift and error:
224+
225+
<Tip>
226+
227+
The example code below is a partial implementation of a custom type, please see the [Custom Value Type documentation](/terraform/plugin/framework/handling-data/types/custom#value-type) for guidance.
228+
229+
</Tip>
230+
231+
```go
232+
type CaseInsensitive struct {
233+
basetypes.StringValue
234+
}
235+
236+
// ... custom value type implementation
237+
238+
// StringSemanticEquals returns true if the given string value is semantically equal to the current string value. (case-insensitive)
239+
func (v CaseInsensitive) StringSemanticEquals(_ context.Context, newValuable basetypes.StringValuable) (bool, diag.Diagnostics) {
240+
var diags diag.Diagnostics
241+
242+
newValue, ok := newValuable.(CaseInsensitive)
243+
if !ok {
244+
diags.AddError(
245+
"Semantic Equality Check Error",
246+
"An unexpected value type was received while performing semantic equality checks. "+
247+
"Please report this to the provider developers.\n\n"+
248+
"Expected Value Type: "+fmt.Sprintf("%T", v)+"\n"+
249+
"Got Value Type: "+fmt.Sprintf("%T", newValuable),
250+
)
251+
252+
return false, diags
253+
}
254+
255+
return strings.EqualFold(newValue.ValueString(), v.ValueString()), diags
256+
}
257+
```
258+

website/docs/plugin/framework/migrating/resources/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ the `resource.Resource` interface, which includes a `Schema` method that returns
141141
- SDKv2 implements a resource's CRUD operations as functions on the `schema.Resource`. In the Framework, you define a
142142
type that implements the `resource.Resource` interface. The resource interface contains the functions that define your resource's
143143
CRUD operations.
144-
- SDKv2 by default demotes certain resource schema definition and data consistency errors to only be visible as Terraform warning logs. After migration, these errors will always be visible to practitioners and prevent further Terraform operations. The [SDKv2 resource data consistency errors documentation](/terraform/plugin/sdkv2/resources/data-consistency-errors) discusses how to find and potentially resolve these.
144+
- SDKv2 by default demotes certain resource schema definition and data consistency errors to only be visible as Terraform warning logs. After migration, these errors will always be visible to practitioners and prevent further Terraform operations. The [SDKv2 resource data consistency errors documentation](/terraform/plugin/sdkv2/resources/data-consistency-errors) discusses how to find these errors in SDKv2 resources and potential solutions **prior** to migrating. See the [CRUD - Resolving Data Consistency Errors](/terraform/plugin/framework/migrating/resources/crud#resolving-data-consistency-errors) section for Plugin Framework solutions **during** migration.
145145

146146
## Example
147147

0 commit comments

Comments
 (0)