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 }