Skip to content

Commit 7ecb0b8

Browse files
committed
Do not add orphan nodes for deposed instances
Resource instances with no current object in state should not have orphan nodes added to the graph, as deposed objects are handled separately. This was previously handled correctly for the non-expanded case, but expanded resources were missing the appropriate check for a current object. Also update the comment in the non-expanded case to hopefully clarify that we're checking for the presence of a current object, not the absence of any deposed objects. An instance may have both a current object and zero or more deposed objects in some circumstances, and if so, we still want an orphan node to be added if the instance is not in configuration.
1 parent d7d8a22 commit 7ecb0b8

File tree

3 files changed

+73
-2
lines changed

3 files changed

+73
-2
lines changed

internal/terraform/transform_orphan_count.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,13 @@ func (t *OrphanResourceInstanceCountTransformer) Transform(g *Graph) error {
3333
// number of instances of a single resource ought to always be small in any
3434
// reasonable Terraform configuration.
3535
Have:
36-
for key := range rs.Instances {
36+
for key, inst := range rs.Instances {
37+
// Instances which have no current objects (only one or more
38+
// deposed objects) will be taken care of separately
39+
if inst.Current == nil {
40+
continue
41+
}
42+
3743
thisAddr := rs.Addr.Instance(key)
3844
for _, wantAddr := range t.InstanceAddrs {
3945
if wantAddr.Equal(thisAddr) {

internal/terraform/transform_orphan_count_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,66 @@ func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) {
161161
}
162162
}
163163

164+
func TestOrphanResourceCountTransformer_deposed(t *testing.T) {
165+
state := states.NewState()
166+
root := state.RootModule()
167+
root.SetResourceInstanceCurrent(
168+
mustResourceInstanceAddr("aws_instance.web").Resource,
169+
&states.ResourceInstanceObjectSrc{
170+
Status: states.ObjectReady,
171+
AttrsJSON: []byte(`{"id":"foo"}`),
172+
},
173+
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
174+
)
175+
root.SetResourceInstanceCurrent(
176+
mustResourceInstanceAddr("aws_instance.foo[0]").Resource,
177+
&states.ResourceInstanceObjectSrc{
178+
Status: states.ObjectReady,
179+
AttrsJSON: []byte(`{"id":"foo"}`),
180+
},
181+
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
182+
)
183+
root.SetResourceInstanceCurrent(
184+
mustResourceInstanceAddr("aws_instance.foo[1]").Resource,
185+
&states.ResourceInstanceObjectSrc{
186+
Status: states.ObjectReady,
187+
AttrsJSON: []byte(`{"id":"foo"}`),
188+
},
189+
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
190+
)
191+
root.SetResourceInstanceDeposed(
192+
mustResourceInstanceAddr("aws_instance.foo[2]").Resource,
193+
states.NewDeposedKey(),
194+
&states.ResourceInstanceObjectSrc{
195+
Status: states.ObjectReady,
196+
AttrsJSON: []byte(`{"id":"foo"}`),
197+
},
198+
mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`),
199+
)
200+
201+
g := Graph{Path: addrs.RootModuleInstance}
202+
203+
{
204+
tf := &OrphanResourceInstanceCountTransformer{
205+
Concrete: testOrphanResourceConcreteFunc,
206+
Addr: addrs.RootModuleInstance.Resource(
207+
addrs.ManagedResourceMode, "aws_instance", "foo",
208+
),
209+
InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")},
210+
State: state,
211+
}
212+
if err := tf.Transform(&g); err != nil {
213+
t.Fatalf("err: %s", err)
214+
}
215+
}
216+
217+
actual := strings.TrimSpace(g.String())
218+
expected := strings.TrimSpace(testTransformOrphanResourceCountDeposedStr)
219+
if actual != expected {
220+
t.Fatalf("bad:\n\n%s", actual)
221+
}
222+
}
223+
164224
// When converting from a NoEach mode to an EachMap via a switch to for_each,
165225
// an edge is necessary to ensure that the map-key'd instances
166226
// are evaluated after the NoKey resource, because the final instance evaluated
@@ -236,6 +296,10 @@ const testTransformOrphanResourceCountOneIndexStr = `
236296
aws_instance.foo[1] (orphan)
237297
`
238298

299+
const testTransformOrphanResourceCountDeposedStr = `
300+
aws_instance.foo[1] (orphan)
301+
`
302+
239303
const testTransformOrphanResourceForEachStr = `
240304
aws_instance.foo (orphan)
241305
aws_instance.foo["bar"] (orphan)

internal/terraform/transform_orphan_resource.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Modul
8787
}
8888

8989
for key, inst := range rs.Instances {
90-
// deposed instances will be taken care of separately
90+
// Instances which have no current objects (only one or more
91+
// deposed objects) will be taken care of separately
9192
if inst.Current == nil {
9293
continue
9394
}

0 commit comments

Comments
 (0)