github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/terraform/transform_orphan_count.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/hashicorp/terraform/dag"
     7  )
     8  
     9  // OrphanResourceCountTransformer is a GraphTransformer that adds orphans
    10  // for an expanded count to the graph. The determination of this depends
    11  // on the count argument given.
    12  //
    13  // Orphans are found by comparing the count to what is found in the state.
    14  // This transform assumes that if an element in the state is within the count
    15  // bounds given, that it is not an orphan.
    16  type OrphanResourceCountTransformer struct {
    17  	Concrete ConcreteResourceNodeFunc
    18  
    19  	Count int              // Actual count of the resource
    20  	Addr  *ResourceAddress // Addr of the resource to look for orphans
    21  	State *State           // Full global state
    22  }
    23  
    24  func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
    25  	log.Printf("[TRACE] OrphanResourceCount: Starting...")
    26  
    27  	// Grab the module in the state just for this resource address
    28  	ms := t.State.ModuleByPath(normalizeModulePath(t.Addr.Path))
    29  	if ms == nil {
    30  		// If no state, there can't be orphans
    31  		return nil
    32  	}
    33  
    34  	orphanIndex := -1
    35  	if t.Count == 1 {
    36  		orphanIndex = 0
    37  	}
    38  
    39  	// Go through the orphans and add them all to the state
    40  	for key, _ := range ms.Resources {
    41  		// Build the address
    42  		addr, err := parseResourceAddressInternal(key)
    43  		if err != nil {
    44  			return err
    45  		}
    46  		addr.Path = ms.Path[1:]
    47  
    48  		// Copy the address for comparison. If we aren't looking at
    49  		// the same resource, then just ignore it.
    50  		addrCopy := addr.Copy()
    51  		addrCopy.Index = -1
    52  		if !addrCopy.Equals(t.Addr) {
    53  			continue
    54  		}
    55  
    56  		log.Printf("[TRACE] OrphanResourceCount: Checking: %s", addr)
    57  
    58  		idx := addr.Index
    59  
    60  		// If we have zero and the index here is 0 or 1, then we
    61  		// change the index to a high number so that we treat it as
    62  		// an orphan.
    63  		if t.Count <= 0 && idx <= 0 {
    64  			idx = t.Count + 1
    65  		}
    66  
    67  		// If we have a count greater than 0 and we're at the zero index,
    68  		// we do a special case check to see if our state also has a
    69  		// -1 index value. If so, this is an orphan because our rules are
    70  		// that if both a -1 and 0 are in the state, the 0 is destroyed.
    71  		if t.Count > 0 && idx == orphanIndex {
    72  			// This is a piece of cleverness (beware), but its simple:
    73  			// if orphanIndex is 0, then check -1, else check 0.
    74  			checkIndex := (orphanIndex + 1) * -1
    75  
    76  			key := &ResourceStateKey{
    77  				Name:  addr.Name,
    78  				Type:  addr.Type,
    79  				Mode:  addr.Mode,
    80  				Index: checkIndex,
    81  			}
    82  
    83  			if _, ok := ms.Resources[key.String()]; ok {
    84  				// We have a -1 index, too. Make an arbitrarily high
    85  				// index so that we always mark this as an orphan.
    86  				log.Printf(
    87  					"[WARN] OrphanResourceCount: %q both -1 and 0 index found, orphaning %d",
    88  					addr, orphanIndex)
    89  				idx = t.Count + 1
    90  			}
    91  		}
    92  
    93  		// If the index is within the count bounds, it is not an orphan
    94  		if idx < t.Count {
    95  			continue
    96  		}
    97  
    98  		// Build the abstract node and the concrete one
    99  		abstract := &NodeAbstractResource{Addr: addr}
   100  		var node dag.Vertex = abstract
   101  		if f := t.Concrete; f != nil {
   102  			node = f(abstract)
   103  		}
   104  
   105  		// Add it to the graph
   106  		g.Add(node)
   107  	}
   108  
   109  	return nil
   110  }