helper/schema: mark diff as forcenew if element is computed

Fixes #10125

If the elements are computed and the field is ForceNew, then we should
mark the computed count as potentially forcing a new operation.

Example, assuming `groups` forces new...

**Step 1:**

    groups = ["1", "2", "3"]

At this point, the resource isn't create, so this should result in a
diff like:

    CREATE resource:
      groups: "" => ["1", "2", "3"]

**Step 2:**

    groups = ["${computedvar}"]

The OLD behavior was:

    UPDATE resource
      groups.#: "3" => "computed"

This would cause a diff mismatch because if `${computedvar}` was
different then it should force new. The NEW behavior is:

    DESTROY/CREATE resource:
      groups.#: "3" => "computed" (forces new)
This commit is contained in:
Mitchell Hashimoto 2016-11-15 11:02:14 -08:00
parent 75aabd7a79
commit 39542898b0
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 52 additions and 8 deletions

View File

@ -925,6 +925,13 @@ func (m schemaMap) diffSet(
oldStr := strconv.Itoa(oldLen)
newStr := strconv.Itoa(newLen)
// Build a schema for our count
countSchema := &Schema{
Type: TypeInt,
Computed: schema.Computed,
ForceNew: schema.ForceNew,
}
// If the set computed then say that the # is computed
if computedSet || schema.Computed && !nSet {
// If # already exists, equals 0 and no new set is supplied, there
@ -941,22 +948,16 @@ func (m schemaMap) diffSet(
countStr = ""
}
diff.Attributes[k+".#"] = &terraform.ResourceAttrDiff{
diff.Attributes[k+".#"] = countSchema.finalizeDiff(&terraform.ResourceAttrDiff{
Old: countStr,
NewComputed: true,
}
})
return nil
}
// If the counts are not the same, then record that diff
changed := oldLen != newLen
if changed || all {
countSchema := &Schema{
Type: TypeInt,
Computed: schema.Computed,
ForceNew: schema.ForceNew,
}
diff.Attributes[k+".#"] = countSchema.finalizeDiff(&terraform.ResourceAttrDiff{
Old: oldStr,
New: newStr,

View File

@ -2608,6 +2608,49 @@ func TestSchemaMap_Diff(t *testing.T) {
Err: false,
},
{
Name: "Set ForceNew marks count as ForceNew if computed",
Schema: map[string]*Schema{
"ports": &Schema{
Type: TypeSet,
Required: true,
ForceNew: true,
Elem: &Schema{Type: TypeInt},
Set: func(a interface{}) int {
return a.(int)
},
},
},
State: &terraform.InstanceState{
Attributes: map[string]string{
"ports.#": "3",
"ports.1": "1",
"ports.2": "2",
"ports.4": "4",
},
},
Config: map[string]interface{}{
"ports": []interface{}{"${var.foo}", 2, 1},
},
ConfigVariables: map[string]ast.Variable{
"var.foo": interfaceToVariableSwallowError(config.UnknownVariableValue),
},
Diff: &terraform.InstanceDiff{
Attributes: map[string]*terraform.ResourceAttrDiff{
"ports.#": &terraform.ResourceAttrDiff{
Old: "3",
New: "",
NewComputed: true,
RequiresNew: true,
},
},
},
},
}
for i, tc := range cases {