From 8a412678692ed80496eb8e544776145843240775 Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Thu, 25 Aug 2022 19:27:37 -0700 Subject: [PATCH 1/2] Fix for TypeSet applying with unexpected empty element https://github.com/hashicorp/terraform-plugin-sdk/issues/895 When calculating a diff, sets are added as delete of all old attributes and a create of all new attributes. When DiffSuppressFunc is used, the delete attribute drops the `NewRemoved` field, which results in sending a diff that ends up creating a new empty set element. --- helper/schema/schema.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/helper/schema/schema.go b/helper/schema/schema.go index fc955ce16..c9896afc8 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -1149,10 +1149,10 @@ func (m schemaMap) diff( } logging.HelperSchemaDebug(ctx, "Ignoring change due to DiffSuppressFunc", map[string]interface{}{logging.KeyAttributePath: attrK}) - attrV = &terraform.ResourceAttrDiff{ - Old: attrV.Old, - New: attrV.Old, - } + // If the diff is suppressed, we want Old = New, but retain the other properties. + updatedAttr := *attrV + updatedAttr.New = attrV.Old + attrV = &updatedAttr } } diff.Attributes[attrK] = attrV From f6de18a5b6ab06103a92d6fdd32aae679331b4dd Mon Sep 17 00:00:00 2001 From: Prashant Varanasi Date: Fri, 26 Aug 2022 11:58:54 -0700 Subject: [PATCH 2/2] Add test --- helper/schema/schema_test.go | 74 ++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index a39250fe1..c5d61adbf 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -1155,6 +1155,80 @@ func TestSchemaMap_Diff(t *testing.T) { Err: false, }, + { + Name: "Set with DiffSuppressFunc", + Schema: map[string]*Schema{ + "rule": { + Type: TypeSet, + Required: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "port": { + Type: TypeInt, + Required: true, + }, + "duration": { + Type: TypeString, + Optional: true, + DiffSuppressFunc: func(k, oldValue, newValue string, d *ResourceData) bool { + // Adding a DiffSuppressFunc to an element in a set changes behaviour. + // The actual suppress func doesn't matter. + return oldValue == newValue + }, + }, + }, + }, + Set: func(v interface{}) int { + m := v.(map[string]interface{}) + port := m["port"].(int) + return port + }, + }, + }, + + State: &terraform.InstanceState{ + Attributes: map[string]string{ + "rule.#": "1", + "rule.80.port": "80", + "rule.80.duration": "", + }, + }, + + Config: map[string]interface{}{ + "rule": []interface{}{ + map[string]interface{}{ + "port": 90, + "duration": "30s", + }, + }, + }, + + Diff: &terraform.InstanceDiff{ + Attributes: map[string]*terraform.ResourceAttrDiff{ + "rule.80.port": { + Old: "80", + New: "0", + NewRemoved: true, + }, + "rule.80.duration": { + Old: "", + New: "", + NewRemoved: true, + }, + "rule.90.port": { + Old: "", + New: "90", + }, + "rule.90.duration": { + Old: "", + New: "30s", + }, + }, + }, + + Err: false, + }, + { Name: "List of structure decode", Schema: map[string]*Schema{