Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeSet is not modified during Update #792

Open
FlorianJDF opened this issue Aug 12, 2021 · 5 comments
Open

TypeSet is not modified during Update #792

FlorianJDF opened this issue Aug 12, 2021 · 5 comments

Comments

@FlorianJDF
Copy link

SDK Version

2.7.0

Relevant provider source code

Resource:

func resourceTestComponent() *schema.Resource {
	return &schema.Resource{
		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
			},
			"the_test": {
				Type:     schema.TypeSet,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"id": {
							Type:     schema.TypeString,
							Computed: true,
						},
						"to_change": {
							Type:     schema.TypeString,
							Computed: true,
						},
					},
				},
			},
		},
		CreateContext: tCreate,
		CustomizeDiff: tDiff,
		ReadContext:   tRead,
		UpdateContext: tUpdate,
		DeleteContext: tDelete,
	}
}

func tRead(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics {
	log.Println("================> In Read <================")
	var diags diag.Diagnostics
	err := rd.Set("the_test", generateMap([]map[string]string{
		{
			"id":        "1",
			"to_change": "noRead",
		},
		{
			"id":        "2",
			"to_change": "NoRead",
		},
	}))
	if err != nil {
		return diag.FromErr(err)
	}

	log.Println("================> End of Read <================")
	return diags
}

func generateMap(mapper []map[string]string) []interface{} {
	var result []interface{}
	for _, elt := range mapper {
		result = append(result, elt)
	}

	return result
}

func tCreate(c context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
	log.Println("================> In create <================")
	var diags diag.Diagnostics
	data.SetId("un")

	err := data.Set("the_test", generateMap([]map[string]string{
		{
			"id":        "1",
			"to_change": "no",
		},
		{
			"id":        "2",
			"to_change": "no",
		},
	}))
	if err != nil {
		return diag.FromErr(err)
	}

	log.Println("================> End of create <================")
	log.Println(err)
	return diags
}

func tDiff(c context.Context, rd *schema.ResourceDiff, i interface{}) error {
	log.Println("================> In Custom diff <================")

	resourceName, _ := rd.GetChange("name")
	if resourceName == "" {
		return nil
	}

	err := rd.SetNew("the_test", generateMap([]map[string]string{
		{
			"id":        "1",
			"to_change": "yes",
		},
		{
			"id":        "2",
			"to_change": "yes",
		},
	}))
	if err != nil {
		return err
	}

	log.Println("================> End of custom diff <================")
	return nil
}

func tUpdate(c context.Context, data *schema.ResourceData, meta interface{}) diag.Diagnostics {
	log.Println("================> In Update <================")
	var diags diag.Diagnostics
	setter := data.Get("the_test").(*schema.Set)

	log.Println("-> Before sata set")
	log.Println(setter.List())

	for _, elt := range setter.List() {
		m := elt.(map[string]interface{})
		m["to_change"] = "no2"
	}

	log.Println("-> After manual loop")
	log.Println(setter.List())

	err := data.Set("the_test", setter)
	if err != nil {
		return diag.FromErr(err)
	}

	log.Println("-> After sata set")
	setter2 := data.Get("the_test").(*schema.Set)
	log.Println(setter2.List())

	log.Println("================> End of Update <================")
	return diags
}

State First plan/apply

resource "test_comp" "base-config" {
    id       = "un"
    name     = "new"
    the_test = [
        {
            id        = "1"
            to_change = "no"
        },
        {
            id        = "2"
            to_change = "no"
        },
    ]
}

State after the second plan/apply

resource "test_comp" "base-config" {
    id       = "un"
    name     = "new"
    the_test = [
        {
            id        = "1"
            to_change = "yes"
        },
        {
            id        = "2"
            to_change = "yes"
        },
    ]
}

The value of the customDiff is persisted, not the Update.

Issue

I am developping a TF provider.
I have a resource with a Computed TypeSet.

When calling the Create function at first apply, the TypeSet is created with the rights values.
Then the second plan shows the diff from the values in the CustomizeDiff.

But once applied, it is the values of the CustomeDiff that are stored in the state and not the value of the the Update function.

I pasted a representation of the code. In the logs I can see that in the update function the change happened, but is not persisted at the end.
Here are the logs of the provider

2021/08/12 09:46:46 ================> In Update <================: timestamp=2021-08-12T09:46:46.659Z
2021/08/12 09:46:46 -> Before sata set: timestamp=2021-08-12T09:46:46.659Z
2021/08/12 09:46:46 [map[id:1 to_change:yes] map[id:2 to_change:yes]]: timestamp=2021-08-12T09:46:46.659Z
2021/08/12 09:46:46 -> After manual loop: timestamp=2021-08-12T09:46:46.660Z
2021/08/12 09:46:46 [map[id:1 to_change:no2] map[id:2 to_change:no2]]: timestamp=2021-08-12T09:46:46.660Z
2021/08/12 09:46:46 -> After sata set: timestamp=2021-08-12T09:46:46.660Z
 2021/08/12 09:46:46 [map[id:2 to_change:no2] map[id:1 to_change:no2]]: timestamp=2021-08-12T09:46:46.660Z
2021/08/12 09:46:46 ================> End of Update <================: timestamp=2021-08-12T09:46:46.660Z

Expected Behavior

The value stored in the state file shoud be the one set in the function Update.

Am I missing something about how TypeSet works ?

The same behavior is working perfectly with TypeList.

@eduardovra
Copy link

I am experiencing the same problem

@vbauzys
Copy link

vbauzys commented Nov 30, 2021

Observed the same behavior.

@benben
Copy link

benben commented Jun 5, 2023

took me now a full day to end up here, so an annoying 👍 as a comment instead of just a reaction :)

@lgarber-akamai
Copy link

lgarber-akamai commented Jan 2, 2024

Looks like we're running into a similar issue when indirectly updating the linode_instance_config.device field in the Linode Terraform Provider: https://github.com/linode/terraform-provider-linode/blob/dev/linode/instanceconfig/resource.go#L115

@zliang-akamai
Copy link

Also took a full day to debug this, lol
May we have a fix in a future version of SDKv2? @bflad @bendbennett

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants