terraform-plugin-sdk icon indicating copy to clipboard operation
terraform-plugin-sdk copied to clipboard

SetNew does not work on nested fields

Open marclop opened this issue 5 years ago • 5 comments

SDK version

{
  "Path": "github.com/hashicorp/terraform-plugin-sdk",
  "Version": "v1.12.0"
}

Use-cases

Currently, trying to set any nested (computed) field value in a CustomizeDiff function will fail due to a hardcoded false value on d.checkKey() in schema.ResourceDiff.SetNewComputed() and schema.ResourceDiff.SetNew().

This seems to have been changed in commit 1e08e98. Not entirely sure why this change was made, and in any case, the Elasticsearch property is a list, but not a computed one, so not even that would be possible to Get and Set.

My use case is having global values in resources which are used to override nested values.

func Deployment() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
            "version": {
                Type:     schema.TypeString,
                Required: true,
            },

            // Workloads
            "elasticsearch": {
                Type:     schema.TypeList,
                MinItems: 1,
                MaxItems: 1,
                Required: true,
                Elem: &schema.Resource{
                    Schema: map[string]*schema.Schema{
                        // ...
                        "version": {
                            Type:     schema.TypeString,
                            Computed: true,
                        },
                    },
                },
            },
            // ...
        },
		CustomizeDiff: customdiff.All(
			customdiff.IfValueChange("version", func(old, new, meta interface{}) bool {
				return new.(string) > old.(string)
			}, func(d *schema.ResourceDiff, _ interface{}) error {
                // Succeeds obtaining the key.
                log.Println("[DEBUG]", d.Get("elasticsearch.0.version"))
                // Fails setting ANY nested key.
				if err := d.SetNew("elasticsearch.0.version", d.Get("elasticsearch.0.version")); err != nil {
					return err
				}
				return nil
			}),
        ),
    }
}

Proposal

Make SetNewComputed and SetNew able to set items on a list.

marclop avatar May 18 '20 05:05 marclop

Hi, the referenced change https://github.com/hashicorp/terraform-plugin-sdk/commit/1e08e982731eb0c0a35fc00dcc3878bb1f790f70#diff-5572654f34bded06e0d3e5eb9ed7d1bf does not really remove any capability to update nested fields, it only catches the error earlier.

Before that change, an error was triggered in the field writer implementation.

Error: Cannot set new diff value for key metadata.0.resource_version: metadata.0.resource_version: can only set full list

https://github.com/hashicorp/terraform-plugin-sdk/blob/v1.13.1/helper/schema/field_writer_map.go#L72

pdecat avatar Jun 08 '20 09:06 pdecat

Right, I see.

I wonder what the recommended approach would be when this use-case is required

marclop avatar Jun 09 '20 04:06 marclop

This still doesn't work with the V2 of the SDK.

marclop avatar Oct 22 '20 11:10 marclop

Can anyone speak to whether this is a limitation in Terraform or in the SDK (or in protocol 5, which seems unlikely)? I'm wondering if porting to use a different plugin framework would help.

joey-squid avatar May 21 '24 17:05 joey-squid

Hi @joey-squid 👋 It very likely is only an issue with terraform-plugin-sdk (also where this specific error message is being generated). Terraform has some data consistency rules around plan modifications (e.g. you cannot change a configured value to a different planned value), but otherwise will let you fill in or update computed values regardless of whether it is under a nested block or not. Provider code based on terraform-plugin-framework performing plan modification should not run into this type of problem unless it is something disallowed by Terraform itself.

bflad avatar May 21 '24 17:05 bflad