sdk: use core schema for json state upgrade

When handling the json state in UpgradeResourceState, the schema
must be what core uses, because that is the schema used for
encoding/decoding the json state.

When converting from flatmap to json state, the legacy schema will be
used to decode the flatmap to a cty value, but the resulting json will
be encoded using the CoreConfigSchema to match what core expects.
This commit is contained in:
James Bardin 2019-05-14 15:43:47 -04:00
parent bcf2aa06dd
commit ec65fb960d
2 changed files with 23 additions and 18 deletions

View File

@ -261,30 +261,31 @@ func (s *GRPCProviderServer) UpgradeResourceState(_ context.Context, req *proto.
res := s.provider.ResourcesMap[req.TypeName]
blockForCore := s.getResourceSchemaBlockForCore(req.TypeName)
blockForShimming := s.getResourceSchemaBlockForShimming(req.TypeName)
version := int(req.Version)
var jsonMap map[string]interface{}
jsonMap := map[string]interface{}{}
var err error
// if there's a JSON state, we need to decode it.
if len(req.RawState.Json) > 0 {
err = json.Unmarshal(req.RawState.Json, &jsonMap)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
}
switch {
// We first need to upgrade a flatmap state if it exists.
// There should never be both a JSON and Flatmap state in the request.
if req.RawState.Flatmap != nil {
case len(req.RawState.Flatmap) > 0:
jsonMap, version, err = s.upgradeFlatmapState(version, req.RawState.Flatmap, res)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
// if there's a JSON state, we need to decode it.
case len(req.RawState.Json) > 0:
err = json.Unmarshal(req.RawState.Json, &jsonMap)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
}
default:
log.Println("[DEBUG] no state provided to upgrade")
return resp, nil
}
// complete the upgrade of the JSON states
@ -295,11 +296,11 @@ func (s *GRPCProviderServer) UpgradeResourceState(_ context.Context, req *proto.
}
// The provider isn't required to clean out removed fields
s.removeAttributes(jsonMap, blockForShimming.ImpliedType())
s.removeAttributes(jsonMap, blockForCore.ImpliedType())
// now we need to turn the state into the default json representation, so
// that it can be re-decoded using the actual schema.
val, err := schema.JSONMapToStateValue(jsonMap, blockForShimming)
val, err := schema.JSONMapToStateValue(jsonMap, blockForCore)
if err != nil {
resp.Diagnostics = convert.AppendProtoDiag(resp.Diagnostics, err)
return resp, nil
@ -433,6 +434,11 @@ func (s *GRPCProviderServer) removeAttributes(v interface{}, ty cty.Type) {
return
}
if ty == cty.DynamicPseudoType {
log.Printf("[DEBUG] ignoring dynamic block: %#v\n", v)
return
}
if !ty.IsObjectType() {
// This shouldn't happen, and will fail to decode further on, so
// there's no need to handle it here.

View File

@ -154,10 +154,9 @@ func TestUpgradeState_removedAttr(t *testing.T) {
r3 := &schema.Resource{
Schema: map[string]*schema.Schema{
"config_mode_attr": {
Type: schema.TypeList,
ConfigMode: schema.SchemaConfigModeAttr,
SkipCoreTypeCheck: true,
Optional: true,
Type: schema.TypeList,
ConfigMode: schema.SchemaConfigModeAttr,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"foo": {