diff --git a/internal/terraform/transform_orphan_count.go b/internal/terraform/transform_orphan_count.go index 5b9f3c75c7..bdeebf6d18 100644 --- a/internal/terraform/transform_orphan_count.go +++ b/internal/terraform/transform_orphan_count.go @@ -33,7 +33,13 @@ func (t *OrphanResourceInstanceCountTransformer) Transform(g *Graph) error { // number of instances of a single resource ought to always be small in any // reasonable Terraform configuration. Have: - for key := range rs.Instances { + for key, inst := range rs.Instances { + // Instances which have no current objects (only one or more + // deposed objects) will be taken care of separately + if inst.Current == nil { + continue + } + thisAddr := rs.Addr.Instance(key) for _, wantAddr := range t.InstanceAddrs { if wantAddr.Equal(thisAddr) { diff --git a/internal/terraform/transform_orphan_count_test.go b/internal/terraform/transform_orphan_count_test.go index a777631f09..024189b9a4 100644 --- a/internal/terraform/transform_orphan_count_test.go +++ b/internal/terraform/transform_orphan_count_test.go @@ -161,6 +161,66 @@ func TestOrphanResourceCountTransformer_oneIndex(t *testing.T) { } } +func TestOrphanResourceCountTransformer_deposed(t *testing.T) { + state := states.NewState() + root := state.RootModule() + root.SetResourceInstanceCurrent( + mustResourceInstanceAddr("aws_instance.web").Resource, + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"id":"foo"}`), + }, + mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), + ) + root.SetResourceInstanceCurrent( + mustResourceInstanceAddr("aws_instance.foo[0]").Resource, + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"id":"foo"}`), + }, + mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), + ) + root.SetResourceInstanceCurrent( + mustResourceInstanceAddr("aws_instance.foo[1]").Resource, + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"id":"foo"}`), + }, + mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), + ) + root.SetResourceInstanceDeposed( + mustResourceInstanceAddr("aws_instance.foo[2]").Resource, + states.NewDeposedKey(), + &states.ResourceInstanceObjectSrc{ + Status: states.ObjectReady, + AttrsJSON: []byte(`{"id":"foo"}`), + }, + mustProviderConfig(`provider["registry.terraform.io/hashicorp/aws"]`), + ) + + g := Graph{Path: addrs.RootModuleInstance} + + { + tf := &OrphanResourceInstanceCountTransformer{ + Concrete: testOrphanResourceConcreteFunc, + Addr: addrs.RootModuleInstance.Resource( + addrs.ManagedResourceMode, "aws_instance", "foo", + ), + InstanceAddrs: []addrs.AbsResourceInstance{mustResourceInstanceAddr("aws_instance.foo[0]")}, + State: state, + } + if err := tf.Transform(&g); err != nil { + t.Fatalf("err: %s", err) + } + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTransformOrphanResourceCountDeposedStr) + if actual != expected { + t.Fatalf("bad:\n\n%s", actual) + } +} + // When converting from a NoEach mode to an EachMap via a switch to for_each, // an edge is necessary to ensure that the map-key'd instances // are evaluated after the NoKey resource, because the final instance evaluated @@ -236,6 +296,10 @@ const testTransformOrphanResourceCountOneIndexStr = ` aws_instance.foo[1] (orphan) ` +const testTransformOrphanResourceCountDeposedStr = ` +aws_instance.foo[1] (orphan) +` + const testTransformOrphanResourceForEachStr = ` aws_instance.foo (orphan) aws_instance.foo["bar"] (orphan) diff --git a/internal/terraform/transform_orphan_resource.go b/internal/terraform/transform_orphan_resource.go index 974fdf0de3..348ae90520 100644 --- a/internal/terraform/transform_orphan_resource.go +++ b/internal/terraform/transform_orphan_resource.go @@ -87,7 +87,8 @@ func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Modul } for key, inst := range rs.Instances { - // deposed instances will be taken care of separately + // Instances which have no current objects (only one or more + // deposed objects) will be taken care of separately if inst.Current == nil { continue }