github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/terraform/transform_orphan_resource.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/cycloidio/terraform/configs"
     7  	"github.com/cycloidio/terraform/dag"
     8  	"github.com/cycloidio/terraform/states"
     9  )
    10  
    11  // OrphanResourceInstanceTransformer is a GraphTransformer that adds orphaned
    12  // resource instances to the graph. An "orphan" is an instance that is present
    13  // in the state but belongs to a resource that is no longer present in the
    14  // configuration.
    15  //
    16  // This is not the transformer that deals with "count orphans" (instances that
    17  // are no longer covered by a resource's "count" or "for_each" setting); that's
    18  // handled instead by OrphanResourceCountTransformer.
    19  type OrphanResourceInstanceTransformer struct {
    20  	Concrete ConcreteResourceInstanceNodeFunc
    21  
    22  	// State is the global state. We require the global state to
    23  	// properly find module orphans at our path.
    24  	State *states.State
    25  
    26  	// Config is the root node in the configuration tree. We'll look up
    27  	// the appropriate note in this tree using the path in each node.
    28  	Config *configs.Config
    29  }
    30  
    31  func (t *OrphanResourceInstanceTransformer) Transform(g *Graph) error {
    32  	if t.State == nil {
    33  		// If the entire state is nil, there can't be any orphans
    34  		return nil
    35  	}
    36  	if t.Config == nil {
    37  		// Should never happen: we can't be doing any Terraform operations
    38  		// without at least an empty configuration.
    39  		panic("OrphanResourceInstanceTransformer used without setting Config")
    40  	}
    41  
    42  	// Go through the modules and for each module transform in order
    43  	// to add the orphan.
    44  	for _, ms := range t.State.Modules {
    45  		if err := t.transform(g, ms); err != nil {
    46  			return err
    47  		}
    48  	}
    49  
    50  	return nil
    51  }
    52  
    53  func (t *OrphanResourceInstanceTransformer) transform(g *Graph, ms *states.Module) error {
    54  	if ms == nil {
    55  		return nil
    56  	}
    57  
    58  	moduleAddr := ms.Addr
    59  
    60  	// Get the configuration for this module. The configuration might be
    61  	// nil if the module was removed from the configuration. This is okay,
    62  	// this just means that every resource is an orphan.
    63  	var m *configs.Module
    64  	if c := t.Config.DescendentForInstance(moduleAddr); c != nil {
    65  		m = c.Module
    66  	}
    67  
    68  	// An "orphan" is a resource that is in the state but not the configuration,
    69  	// so we'll walk the state resources and try to correlate each of them
    70  	// with a configuration block. Each orphan gets a node in the graph whose
    71  	// type is decided by t.Concrete.
    72  	//
    73  	// We don't handle orphans related to changes in the "count" and "for_each"
    74  	// pseudo-arguments here. They are handled by OrphanResourceCountTransformer.
    75  	for _, rs := range ms.Resources {
    76  		if m != nil {
    77  			if r := m.ResourceByAddr(rs.Addr.Resource); r != nil {
    78  				continue
    79  			}
    80  		}
    81  
    82  		for key, inst := range rs.Instances {
    83  			// deposed instances will be taken care of separately
    84  			if inst.Current == nil {
    85  				continue
    86  			}
    87  
    88  			addr := rs.Addr.Instance(key)
    89  			abstract := NewNodeAbstractResourceInstance(addr)
    90  			var node dag.Vertex = abstract
    91  			if f := t.Concrete; f != nil {
    92  				node = f(abstract)
    93  			}
    94  			log.Printf("[TRACE] OrphanResourceInstanceTransformer: adding single-instance orphan node for %s", addr)
    95  			g.Add(node)
    96  		}
    97  	}
    98  
    99  	return nil
   100  }