core: Ensure hasComputedSubKeys iterates over Sets and Lists properly

This fixes some edge-ish cases where a set in a config has a set or list
in it that contains computed values, but non-set or list values in the
parent do not.

This can cause "diffs didn't match during apply" errors in a scenario
such as when a set's hash is calculated off of child items (including
any sub-lists or sets, as it should be), and the hash changes between
the plan and apply diffs due to the computed values present in the
sub-list or set items. These will be marked as computed, but due to the
fact that the function was not iterating over the list or set items
properly (ie: not adding the item number to the address, so
set.0.set.foo was being yielded instead of set.0.set.0.foo), these
computed values were not being properly propagated to the parent set to
be marked as computed.

Fixes hashicorp/terraform#6527.
Fixes hashicorp/terraform#8271.

This possibly fixes other non-CloudFront related issues too.
This commit is contained in:
Chris Marchesi 2016-10-02 11:02:09 -07:00
parent 283d49f12f
commit 4d8208d840
1 changed files with 21 additions and 3 deletions

View File

@ -265,12 +265,30 @@ func (r *ConfigFieldReader) hasComputedSubKeys(key string, schema *Schema) bool
switch t := schema.Elem.(type) {
case *Resource:
for k, schema := range t.Schema {
if r.Config.IsComputed(prefix + k) {
addr := prefix + k
if r.Config.IsComputed(addr) {
return true
}
if r.hasComputedSubKeys(prefix+k, schema) {
return true
// We need to loop into sets and lists to ensure we pass the correct
// address to the raw config - otherwise for sets we get something like
// set.0.set.item instead of set.0.set.0.item, which renders an
// inaccurate result.
if schema.Type == TypeSet || schema.Type == TypeList {
raw, err := readListField(&nestedConfigFieldReader{r}, strings.Split(addr, "."), schema)
if err != nil {
panic(fmt.Errorf("readListField failed when field was supposed to be list-like: %v", err))
}
// Just range into the address space here, we don't need the value.
for i := range raw.Value.([]interface{}) {
if r.hasComputedSubKeys(addr+"."+strconv.Itoa(i), schema) {
return true
}
}
} else {
if r.hasComputedSubKeys(addr, schema) {
return true
}
}
}
}