terraform/terraform/transform_orphan_count.go

111 lines
3.0 KiB
Go

package terraform
import (
"log"
"github.com/hashicorp/terraform/dag"
)
// OrphanResourceCountTransformer is a GraphTransformer that adds orphans
// for an expanded count to the graph. The determination of this depends
// on the count argument given.
//
// Orphans are found by comparing the count to what is found in the state.
// This transform assumes that if an element in the state is within the count
// bounds given, that it is not an orphan.
type OrphanResourceCountTransformer struct {
Concrete ConcreteResourceNodeFunc
Count int // Actual count of the resource
Addr *ResourceAddress // Addr of the resource to look for orphans
State *State // Full global state
}
func (t *OrphanResourceCountTransformer) Transform(g *Graph) error {
log.Printf("[TRACE] OrphanResourceCount: Starting...")
// Grab the module in the state just for this resource address
ms := t.State.ModuleByPath(normalizeModulePath(t.Addr.Path))
if ms == nil {
// If no state, there can't be orphans
return nil
}
orphanIndex := -1
if t.Count == 1 {
orphanIndex = 0
}
// Go through the orphans and add them all to the state
for key, _ := range ms.Resources {
// Build the address
addr, err := parseResourceAddressInternal(key)
if err != nil {
return err
}
addr.Path = ms.Path[1:]
// Copy the address for comparison. If we aren't looking at
// the same resource, then just ignore it.
addrCopy := addr.Copy()
addrCopy.Index = -1
if !addrCopy.Equals(t.Addr) {
continue
}
log.Printf("[TRACE] OrphanResourceCount: Checking: %s", addr)
idx := addr.Index
// If we have zero and the index here is 0 or 1, then we
// change the index to a high number so that we treat it as
// an orphan.
if t.Count <= 0 && idx <= 0 {
idx = t.Count + 1
}
// If we have a count greater than 0 and we're at the zero index,
// we do a special case check to see if our state also has a
// -1 index value. If so, this is an orphan because our rules are
// that if both a -1 and 0 are in the state, the 0 is destroyed.
if t.Count > 0 && idx == orphanIndex {
// This is a piece of cleverness (beware), but its simple:
// if orphanIndex is 0, then check -1, else check 0.
checkIndex := (orphanIndex + 1) * -1
key := &ResourceStateKey{
Name: addr.Name,
Type: addr.Type,
Mode: addr.Mode,
Index: checkIndex,
}
if _, ok := ms.Resources[key.String()]; ok {
// We have a -1 index, too. Make an arbitrarily high
// index so that we always mark this as an orphan.
log.Printf(
"[WARN] OrphanResourceCount: %q both -1 and 0 index found, orphaning %d",
addr, orphanIndex)
idx = t.Count + 1
}
}
// If the index is within the count bounds, it is not an orphan
if idx < t.Count {
continue
}
// Build the abstract node and the concrete one
abstract := &NodeAbstractResource{Addr: addr}
var node dag.Vertex = abstract
if f := t.Concrete; f != nil {
node = f(abstract)
}
// Add it to the graph
g.Add(node)
}
return nil
}