Ensure all object attrs & empty blocks in upgrade

When upgrading from a flatmap state, unset blocks would not exist in the
state, while they will represented as empty in the new cty.Value. This
will cause an unexpected diff in the first plan after upgrade. This
situation may normally be applied with no impact, but some providers may
have unexpected behavior, and if the attributes force replacement it may
require manual alteration of the state to complete the upgrade.
This commit is contained in:
James Bardin 2019-06-12 18:27:50 -04:00
parent 91ae7ec951
commit dbe22181ae
2 changed files with 27 additions and 2 deletions

View File

@ -15,6 +15,7 @@ import (
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/helper/schema"
proto "github.com/hashicorp/terraform/internal/tfplugin5"
"github.com/hashicorp/terraform/plans/objchange"
"github.com/hashicorp/terraform/plugin/convert"
"github.com/hashicorp/terraform/terraform"
)
@ -283,6 +284,17 @@ func (s *GRPCProviderServer) UpgradeResourceState(_ context.Context, req *proto.
return resp, nil
}
// Now we need to make sure blocks are represented correctly, which means
// that missing blocks are empty collections, rather than null.
// First we need to CoerceValue to ensure that all object types match.
val, err = schemaBlock.CoerceValue(val)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
// Normalize the value and fill in any missing blocks.
val = objchange.NormalizeObjectFromLegacySDK(val, schemaBlock)
// encode the final state to the expected msgpack format
newStateMP, err := msgpack.Marshal(val, schemaBlock.ImpliedType())
if err != nil {

View File

@ -262,6 +262,18 @@ func TestUpgradeState_flatmapState(t *testing.T) {
Type: schema.TypeInt,
Required: true,
},
"block": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"attr": {
Type: schema.TypeString,
Optional: true,
},
},
},
},
},
// this MigrateState will take the state to version 2
MigrateState: func(v int, is *terraform.InstanceState, _ interface{}) (*terraform.InstanceState, error) {
@ -426,8 +438,9 @@ func TestUpgradeState_flatmapState(t *testing.T) {
}
expected := cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("bar"),
"four": cty.NumberIntVal(4),
"block": cty.ListValEmpty(cty.Object(map[string]cty.Type{"attr": cty.String})),
"id": cty.StringVal("bar"),
"four": cty.NumberIntVal(4),
})
if !cmp.Equal(expected, val, valueComparer, equateEmpty) {