hashicorp / terraform-plugin-framework

A next-generation framework for building Terraform providers.
https://developer.hashicorp.com/terraform/plugin/framework
Mozilla Public License 2.0
298 stars 92 forks source link

`Plan` and `State` `SetAttribute` methods do not support setting an untyped nil value #66

Open ewbankkit opened 3 years ago

ewbankkit commented 3 years ago

Module version

% go list -m github.com/hashicorp/terraform-plugin-framework/...
github.com/hashicorp/terraform-plugin-framework v0.1.0

Actual Behavior

The Plan.SetAttribute and State.SetAttribute methods do not currently support setting a Null value via state.SetAttribute(ctx, path, nil). I get the error

error setting value at AttributeName("identifier"): error creating new state value: don't know how to construct attr.Type from <nil> (invalid)

Expected Behavior

To be able to set a Null value (of the type specified at path) in State (and Plan, although I am not currently concerned with that case).

paddycarver commented 3 years ago

Fundamentally, this is a problem with how the reflection code is written. We currently infer some information about what the provider tries to set in state, then compare that to the schema to ensure that it matches what the schema expects. But we start with the type information of the data passed in.

In your example, you're using an untyped nil, which breaks that assumption because it has no type, so it falls through the switch statement. Wrapping it in a type assertion for an appropriate type for that attribute (e.g. *string(nil)) should, in theory, work. As should var val *string.

This isn't intuitive and is annoyingly verbose, though. And there's no reason it has to be this way.

One way to resolve this is to just check, in our reflection code, if the value is nil and return a null value if it is, short-circuiting the type reflection entirely. But I'm suspicious that untyped constants (string literals, numerical literals, etc.) will have the same problem.

A cleaner way may just be to flip our reflection code on it's head, starting with the type the schema defines and switching on that, checking that the data fits in it on a case-by-case basis, which should let us break down the untyped constants problem a little more cleanly.