fix unknowns added to maps by schemaMap

The legacy diff process inserts unknown values into an optional+computed
map. Fix these up in post-plan normalization process, by looking for
known strings that were changed to unknown.
This commit is contained in:
James Bardin 2019-03-29 11:24:14 -04:00
parent 009df443f7
commit 86e30add98
2 changed files with 43 additions and 6 deletions

View File

@ -1184,11 +1184,8 @@ func normalizeNullValues(dst, src cty.Value, preferDst bool) cty.Value {
dstMap = map[string]cty.Value{} dstMap = map[string]cty.Value{}
} }
ei := src.ElementIterator() srcMap := src.AsValueMap()
for ei.Next() { for key, v := range srcMap {
k, v := ei.Element()
key := k.AsString()
dstVal := dstMap[key] dstVal := dstMap[key]
if dstVal == cty.NilVal { if dstVal == cty.NilVal {
if preferDst && ty.IsMapType() { if preferDst && ty.IsMapType() {
@ -1211,6 +1208,24 @@ func normalizeNullValues(dst, src cty.Value, preferDst bool) cty.Value {
} }
if ty.IsMapType() { if ty.IsMapType() {
// helper/schema will populate an optional+computed map with
// unknowns which we have to fixup here.
// It would be preferable to simply prevent any known value from
// becoming unknown, but concessions have to be made to retain the
// broken legacy behavior when possible.
for k, srcVal := range srcMap {
if !srcVal.IsNull() && srcVal.IsKnown() {
dstVal, ok := dstMap[k]
if !ok {
continue
}
if !dstVal.IsNull() && !dstVal.IsKnown() {
dstMap[k] = srcVal
}
}
}
return cty.MapVal(dstMap) return cty.MapVal(dstMap)
} }

View File

@ -909,7 +909,7 @@ func TestNormalizeNullValues(t *testing.T) {
}), }),
}), }),
}, },
// the empty list should be transferred, but the new unknown show not be overridden // the empty list should be transferred, but the new unknown should not be overridden
{ {
Src: cty.ObjectVal(map[string]cty.Value{ Src: cty.ObjectVal(map[string]cty.Value{
"network_interface": cty.ListVal([]cty.Value{ "network_interface": cty.ListVal([]cty.Value{
@ -942,6 +942,28 @@ func TestNormalizeNullValues(t *testing.T) {
}), }),
Plan: true, Plan: true,
}, },
{
// fix unknowns added to a map
Src: cty.ObjectVal(map[string]cty.Value{
"map": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("a"),
"b": cty.StringVal(""),
}),
}),
Dst: cty.ObjectVal(map[string]cty.Value{
"map": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("a"),
"b": cty.UnknownVal(cty.String),
}),
}),
Expect: cty.ObjectVal(map[string]cty.Value{
"map": cty.MapVal(map[string]cty.Value{
"a": cty.StringVal("a"),
"b": cty.StringVal(""),
}),
}),
Plan: true,
},
} { } {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
got := normalizeNullValues(tc.Dst, tc.Src, tc.Plan) got := normalizeNullValues(tc.Dst, tc.Src, tc.Plan)