don't panic with a null list block value in config

Using ignore_changes with a list block, where the provider returned an
invalid null value for that block, can result in a panic when validating
the plan.

Future releases may prevent providers from storing a null block in
state, however we can avoid the panic for now. Only the NestingList case
needs to be handled, because legacy providers only have list and set
blocks, and the set case does not use the config value.
pull/32428/head
James Bardin 3 years ago
parent 0e46d0ad25
commit ea193d5ce6

@ -101,6 +101,14 @@ func assertPlanValid(schema *configschema.Block, priorState, config, plannedStat
continue
}
if configV.IsNull() {
// Configuration cannot decode a block into a null value, but
// we could be dealing with a null returned by a legacy
// provider and inserted via ignore_changes. Fix the value in
// place so the length can still be compared.
configV = cty.ListValEmpty(configV.Type().ElementType())
}
plannedL := plannedV.LengthInt()
configL := configV.LengthInt()
if plannedL != configL {

@ -389,6 +389,41 @@ func TestAssertPlanValid(t *testing.T) {
},
},
// but don't panic on a null list just in case
"nested list, null in config": {
&configschema.Block{
BlockTypes: map[string]*configschema.NestedBlock{
"b": {
Nesting: configschema.NestingList,
Block: configschema.Block{
Attributes: map[string]*configschema.Attribute{
"c": {
Type: cty.String,
Optional: true,
},
},
},
},
},
},
cty.ObjectVal(map[string]cty.Value{
"b": cty.ListValEmpty(cty.Object(map[string]cty.Type{
"c": cty.String,
})),
}),
cty.ObjectVal(map[string]cty.Value{
"b": cty.NullVal(cty.List(cty.Object(map[string]cty.Type{
"c": cty.String,
}))),
}),
cty.ObjectVal(map[string]cty.Value{
"b": cty.ListValEmpty(cty.Object(map[string]cty.Type{
"c": cty.String,
})),
}),
nil,
},
// blocks can be unknown when using dynamic
"nested list, unknown nested dynamic": {
&configschema.Block{
@ -1671,7 +1706,7 @@ func TestAssertPlanValid(t *testing.T) {
t.Logf(
"\nprior: %sconfig: %splanned: %s",
dump.Value(test.Planned),
dump.Value(test.Prior),
dump.Value(test.Config),
dump.Value(test.Planned),
)

Loading…
Cancel
Save