core: Upgrade flatmap to JSON when dynamic attributes are present

When a resource type schema includes dynamically-typed attributes we can't
do any automatic conversion from flatmap to JSON because we don't know
how to interpret the keys that start with the dynamically-typed
attribute's prefix.

To work around that, we'll instead just ask the SDK to do a no-op upgrade
(current and target versions are the same) which will convert from flatmap
to JSON using the SDK's own logic as a side-effect.

This situation should rarely arise in real-world use, but it ends up being
very important for the helper/resource provider test harness because it
is forced to lower the state back to flatmap repeatedly after every step
in order to run legacy checking and processing code.
This commit is contained in:
Martin Atkins 2019-03-21 12:03:12 -07:00
parent 135121562e
commit 2a64a00983

View File

@ -19,7 +19,18 @@ import (
// If any errors occur during upgrade, error diagnostics are returned. In that
// case it is not safe to proceed with using the original state object.
func UpgradeResourceState(addr addrs.AbsResourceInstance, provider providers.Interface, src *states.ResourceInstanceObjectSrc, currentSchema *configschema.Block, currentVersion uint64) (*states.ResourceInstanceObjectSrc, tfdiags.Diagnostics) {
if src.SchemaVersion == currentVersion {
currentTy := currentSchema.ImpliedType()
// If the state is currently in flatmap format and the current schema
// contains DynamicPseudoType attributes then we won't be able to convert
// it to JSON without the provider's help even if the schema version matches,
// since only the provider knows how to interpret the dynamic attribute
// value in flatmap format to convert it to JSON.
schemaHasDynamic := currentTy.HasDynamicTypes()
stateIsFlatmap := len(src.AttrsJSON) == 0
forceProviderUpgrade := schemaHasDynamic && stateIsFlatmap
if src.SchemaVersion == currentVersion && !forceProviderUpgrade {
// No upgrading required, then.
return src, nil
}
@ -62,10 +73,10 @@ func UpgradeResourceState(addr addrs.AbsResourceInstance, provider providers.Int
Version: int64(src.SchemaVersion),
}
if len(src.AttrsJSON) != 0 {
req.RawStateJSON = src.AttrsJSON
} else {
if stateIsFlatmap {
req.RawStateFlatmap = src.AttrsFlat
} else {
req.RawStateJSON = src.AttrsJSON
}
resp := provider.UpgradeResourceState(req)