github.com/opentofu/opentofu@v1.7.1/internal/tofu/transform_orphan_count.go (about)

     1  // Copyright (c) The OpenTofu Authors
     2  // SPDX-License-Identifier: MPL-2.0
     3  // Copyright (c) 2023 HashiCorp, Inc.
     4  // SPDX-License-Identifier: MPL-2.0
     5  
     6  package tofu
     7  
     8  import (
     9  	"log"
    10  
    11  	"github.com/opentofu/opentofu/internal/addrs"
    12  	"github.com/opentofu/opentofu/internal/dag"
    13  	"github.com/opentofu/opentofu/internal/states"
    14  )
    15  
    16  // OrphanResourceInstanceCountTransformer is a GraphTransformer that adds orphans
    17  // for an expanded count to the graph. The determination of this depends
    18  // on the count argument given.
    19  //
    20  // Orphans are found by comparing the count to what is found in the state.
    21  // This transform assumes that if an element in the state is within the count
    22  // bounds given, that it is not an orphan.
    23  type OrphanResourceInstanceCountTransformer struct {
    24  	Concrete ConcreteResourceInstanceNodeFunc
    25  
    26  	Addr          addrs.AbsResource           // Addr of the resource to look for orphans
    27  	InstanceAddrs []addrs.AbsResourceInstance // Addresses that currently exist in config
    28  	State         *states.State               // Full global state
    29  }
    30  
    31  func (t *OrphanResourceInstanceCountTransformer) Transform(g *Graph) error {
    32  	rs := t.State.Resource(t.Addr)
    33  	if rs == nil {
    34  		return nil // Resource doesn't exist in state, so nothing to do!
    35  	}
    36  
    37  	// This is an O(n*m) analysis, which we accept for now because the
    38  	// number of instances of a single resource ought to always be small in any
    39  	// reasonable OpenTofu configuration.
    40  Have:
    41  	for key, inst := range rs.Instances {
    42  		// Instances which have no current objects (only one or more
    43  		// deposed objects) will be taken care of separately
    44  		if inst.Current == nil {
    45  			continue
    46  		}
    47  
    48  		thisAddr := rs.Addr.Instance(key)
    49  		for _, wantAddr := range t.InstanceAddrs {
    50  			if wantAddr.Equal(thisAddr) {
    51  				continue Have
    52  			}
    53  		}
    54  		// If thisAddr is not in t.InstanceAddrs then we've found an "orphan"
    55  
    56  		abstract := NewNodeAbstractResourceInstance(thisAddr)
    57  		var node dag.Vertex = abstract
    58  		if f := t.Concrete; f != nil {
    59  			node = f(abstract)
    60  		}
    61  		log.Printf("[TRACE] OrphanResourceInstanceCountTransformer: adding %s as %T", thisAddr, node)
    62  		g.Add(node)
    63  	}
    64  
    65  	return nil
    66  }