diff --git a/helper/schema/schema.go b/helper/schema/schema.go index a3e6cde42..7591721af 100644 --- a/helper/schema/schema.go +++ b/helper/schema/schema.go @@ -919,6 +919,7 @@ func (m schemaMap) diffSet( diff *terraform.InstanceDiff, d *ResourceData, all bool) error { + o, n, _, computedSet := d.diffChange(k) if computedSet { n = nil @@ -1003,6 +1004,7 @@ func (m schemaMap) diffSet( for _, code := range list { switch t := schema.Elem.(type) { case *Resource: + countDiff, cOk := diff.GetAttribute(k + ".#") // This is a complex resource for k2, schema := range t.Schema { subK := fmt.Sprintf("%s.%s.%s", k, code, k2) @@ -1010,7 +1012,17 @@ func (m schemaMap) diffSet( if err != nil { return err } + + // If parent set is being removed + // remove all subfields which were missed by the diff func + // We process these separately because type-specific diff functions + // lack the context (hierarchy of fields) + subKeyIsCount := strings.HasSuffix(subK, ".#") + if cOk && countDiff.New == "0" && !subKeyIsCount { + m.markAsRemoved(subK, schema, diff) + } } + case *Schema: // Copy the schema so that we can set Computed/ForceNew from // the parent schema (the TypeSet). diff --git a/helper/schema/schema_test.go b/helper/schema/schema_test.go index 7fb2a2f11..0a3b7721f 100644 --- a/helper/schema/schema_test.go +++ b/helper/schema/schema_test.go @@ -2985,6 +2985,95 @@ func TestSchemaMap_Diff(t *testing.T) { }, }, }, + + { + Name: "Removal of TypeSet should cause computed fields to be removed", + Schema: map[string]*Schema{ + "type_set": &Schema{ + Type: TypeSet, + Optional: true, + Elem: &Resource{ + Schema: map[string]*Schema{ + "name": &Schema{ + Type: TypeString, + Optional: true, + }, + "required": &Schema{ + Type: TypeString, + Required: true, + }, + "value": &Schema{ + Type: TypeInt, + Optional: true, + }, + "required_value": &Schema{ + Type: TypeInt, + Required: true, + }, + "computed_value": &Schema{ + Type: TypeString, + Optional: true, + Computed: true, + }, + }, + }, + Set: func(i interface{}) int { + if i != nil { + return 12345 + } + return 0 + }, + }, + }, + + State: &terraform.InstanceState{ + Attributes: map[string]string{ + "type_set.#": "1", + "type_set.12345.name": "Name", + "type_set.12345.required": "Required", + "type_set.12345.value": "0", + "type_set.12345.required_value": "5", + "type_set.12345.computed_value": "COMPUTED", + }, + }, + + Config: map[string]interface{}{ + "type_set": []interface{}{}, + }, + + Diff: &terraform.InstanceDiff{ + Attributes: map[string]*terraform.ResourceAttrDiff{ + "type_set.#": &terraform.ResourceAttrDiff{ + Old: "1", + New: "0", + NewRemoved: false, + }, + "type_set.12345.name": &terraform.ResourceAttrDiff{ + Old: "Name", + New: "", + NewRemoved: true, + }, + "type_set.12345.required": &terraform.ResourceAttrDiff{ + Old: "Required", + New: "", + NewRemoved: true, + }, + "type_set.12345.value": &terraform.ResourceAttrDiff{ + Old: "0", + New: "0", + NewRemoved: true, + }, + "type_set.12345.required_value": &terraform.ResourceAttrDiff{ + Old: "5", + New: "0", + NewRemoved: true, + }, + "type_set.12345.computed_value": &terraform.ResourceAttrDiff{ + NewRemoved: true, + }, + }, + }, + }, } for i, tc := range cases {