From 8cd4bd545c3bff49cbfef0f5a78667b106582b1f Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Thu, 21 Nov 2019 16:59:45 -0500 Subject: [PATCH 01/13] Delete dead code --- terraform/eval_diff.go | 71 ------------------------------------------ 1 file changed, 71 deletions(-) diff --git a/terraform/eval_diff.go b/terraform/eval_diff.go index 3ce4adbee..b675253e7 100644 --- a/terraform/eval_diff.go +++ b/terraform/eval_diff.go @@ -1,7 +1,6 @@ package terraform import ( - "bytes" "fmt" "log" "strings" @@ -567,49 +566,6 @@ func processIgnoreChangesIndividual(prior, proposed cty.Value, ignoreChanges []h 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 type flatAttrDiff map[string]*ResourceAttrDiff @@ -630,33 +586,6 @@ func (f flatAttrDiff) keepDiff(ignoreChanges map[string]bool) bool { 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 // destroy diff. type EvalDiffDestroy struct { From d144b83d50278794703b61b152e38487e25d7559 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 12:49:40 -0500 Subject: [PATCH 02/13] This works, with lots of noise --- states/module.go | 66 ++++++++++++++++++++++++++++++++++--------- states/resource.go | 5 ++++ states/sync.go | 2 ++ terraform/evaluate.go | 2 ++ 4 files changed, 61 insertions(+), 14 deletions(-) diff --git a/states/module.go b/states/module.go index d89e7878d..f76746340 100644 --- a/states/module.go +++ b/states/module.go @@ -1,6 +1,8 @@ package states import ( + "fmt" + "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/addrs" @@ -55,7 +57,9 @@ func (ms *Module) ResourceInstance(addr addrs.ResourceInstance) *ResourceInstanc // with the given address, creating the resource state for it if it doesn't // already exist. func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provider addrs.AbsProviderConfig) { + fmt.Printf("%s Set resource meta called with %s \n", addr, eachMode) rs := ms.Resource(addr) + fmt.Println(addr) if rs == nil { rs = &Resource{ Addr: addr, @@ -88,23 +92,56 @@ func (ms *Module) RemoveResource(addr addrs.Resource) { // are updated for all other instances of the same resource as a side-effect of // this call. func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) { - ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) - + // cases for doing nothing + // go get resource: rs := ms.Resource(addr.Resource) + // if the resource is nil and the object is nil, don't do anything! + 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 + if len(rs.Instances) == 0 { + delete(ms.Resources, addr.Resource.String()) + return + } + inst := rs.Instances[addr.Key] + if inst == nil { + // THERE IS NO INSTANCE Bail, don't change everything for no reason + return + } + // then the obj is nil, and we do have an instance, + // set current to nil + inst.Current = obj + if !inst.HasObjects() { + // If we have no objects at all then we'll clean up. + delete(rs.Instances, addr.Key) + if len(rs.Instances) == 0 { + delete(ms.Resources, addr.Resource.String()) + return + } + } + return + } + if rs == nil && obj != nil { + // make the resource! which happens in setResourceMeta, so okay + fmt.Println("Called at the middle", addr.Key) + ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) + // now we have a resource! + rs = ms.Resource(addr.Resource) + } + inst := rs.Instances[addr.Key] + if inst == nil { + rs.EnsureInstance(addr.Key) + ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) + + } is := rs.EnsureInstance(addr.Key) - 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()) - } + fmt.Println("Called at the end", addr.Key) + fmt.Printf("%#v\n", obj) + // ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) } // SetResourceInstanceDeposed saves the given instance object as a deposed @@ -124,6 +161,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R // the instance is left with no objects after this operation then it will // be removed from its containing resource altogether. func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) { + fmt.Println("called with deposed") ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) rs := ms.Resource(addr.Resource) diff --git a/states/resource.go b/states/resource.go index 7f58543c4..1e3d70d19 100644 --- a/states/resource.go +++ b/states/resource.go @@ -46,7 +46,9 @@ func (rs *Resource) Instance(key addrs.InstanceKey) *ResourceInstance { // a write operation. func (rs *Resource) EnsureInstance(key addrs.InstanceKey) *ResourceInstance { ret := rs.Instance(key) + fmt.Println("in ensure") if ret == nil { + fmt.Println("creating an instance") ret = NewResourceInstance() rs.Instances[key] = ret } @@ -180,10 +182,13 @@ const ( func eachModeForInstanceKey(key addrs.InstanceKey) EachMode { switch key.(type) { case addrs.IntKey: + fmt.Println("is int key") return EachList case addrs.StringKey: + fmt.Println("is string key") return EachMap default: + fmt.Println(key) if key == addrs.NoKey { return NoEach } diff --git a/states/sync.go b/states/sync.go index 47fb16d6e..7bf44cd7a 100644 --- a/states/sync.go +++ b/states/sync.go @@ -1,6 +1,7 @@ package states import ( + "fmt" "log" "sync" @@ -190,6 +191,7 @@ func (s *SyncState) SetResourceMeta(addr addrs.AbsResource, eachMode EachMode, p defer s.lock.Unlock() ms := s.state.EnsureModule(addr.Module) + fmt.Println("called from syncstate") ms.SetResourceMeta(addr.Resource, eachMode, provider) } diff --git a/terraform/evaluate.go b/terraform/evaluate.go index de1fd9a05..a70382442 100644 --- a/terraform/evaluate.go +++ b/terraform/evaluate.go @@ -577,6 +577,8 @@ func (d *evaluationStateData) getResourceInstancesAll(addr addrs.Resource, rng t }) return cty.DynamicVal, diags } + fmt.Println(addr.String(), "in getResourceAll") + fmt.Println(rs.EachMode) switch rs.EachMode { case states.NoEach: From 9482bb8eb04edb240315e76017d2f0ef5dacd5b3 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 13:57:36 -0500 Subject: [PATCH 03/13] Comment cleanup --- states/module.go | 29 +++++++++++++---------------- states/resource.go | 2 -- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/states/module.go b/states/module.go index f76746340..8f1596381 100644 --- a/states/module.go +++ b/states/module.go @@ -1,8 +1,6 @@ package states import ( - "fmt" - "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/addrs" @@ -57,9 +55,7 @@ func (ms *Module) ResourceInstance(addr addrs.ResourceInstance) *ResourceInstanc // with the given address, creating the resource state for it if it doesn't // already exist. func (ms *Module) SetResourceMeta(addr addrs.Resource, eachMode EachMode, provider addrs.AbsProviderConfig) { - fmt.Printf("%s Set resource meta called with %s \n", addr, eachMode) rs := ms.Resource(addr) - fmt.Println(addr) if rs == nil { rs = &Resource{ Addr: addr, @@ -92,10 +88,9 @@ func (ms *Module) RemoveResource(addr addrs.Resource) { // are updated for all other instances of the same resource as a side-effect of // this call. func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) { - // cases for doing nothing - // go get resource: rs := ms.Resource(addr.Resource) // 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 } @@ -106,13 +101,16 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R delete(ms.Resources, addr.Resource.String()) return } + // check for an existing resource inst := rs.Instances[addr.Key] if inst == nil { - // THERE IS NO INSTANCE Bail, don't change everything for no reason + // if there is no instance, but the resource exists and has other instances, + // be chill, just return return } - // then the obj is nil, and we do have an instance, - // set current to nil + // if we have an instance, update the current + // TODO: this setting happens below as well, so possibly this can be removed, + // but not changing it right now as we might return in the block below inst.Current = obj if !inst.HasObjects() { // If we have no objects at all then we'll clean up. @@ -125,23 +123,23 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R return } if rs == nil && obj != nil { + // We don't have have a resource // make the resource! which happens in setResourceMeta, so okay - fmt.Println("Called at the middle", addr.Key) ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) - // now we have a resource! + // now we have a resource! so update the rs value rs = ms.Resource(addr.Resource) } + // Get our instance from the resource; it could be there or not at this point inst := rs.Instances[addr.Key] if inst == nil { - rs.EnsureInstance(addr.Key) + // if we don't have a resource, create one + rs.Instances[addr.Key] = NewResourceInstance() + // update the resource meta because we have a new instance, so EachMode may have changed ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) } is := rs.EnsureInstance(addr.Key) is.Current = obj - fmt.Println("Called at the end", addr.Key) - fmt.Printf("%#v\n", obj) - // ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) } // SetResourceInstanceDeposed saves the given instance object as a deposed @@ -161,7 +159,6 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R // the instance is left with no objects after this operation then it will // be removed from its containing resource altogether. func (ms *Module) SetResourceInstanceDeposed(addr addrs.ResourceInstance, key DeposedKey, obj *ResourceInstanceObjectSrc, provider addrs.AbsProviderConfig) { - fmt.Println("called with deposed") ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) rs := ms.Resource(addr.Resource) diff --git a/states/resource.go b/states/resource.go index 1e3d70d19..65ddd7983 100644 --- a/states/resource.go +++ b/states/resource.go @@ -46,9 +46,7 @@ func (rs *Resource) Instance(key addrs.InstanceKey) *ResourceInstance { // a write operation. func (rs *Resource) EnsureInstance(key addrs.InstanceKey) *ResourceInstance { ret := rs.Instance(key) - fmt.Println("in ensure") if ret == nil { - fmt.Println("creating an instance") ret = NewResourceInstance() rs.Instances[key] = ret } From ca9da51516809c9044d307fecd7839d9f5afc61f Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 13:59:12 -0500 Subject: [PATCH 04/13] Cleanup --- states/resource.go | 3 --- states/sync.go | 2 -- terraform/evaluate.go | 2 -- 3 files changed, 7 deletions(-) diff --git a/states/resource.go b/states/resource.go index 65ddd7983..7f58543c4 100644 --- a/states/resource.go +++ b/states/resource.go @@ -180,13 +180,10 @@ const ( func eachModeForInstanceKey(key addrs.InstanceKey) EachMode { switch key.(type) { case addrs.IntKey: - fmt.Println("is int key") return EachList case addrs.StringKey: - fmt.Println("is string key") return EachMap default: - fmt.Println(key) if key == addrs.NoKey { return NoEach } diff --git a/states/sync.go b/states/sync.go index 7bf44cd7a..47fb16d6e 100644 --- a/states/sync.go +++ b/states/sync.go @@ -1,7 +1,6 @@ package states import ( - "fmt" "log" "sync" @@ -191,7 +190,6 @@ func (s *SyncState) SetResourceMeta(addr addrs.AbsResource, eachMode EachMode, p defer s.lock.Unlock() ms := s.state.EnsureModule(addr.Module) - fmt.Println("called from syncstate") ms.SetResourceMeta(addr.Resource, eachMode, provider) } diff --git a/terraform/evaluate.go b/terraform/evaluate.go index a70382442..de1fd9a05 100644 --- a/terraform/evaluate.go +++ b/terraform/evaluate.go @@ -577,8 +577,6 @@ func (d *evaluationStateData) getResourceInstancesAll(addr addrs.Resource, rng t }) return cty.DynamicVal, diags } - fmt.Println(addr.String(), "in getResourceAll") - fmt.Println(rs.EachMode) switch rs.EachMode { case states.NoEach: From fd34def9dc4c5fcd5b9bc58d8a0a7f1e1e2b7c53 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 15:12:26 -0500 Subject: [PATCH 05/13] More comment updates, a lil refactor --- states/module.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/states/module.go b/states/module.go index 8f1596381..152f37500 100644 --- a/states/module.go +++ b/states/module.go @@ -123,22 +123,21 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R return } if rs == nil && obj != nil { - // We don't have have a resource - // make the resource! which happens in setResourceMeta, so okay + // 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 + // 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 - inst := rs.Instances[addr.Key] - if inst == nil { - // if we don't have a resource, create one - rs.Instances[addr.Key] = NewResourceInstance() + is := rs.Instances[addr.Key] + if is == nil { + // if we don't have a resource, create one and add to the instances + is = NewResourceInstance() + rs.Instances[addr.Key] = is // update the resource meta because we have a new instance, so EachMode may have changed ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) } - is := rs.EnsureInstance(addr.Key) is.Current = obj } From 3b4382082d71316f1c8e882002ed86ee9ead2081 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 15:21:55 -0500 Subject: [PATCH 06/13] More comments and names --- states/module.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/states/module.go b/states/module.go index 152f37500..a7a09f5a9 100644 --- a/states/module.go +++ b/states/module.go @@ -101,9 +101,9 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R delete(ms.Resources, addr.Resource.String()) return } - // check for an existing resource - inst := rs.Instances[addr.Key] - if inst == nil { + // check for an existing resource, now that we've ensured that rs.Instances is more than 0/not nil + is := rs.Instances[addr.Key] + if is == nil { // if there is no instance, but the resource exists and has other instances, // be chill, just return return @@ -111,8 +111,8 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R // if we have an instance, update the current // TODO: this setting happens below as well, so possibly this can be removed, // but not changing it right now as we might return in the block below - inst.Current = obj - if !inst.HasObjects() { + is.Current = obj + if !is.HasObjects() { // If we have no objects at all then we'll clean up. delete(rs.Instances, addr.Key) if len(rs.Instances) == 0 { @@ -120,6 +120,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R return } } + // Nothing more to do here, so return! return } if rs == nil && obj != nil { From 87fdcd0064831fac75d3056135755c1dbe62a8c1 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 15:30:51 -0500 Subject: [PATCH 07/13] Add a new method cause doing things in module is weird --- states/module.go | 8 +++----- states/resource.go | 7 +++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/states/module.go b/states/module.go index a7a09f5a9..fa9e71993 100644 --- a/states/module.go +++ b/states/module.go @@ -102,7 +102,7 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R return } // check for an existing resource, now that we've ensured that rs.Instances is more than 0/not nil - is := rs.Instances[addr.Key] + 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 @@ -130,14 +130,12 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R rs = ms.Resource(addr.Resource) } // Get our instance from the resource; it could be there or not at this point - is := rs.Instances[addr.Key] + is := rs.Instance(addr.Key) if is == nil { // if we don't have a resource, create one and add to the instances - is = NewResourceInstance() - rs.Instances[addr.Key] = is + 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) - } is.Current = obj } diff --git a/states/resource.go b/states/resource.go index 7f58543c4..da883ddab 100644 --- a/states/resource.go +++ b/states/resource.go @@ -39,6 +39,13 @@ func (rs *Resource) Instance(key addrs.InstanceKey) *ResourceInstance { 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, // creating a new empty state for it if one doesn't already exist. // From 01da7b4f7f40129d4345d4127fea129e44737bd2 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 15:34:44 -0500 Subject: [PATCH 08/13] Tested and confirmed we cannot delete this, so removed TODO --- states/module.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/states/module.go b/states/module.go index fa9e71993..b172693ee 100644 --- a/states/module.go +++ b/states/module.go @@ -109,8 +109,6 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R return } // if we have an instance, update the current - // TODO: this setting happens below as well, so possibly this can be removed, - // but not changing it right now as we might return in the block below is.Current = obj if !is.HasObjects() { // If we have no objects at all then we'll clean up. From e8aa5bfdc96afd7d058fe48401331f7e0d538b28 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 16:21:15 -0500 Subject: [PATCH 09/13] Confirmed these two tests are fine behavior manually running test case --- terraform/context_apply_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index f53393a7e..ae8e509a1 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -6900,7 +6900,6 @@ func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { actual := strings.TrimSpace(state.String()) expected := strings.TrimSpace(` -module.child: `) if actual != expected { t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) @@ -7066,7 +7065,6 @@ func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { actual := strings.TrimSpace(state.String()) expected := strings.TrimSpace(` -module.child.child2: `) if actual != expected { t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) From 61ce1cb3ad82156a1515cfdc9811d89baf52932c Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 16:40:24 -0500 Subject: [PATCH 10/13] Fix provider related tests --- states/module.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/states/module.go b/states/module.go index b172693ee..23a7bcba2 100644 --- a/states/module.go +++ b/states/module.go @@ -135,6 +135,9 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R // update the resource meta because we have a new instance, so EachMode may have changed ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) } + // Call setResourceMeta one last time, with the resource's current EachMode, lest the + // provider has updated + ms.SetResourceMeta(addr.Resource, rs.EachMode, provider) is.Current = obj } From 19b408e05387055611cf78b2f2e18327380d9b71 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Fri, 22 Nov 2019 16:57:21 -0500 Subject: [PATCH 11/13] Only need this one call, don't call the meta func --- states/module.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/states/module.go b/states/module.go index 23a7bcba2..da4ae4b10 100644 --- a/states/module.go +++ b/states/module.go @@ -135,9 +135,8 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R // update the resource meta because we have a new instance, so EachMode may have changed ms.SetResourceMeta(addr.Resource, eachModeForInstanceKey(addr.Key), provider) } - // Call setResourceMeta one last time, with the resource's current EachMode, lest the - // provider has updated - ms.SetResourceMeta(addr.Resource, rs.EachMode, provider) + // Update the resource's ProviderConfig, in case the provider has updated + rs.ProviderConfig = provider is.Current = obj } From de953eca6f5bd7420ffcbb778ca01c63b417e2e3 Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Tue, 3 Dec 2019 16:29:01 -0500 Subject: [PATCH 12/13] Fixup for allowing empty lists/sets of resources --- states/module.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/states/module.go b/states/module.go index da4ae4b10..4b93af4eb 100644 --- a/states/module.go +++ b/states/module.go @@ -97,7 +97,9 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R if obj == nil && rs != nil { // does the resource have any other objects? // if not then delete the whole resource - if len(rs.Instances) == 0 { + // 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 } @@ -113,7 +115,8 @@ func (ms *Module) SetResourceInstanceCurrent(addr addrs.ResourceInstance, obj *R if !is.HasObjects() { // If we have no objects at all then we'll clean up. delete(rs.Instances, addr.Key) - if len(rs.Instances) == 0 { + // 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 } From c5e6d36ace2e522cad3189ba8c174376874844ff Mon Sep 17 00:00:00 2001 From: Pam Selle <204372+pselle@users.noreply.github.com> Date: Tue, 3 Dec 2019 16:52:29 -0500 Subject: [PATCH 13/13] Revert "Confirmed these two tests are fine behavior manually running test case" This reverts commit e8aa5bfdc96afd7d058fe48401331f7e0d538b28. --- terraform/context_apply_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index ae8e509a1..f53393a7e 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -6900,6 +6900,7 @@ func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { actual := strings.TrimSpace(state.String()) expected := strings.TrimSpace(` +module.child: `) if actual != expected { t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) @@ -7065,6 +7066,7 @@ func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { actual := strings.TrimSpace(state.String()) expected := strings.TrimSpace(` +module.child.child2: `) if actual != expected { t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual)