From 2a64a009832a33e27718ec5417aa2596844805e0 Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 21 Mar 2019 12:03:12 -0700 Subject: [PATCH] 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. --- terraform/eval_state_upgrade.go | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/terraform/eval_state_upgrade.go b/terraform/eval_state_upgrade.go index e78cc206b7..b7720d71bd 100644 --- a/terraform/eval_state_upgrade.go +++ b/terraform/eval_state_upgrade.go @@ -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)