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.
pull/21711/head
James Bardin 7 years ago
parent 91ae7ec951
commit dbe22181ae

@ -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 {

@ -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) {

Loading…
Cancel
Save