111 lines
3.0 KiB
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
|
|
}
|