diff --git a/plans/objchange/compatible.go b/plans/objchange/compatible.go index 8a74c07fe..d85086c97 100644 --- a/plans/objchange/compatible.go +++ b/plans/objchange/compatible.go @@ -169,6 +169,16 @@ func assertObjectCompatible(schema *configschema.Block, planned, actual cty.Valu }) errs = append(errs, setErrs...) + if maybeUnknownBlocks { + // When unknown blocks are present the final number of blocks + // may be different, either because the unknown set values + // become equal and are collapsed, or the count is unknown due + // a dynamic block. Unfortunately this means we can't do our + // usual checks in this case without generating false + // negatives. + continue + } + // There can be fewer elements in a set after its elements are all // known (values that turn out to be equal will coalesce) but the // number of elements must never get larger. diff --git a/plans/objchange/compatible_test.go b/plans/objchange/compatible_test.go index 2841ec26b..473ee5119 100644 --- a/plans/objchange/compatible_test.go +++ b/plans/objchange/compatible_test.go @@ -1068,9 +1068,9 @@ func TestAssertObjectCompatible(t *testing.T) { }), }), }), - []string{ - `.block: block set length changed from 2 to 3`, - }, + // there is no error here, because the presence of unknowns + // indicates this may be a dynamic block, and the length is unknown + nil, }, { &configschema.Block{ @@ -1135,6 +1135,34 @@ func TestAssertObjectCompatible(t *testing.T) { }), nil, }, + { + &configschema.Block{ + BlockTypes: map[string]*configschema.NestedBlock{ + "block": { + Nesting: configschema.NestingSet, + Block: schemaWithFoo, + }, + }, + }, + cty.ObjectVal(map[string]cty.Value{ + "block": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.UnknownVal(cty.String), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "block": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("a"), + }), + cty.ObjectVal(map[string]cty.Value{ + "foo": cty.StringVal("b"), + }), + }), + }), + nil, + }, { &configschema.Block{ BlockTypes: map[string]*configschema.NestedBlock{