Merge pull request #23475 from hashicorp/pselle/setMetaCleanup
Cleanup SetResourceInstanceCurrent to be clearer and more reliable
This commit is contained in:
commit
2a2201cc74
|
@ -88,23 +88,59 @@ func (ms *Module) RemoveResource(addr addrs.Resource) {
|
||||||
// are updated for all other instances of the same resource as a side-effect of
|
// are updated for all other instances of the same resource as a side-effect of
|
||||||
// this call.
|
// this call.
|
||||||
func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
|
func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) {
|
||||||
ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
|
|
||||||
|
|
||||||
rs := ms.Resource(addr.Resource)
|
rs := ms.Resource(addr.Resource)
|
||||||
is := rs.EnsureInstance(addr.Key)
|
// if the resource is nil and the object is nil, don't do anything!
|
||||||
|
// you'll probably just cause issues
|
||||||
|
if obj == nil && rs == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if obj == nil && rs != nil {
|
||||||
|
// does the resource have any other objects?
|
||||||
|
// if not then delete the whole resource
|
||||||
|
// When deleting the resource, ensure that its EachMode is NoEach,
|
||||||
|
// as a resource with EachList or EachMap can have 0 instances and be valid
|
||||||
|
if rs.EachMode == NoEach && len(rs.Instances) == 0 {
|
||||||
|
delete(ms.Resources, addr.Resource.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// check for an existing resource, now that we've ensured that rs.Instances is more than 0/not nil
|
||||||
|
is := rs.Instance(addr.Key)
|
||||||
|
if is == nil {
|
||||||
|
// if there is no instance, but the resource exists and has other instances,
|
||||||
|
// be chill, just return
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// if we have an instance, update the current
|
||||||
|
is.Current = obj
|
||||||
|
if !is.HasObjects() {
|
||||||
|
// If we have no objects at all then we'll clean up.
|
||||||
|
delete(rs.Instances, addr.Key)
|
||||||
|
// Delete the resource if it has no instances, but only if NoEach
|
||||||
|
if rs.EachMode == NoEach && len(rs.Instances) == 0 {
|
||||||
|
delete(ms.Resources, addr.Resource.String())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Nothing more to do here, so return!
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if rs == nil && obj != nil {
|
||||||
|
// We don't have have a resource so make one, which is a side effect of setResourceMeta
|
||||||
|
ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
|
||||||
|
// now we have a resource! so update the rs value to point to it
|
||||||
|
rs = ms.Resource(addr.Resource)
|
||||||
|
}
|
||||||
|
// Get our instance from the resource; it could be there or not at this point
|
||||||
|
is := rs.Instance(addr.Key)
|
||||||
|
if is == nil {
|
||||||
|
// if we don't have a resource, create one and add to the instances
|
||||||
|
is = rs.CreateInstance(addr.Key)
|
||||||
|
// update the resource meta because we have a new instance, so EachMode may have changed
|
||||||
|
ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider)
|
||||||
|
}
|
||||||
|
// Update the resource's ProviderConfig, in case the provider has updated
|
||||||
|
rs.ProviderConfig = provider
|
||||||
is.Current = obj
|
is.Current = obj
|
||||||
|
|
||||||
if !is.HasObjects() {
|
|
||||||
// If we have no objects at all then we'll clean up.
|
|
||||||
delete(rs.Instances, addr.Key)
|
|
||||||
}
|
|
||||||
if rs.EachMode == NoEach && len(rs.Instances) == 0 {
|
|
||||||
// Also clean up if we only expect to have one instance anyway
|
|
||||||
// and there are none. We leave the resource behind if an each mode
|
|
||||||
// is active because an empty list or map of instances is a valid state.
|
|
||||||
delete(ms.Resources, addr.Resource.String())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetResourceInstanceDeposed saves the given instance object as a deposed
|
// SetResourceInstanceDeposed saves the given instance object as a deposed
|
||||||
|
|
|
@ -39,6 +39,13 @@ func (rs *Resource) Instance(key addrs.InstanceKey) *ResourceInstance {
|
||||||
return rs.Instances[key]
|
return rs.Instances[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateInstance creates an instance and adds it to the resource
|
||||||
|
func (rs *Resource) CreateInstance(key addrs.InstanceKey) *ResourceInstance {
|
||||||
|
is := NewResourceInstance()
|
||||||
|
rs.Instances[key] = is
|
||||||
|
return is
|
||||||
|
}
|
||||||
|
|
||||||
// EnsureInstance returns the state for the instance with the given key,
|
// EnsureInstance returns the state for the instance with the given key,
|
||||||
// creating a new empty state for it if one doesn't already exist.
|
// creating a new empty state for it if one doesn't already exist.
|
||||||
//
|
//
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -567,49 +566,6 @@ func processIgnoreChangesIndividual(prior, proposed cty.Value, ignoreChanges []h
|
||||||
return ret, diags
|
return ret, diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// legacyFlagmapKeyForTraversal constructs a key string compatible with what
|
|
||||||
// the flatmap package would generate for an attribute addressable by the given
|
|
||||||
// traversal.
|
|
||||||
//
|
|
||||||
// This is used only to shim references to attributes within the diff and
|
|
||||||
// state structures, which have not (at the time of writing) yet been updated
|
|
||||||
// to use the newer HCL-based representations.
|
|
||||||
func legacyFlatmapKeyForTraversal(traversal hcl.Traversal) string {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
first := true
|
|
||||||
for _, step := range traversal {
|
|
||||||
if !first {
|
|
||||||
buf.WriteByte('.')
|
|
||||||
}
|
|
||||||
switch ts := step.(type) {
|
|
||||||
case hcl.TraverseRoot:
|
|
||||||
buf.WriteString(ts.Name)
|
|
||||||
case hcl.TraverseAttr:
|
|
||||||
buf.WriteString(ts.Name)
|
|
||||||
case hcl.TraverseIndex:
|
|
||||||
val := ts.Key
|
|
||||||
switch val.Type() {
|
|
||||||
case cty.Number:
|
|
||||||
bf := val.AsBigFloat()
|
|
||||||
buf.WriteString(bf.String())
|
|
||||||
case cty.String:
|
|
||||||
s := val.AsString()
|
|
||||||
buf.WriteString(s)
|
|
||||||
default:
|
|
||||||
// should never happen, since no other types appear in
|
|
||||||
// traversals in practice.
|
|
||||||
buf.WriteByte('?')
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// should never happen, since we've covered all of the types
|
|
||||||
// that show up in parsed traversals in practice.
|
|
||||||
buf.WriteByte('?')
|
|
||||||
}
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// a group of key-*ResourceAttrDiff pairs from the same flatmapped container
|
// a group of key-*ResourceAttrDiff pairs from the same flatmapped container
|
||||||
type flatAttrDiff map[string]*ResourceAttrDiff
|
type flatAttrDiff map[string]*ResourceAttrDiff
|
||||||
|
|
||||||
|
@ -630,33 +586,6 @@ func (f flatAttrDiff) keepDiff(ignoreChanges map[string]bool) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// sets, lists and maps need to be compared for diff inclusion as a whole, so
|
|
||||||
// group the flatmapped keys together for easier comparison.
|
|
||||||
func groupContainers(d *InstanceDiff) map[string]flatAttrDiff {
|
|
||||||
isIndex := multiVal.MatchString
|
|
||||||
containers := map[string]flatAttrDiff{}
|
|
||||||
attrs := d.CopyAttributes()
|
|
||||||
// we need to loop once to find the index key
|
|
||||||
for k := range attrs {
|
|
||||||
if isIndex(k) {
|
|
||||||
// add the key, always including the final dot to fully qualify it
|
|
||||||
containers[k[:len(k)-1]] = flatAttrDiff{}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// loop again to find all the sub keys
|
|
||||||
for prefix, values := range containers {
|
|
||||||
for k, attrDiff := range attrs {
|
|
||||||
// we include the index value as well, since it could be part of the diff
|
|
||||||
if strings.HasPrefix(k, prefix) {
|
|
||||||
values[k] = attrDiff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return containers
|
|
||||||
}
|
|
||||||
|
|
||||||
// EvalDiffDestroy is an EvalNode implementation that returns a plain
|
// EvalDiffDestroy is an EvalNode implementation that returns a plain
|
||||||
// destroy diff.
|
// destroy diff.
|
||||||
type EvalDiffDestroy struct {
|
type EvalDiffDestroy struct {
|
||||||
|
|
Loading…
Reference in New Issue