re-count the flatmapped containers

When applying a legacy diff, recount the flatmapped containers. We can't
trust helper/schema to return the correct value, if it even exists.
This commit is contained in:
James Bardin 2018-11-16 15:26:16 -05:00
parent e95f2b586e
commit db968733da
2 changed files with 73 additions and 11 deletions

View File

@ -7,6 +7,7 @@ import (
"reflect"
"regexp"
"sort"
"strconv"
"strings"
"sync"
@ -617,17 +618,9 @@ func (d *InstanceDiff) applyCollectionDiff(attrName string, oldAttrs map[string]
}
}
// Verify we have the index count.
// If it wasn't added from a diff, check it from the previous value.
// Make sure we keep the count if it existed before, so we can tell if it
// existed, or was null.
if !setIndex {
old := oldAttrs[idx]
if old != "" {
result[idx] = old
}
}
// Don't trust helper/schema to return a valid count, or even have one at
// all.
result[idx] = countFlatmapContainerValues(idx, result)
return result, nil
}
@ -686,9 +679,41 @@ func (d *InstanceDiff) applySetDiff(attrName string, oldAttrs map[string]string,
}
}
result[idx] = countFlatmapContainerValues(idx, result)
return result, nil
}
// countFlatmapContainerValues returns the number of values in the flatmapped container
// (set, map, list) indexed by key. The key argument is expected to include the
// trailing ".#", or ".%".
func countFlatmapContainerValues(key string, attrs map[string]string) string {
if len(key) < 3 || !(strings.HasSuffix(key, ".#") || strings.HasSuffix(key, ".%")) {
panic(fmt.Sprintf("invalid index value %q", key))
}
prefix := key[:len(key)-1]
items := map[string]int{}
for k := range attrs {
if k == key {
continue
}
if !strings.HasPrefix(k, prefix) {
continue
}
suffix := k[len(prefix):]
dot := strings.Index(suffix, ".")
if dot > 0 {
suffix = suffix[:dot]
}
items[suffix]++
}
return strconv.Itoa(len(items))
}
// ResourceAttrDiff is the diff of a single attribute of a resource.
type ResourceAttrDiff struct {
Old string // Old Value

View File

@ -3,6 +3,7 @@ package terraform
import (
"fmt"
"reflect"
"strconv"
"strings"
"testing"
@ -1213,3 +1214,39 @@ CREATE: nodeA
longfoo: "foo" => "bar" (forces new resource)
secretfoo: "<sensitive>" => "<sensitive>" (attribute changed)
`
func TestCountFlatmapContainerValues(t *testing.T) {
for i, tc := range []struct {
attrs map[string]string
key string
count string
}{
{
attrs: map[string]string{"set.2.list.#": "9999", "set.2.list.0": "x", "set.2.list.0.z": "y", "set.2.attr": "bar", "set.#": "9999"},
key: "set.2.list.#",
count: "1",
},
{
attrs: map[string]string{"set.2.list.#": "9999", "set.2.list.0": "x", "set.2.list.0.z": "y", "set.2.attr": "bar", "set.#": "9999"},
key: "set.#",
count: "1",
},
{
attrs: map[string]string{"set.2.list.0": "x", "set.2.list.0.z": "y", "set.2.attr": "bar", "set.#": "9999"},
key: "set.#",
count: "1",
},
{
attrs: map[string]string{"map.#": "3", "map.a": "b", "map.a.#": "0", "map.b": "4"},
key: "map.#",
count: "2",
},
} {
t.Run(strconv.Itoa(i), func(t *testing.T) {
count := countFlatmapContainerValues(tc.key, tc.attrs)
if count != tc.count {
t.Fatalf("expected %q, got %q", tc.count, count)
}
})
}
}