core: Move some of the helper/schema shims so provider mock can use them

The old names are now wrappers around these new functions.
This commit is contained in:
Martin Atkins 2018-09-06 16:48:41 -07:00
parent 9c4aed52b3
commit 76d11f44cc
3 changed files with 91 additions and 69 deletions

View File

@ -2,9 +2,7 @@ package schema
import (
"encoding/json"
"fmt"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/terraform"
@ -40,57 +38,7 @@ func diffFromValues(prior, planned cty.Value, res *Resource, cust CustomizeDiffF
// the legacy provider Diff method to the state required for the new
// PlanResourceChange method.
func ApplyDiff(state cty.Value, d *terraform.InstanceDiff, schemaBlock *configschema.Block) (cty.Value, error) {
// No diff means the state is unchanged.
if d.Empty() {
return state, nil
}
// Create an InstanceState attributes from our existing state.
// We can use this to more easily apply the diff changes.
attrs := hcl2shim.FlatmapValueFromHCL2(state)
if attrs == nil {
attrs = map[string]string{}
}
if d.Destroy || d.DestroyDeposed || d.DestroyTainted {
// to mark a destroy, we remove all attributes
attrs = map[string]string{}
} else if attrs["id"] == "" || d.RequiresNew() {
// Since "id" is always computed, make sure it always has a value. Set
// it as unknown to generate the correct cty.Value
attrs["id"] = config.UnknownVariableValue
}
for attr, diff := range d.Attributes {
old, exists := attrs[attr]
if exists &&
old != diff.Old &&
// if new or old is unknown, then there's no mismatch
old != config.UnknownVariableValue &&
diff.Old != config.UnknownVariableValue {
return state, fmt.Errorf("mismatched diff: %q != %q", old, diff.Old)
}
if diff.NewComputed {
attrs[attr] = config.UnknownVariableValue
continue
}
if diff.NewRemoved {
delete(attrs, attr)
continue
}
attrs[attr] = diff.New
}
val, err := hcl2shim.HCL2ValueFromFlatmap(attrs, schemaBlock.ImpliedType())
if err != nil {
return val, err
}
return schemaBlock.CoerceValue(val)
return d.ApplyToValue(state, schemaBlock)
}
// StateValueToJSONMap converts a cty.Value to generic JSON map via the cty JSON
@ -155,12 +103,5 @@ func StateValueFromInstanceState(is *terraform.InstanceState, ty cty.Type) (cty.
// the provider, because the legacy providers used the private Meta data in the
// InstanceState to store the schema version.
func InstanceStateFromStateValue(state cty.Value, schemaVersion int) *terraform.InstanceState {
attrs := hcl2shim.FlatmapValueFromHCL2(state)
return &terraform.InstanceState{
ID: attrs["id"],
Attributes: attrs,
Meta: map[string]interface{}{
"schema_version": schemaVersion,
},
}
return terraform.NewInstanceStateShimmedFromValue(state, schemaVersion)
}

View File

@ -11,6 +11,10 @@ import (
"sync"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/zclconf/go-cty/cty"
"github.com/mitchellh/copystructure"
)
@ -404,6 +408,66 @@ type InstanceDiff struct {
func (d *InstanceDiff) Lock() { d.mu.Lock() }
func (d *InstanceDiff) Unlock() { d.mu.Unlock() }
// ApplyToValue merges the receiver into the given base value, returning a
// new value that incorporates the planned changes. The given value must
// conform to the given schema, or this method will panic.
//
// This method is intended for shimming old subsystems that still use this
// legacy diff type to work with the new-style types.
func (d *InstanceDiff) ApplyToValue(base cty.Value, schema *configschema.Block) (cty.Value, error) {
// No diff means the state is unchanged.
if d.Empty() {
return base, nil
}
// Create an InstanceState attributes from our existing state.
// We can use this to more easily apply the diff changes.
attrs := hcl2shim.FlatmapValueFromHCL2(base)
if attrs == nil {
attrs = map[string]string{}
}
if d.Destroy || d.DestroyDeposed || d.DestroyTainted {
// to mark a destroy, we remove all attributes
attrs = map[string]string{}
} else if attrs["id"] == "" || d.RequiresNew() {
// Since "id" is always computed, make sure it always has a value. Set
// it as unknown to generate the correct cty.Value
attrs["id"] = config.UnknownVariableValue
}
for attr, diff := range d.Attributes {
old, exists := attrs[attr]
if exists &&
old != diff.Old &&
// if new or old is unknown, then there's no mismatch
old != config.UnknownVariableValue &&
diff.Old != config.UnknownVariableValue {
return base, fmt.Errorf("mismatched diff: %q != %q", old, diff.Old)
}
if diff.NewComputed {
attrs[attr] = config.UnknownVariableValue
continue
}
if diff.NewRemoved {
delete(attrs, attr)
continue
}
attrs[attr] = diff.New
}
val, err := hcl2shim.HCL2ValueFromFlatmap(attrs, schema.ImpliedType())
if err != nil {
return val, err
}
return schema.CoerceValue(val)
}
// ResourceAttrDiff is the diff of a single attribute of a resource.
type ResourceAttrDiff struct {
Old string // Old Value

View File

@ -17,22 +17,23 @@ import (
"sync"
"github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/plans"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/go-version"
"github.com/hashicorp/hcl2/hcl"
"github.com/hashicorp/hcl2/hcl/hclsyntax"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/tfdiags"
tfversion "github.com/hashicorp/terraform/version"
"github.com/mitchellh/copystructure"
"github.com/zclconf/go-cty/cty"
ctyjson "github.com/zclconf/go-cty/cty/json"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/hcl2shim"
"github.com/hashicorp/terraform/configs"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/plans"
"github.com/hashicorp/terraform/tfdiags"
tfversion "github.com/hashicorp/terraform/version"
)
const (
@ -1658,6 +1659,22 @@ func (s *InstanceState) init() {
s.Ephemeral.init()
}
// NewInstanceStateShimmedFromValue is a shim method to lower a new-style
// object value representing the attributes of an instance object into the
// legacy InstanceState representation.
//
// This is for shimming to old components only and should not be used in new code.
func NewInstanceStateShimmedFromValue(state cty.Value, schemaVersion int) *InstanceState {
attrs := hcl2shim.FlatmapValueFromHCL2(state)
return &InstanceState{
ID: attrs["id"],
Attributes: attrs,
Meta: map[string]interface{}{
"schema_version": schemaVersion,
},
}
}
// Copy all the Fields from another InstanceState
func (s *InstanceState) Set(from *InstanceState) {
s.Lock()