From 5de53960f91fce7589ce498c98e561639e9aabbb Mon Sep 17 00:00:00 2001 From: Brian Flad Date: Tue, 8 Oct 2019 11:39:34 -0400 Subject: [PATCH] helper/schema: Do not collapse TypeSet hash values when configuration block contains only Computed attributes Reference: https://github.com/terraform-providers/terraform-provider-aws/issues/7198 Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/10045 Reference: https://github.com/terraform-providers/terraform-provider-aws/pull/10339 Reference: https://github.com/hashicorp/terraform/pull/22719 When a resource schema contains the following: ```go "config_block_attribute": { Type: schema.TypeSet, Computed: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "attribute1": { Type: schema.TypeBool, Computed: true, }, "attribute2": { Type: schema.TypeString, Computed: true, }, }, }, }, ``` The TypeSet hash values were previously all collapsed to the zero-value, which meant that multiple set entries were lost. Here we check that all of the attributes are not just `Computed: true`. If they are all `Computed: true` attributes, ignore the check for user-defined attributes to compute the hash value. --- helper/schema/serialize.go | 9 +++++++-- helper/schema/serialize_test.go | 20 ++++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/helper/schema/serialize.go b/helper/schema/serialize.go index fe6d7504c74..0e0e3cca9e5 100644 --- a/helper/schema/serialize.go +++ b/helper/schema/serialize.go @@ -91,7 +91,12 @@ func SerializeResourceForHash(buf *bytes.Buffer, val interface{}, resource *Reso sm := resource.Schema m := val.(map[string]interface{}) var keys []string - for k := range sm { + allComputed := true + for k, v := range sm { + if v.Optional || v.Required { + allComputed = false + } + keys = append(keys, k) } sort.Strings(keys) @@ -100,7 +105,7 @@ func SerializeResourceForHash(buf *bytes.Buffer, val interface{}, resource *Reso // Skip attributes that are not user-provided. Computed attributes // do not contribute to the hash since their ultimate value cannot // be known at plan/diff time. - if !(innerSchema.Required || innerSchema.Optional) { + if !allComputed && !(innerSchema.Required || innerSchema.Optional) { continue } diff --git a/helper/schema/serialize_test.go b/helper/schema/serialize_test.go index 55afb1528f7..c5480272038 100644 --- a/helper/schema/serialize_test.go +++ b/helper/schema/serialize_test.go @@ -217,6 +217,26 @@ func TestSerializeForHash(t *testing.T) { }, Expected: "outer:{[baz:foo;foo:bar;];};", }, + + testCase{ + Schema: &Resource{ + Schema: map[string]*Schema{ + "attr1": &Schema{ + Type: TypeString, + Computed: true, + }, + "attr2": &Schema{ + Type: TypeString, + Computed: true, + }, + }, + }, + Value: map[string]interface{}{ + "attr1": "value1", + "attr2": "value2", + }, + Expected: "attr1:value1;attr2:value2;", + }, } for _, test := range tests {