plans/objchange: Don't panic when prior state contains nested map blocks

We were using the wrong cty operation to access map members, causing a
panic whenever a prior value was present for a resource type with a nested
block backed by a map value.
This commit is contained in:
Martin Atkins 2019-03-16 17:49:16 -07:00
parent f799a133e3
commit 87fe6cbecd
3 changed files with 41 additions and 2 deletions

View File

@ -177,7 +177,7 @@ func proposedNewObject(schema *configschema.Block, prior, config cty.Value) cty.
atys := configV.Type().AttributeTypes() atys := configV.Type().AttributeTypes()
for name := range atys { for name := range atys {
configEV := configV.GetAttr(name) configEV := configV.GetAttr(name)
if !priorV.Type().HasAttribute(name) { if !priorV.IsKnown() || priorV.IsNull() || !priorV.Type().HasAttribute(name) {
// If there is no corresponding prior element then // If there is no corresponding prior element then
// we just take the config value as-is. // we just take the config value as-is.
newVals[name] = configEV newVals[name] = configEV

View File

@ -182,7 +182,7 @@ func assertPlanValid(schema *configschema.Block, priorState, config, plannedStat
configEV := configV.Index(idx) configEV := configV.Index(idx)
priorEV := cty.NullVal(blockS.ImpliedType()) priorEV := cty.NullVal(blockS.ImpliedType())
if !priorV.IsNull() && priorV.HasIndex(idx).True() { if !priorV.IsNull() && priorV.HasIndex(idx).True() {
priorEV = priorV.GetAttr(k) priorEV = priorV.Index(idx)
} }
moreErrs := assertPlanValid(&blockS.Block, priorEV, configEV, plannedEV, path) moreErrs := assertPlanValid(&blockS.Block, priorEV, configEV, plannedEV, path)
errs = append(errs, moreErrs...) errs = append(errs, moreErrs...)

View File

@ -312,6 +312,45 @@ func TestAssertPlanValid(t *testing.T) {
}), }),
nil, nil,
}, },
"nested map, normal update": {
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"b": {
Nesting: configschema.NestingMap,
Block: configschema.Block{
Attributes: map[string]*configschema.Attribute{
"c": {
Type: cty.String,
Optional: true,
},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"b": cty.MapVal(map[string]cty.Value{
"boop": cty.ObjectVal(map[string]cty.Value{
"c": cty.StringVal("hello"),
}),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"b": cty.MapVal(map[string]cty.Value{
"boop": cty.ObjectVal(map[string]cty.Value{
"c": cty.StringVal("howdy"),
}),
}),
}),
cty.ObjectVal(map[string]cty.Value{
"b": cty.MapVal(map[string]cty.Value{
"boop": cty.ObjectVal(map[string]cty.Value{
"c": cty.StringVal("howdy"),
}),
}),
}),
nil,
},
// Nested block collections are never null // Nested block collections are never null
"nested list, null in plan": { "nested list, null in plan": {