github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/terraform/transform_targets.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/hashicorp/terraform/dag" 7 ) 8 9 // TargetsTransformer is a GraphTransformer that, when the user specifies a 10 // list of resources to target, limits the graph to only those resources and 11 // their dependencies. 12 type TargetsTransformer struct { 13 // List of targeted resource names specified by the user 14 Targets []string 15 16 // List of parsed targets, provided by callers like ResourceCountTransform 17 // that already have the targets parsed 18 ParsedTargets []ResourceAddress 19 20 // Set to true when we're in a `terraform destroy` or a 21 // `terraform plan -destroy` 22 Destroy bool 23 } 24 25 func (t *TargetsTransformer) Transform(g *Graph) error { 26 if len(t.Targets) > 0 && len(t.ParsedTargets) == 0 { 27 addrs, err := t.parseTargetAddresses() 28 if err != nil { 29 return err 30 } 31 32 t.ParsedTargets = addrs 33 } 34 35 if len(t.ParsedTargets) > 0 { 36 targetedNodes, err := t.selectTargetedNodes(g, t.ParsedTargets) 37 if err != nil { 38 return err 39 } 40 41 for _, v := range g.Vertices() { 42 removable := false 43 if _, ok := v.(GraphNodeAddressable); ok { 44 removable = true 45 } 46 if vr, ok := v.(RemovableIfNotTargeted); ok { 47 removable = vr.RemoveIfNotTargeted() 48 } 49 if removable && !targetedNodes.Include(v) { 50 log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v)) 51 g.Remove(v) 52 } 53 } 54 } 55 56 return nil 57 } 58 59 func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) { 60 addrs := make([]ResourceAddress, len(t.Targets)) 61 for i, target := range t.Targets { 62 ta, err := ParseResourceAddress(target) 63 if err != nil { 64 return nil, err 65 } 66 addrs[i] = *ta 67 } 68 69 return addrs, nil 70 } 71 72 // Returns the list of targeted nodes. A targeted node is either addressed 73 // directly, or is an Ancestor of a targeted node. Destroy mode keeps 74 // Descendents instead of Ancestors. 75 func (t *TargetsTransformer) selectTargetedNodes( 76 g *Graph, addrs []ResourceAddress) (*dag.Set, error) { 77 targetedNodes := new(dag.Set) 78 for _, v := range g.Vertices() { 79 if t.nodeIsTarget(v, addrs) { 80 targetedNodes.Add(v) 81 82 // We inform nodes that ask about the list of targets - helps for nodes 83 // that need to dynamically expand. Note that this only occurs for nodes 84 // that are already directly targeted. 85 if tn, ok := v.(GraphNodeTargetable); ok { 86 tn.SetTargets(addrs) 87 } 88 89 var deps *dag.Set 90 var err error 91 if t.Destroy { 92 deps, err = g.Descendents(v) 93 94 // Select any variables that we depend on in case we need them later for 95 // interpolating in the count 96 ancestors, _ := g.Ancestors(v) 97 for _, a := range ancestors.List() { 98 if _, ok := a.(*GraphNodeConfigVariableFlat); ok { 99 deps.Add(a) 100 } 101 } 102 } else { 103 deps, err = g.Ancestors(v) 104 } 105 if err != nil { 106 return nil, err 107 } 108 109 for _, d := range deps.List() { 110 targetedNodes.Add(d) 111 } 112 } 113 } 114 115 return targetedNodes, nil 116 } 117 118 func (t *TargetsTransformer) nodeIsTarget( 119 v dag.Vertex, addrs []ResourceAddress) bool { 120 r, ok := v.(GraphNodeAddressable) 121 if !ok { 122 return false 123 } 124 125 addr := r.ResourceAddress() 126 for _, targetAddr := range addrs { 127 if targetAddr.Equals(addr) { 128 return true 129 } 130 } 131 132 return false 133 } 134 135 // RemovableIfNotTargeted is a special interface for graph nodes that 136 // aren't directly addressable, but need to be removed from the graph when they 137 // are not targeted. (Nodes that are not directly targeted end up in the set of 138 // targeted nodes because something that _is_ targeted depends on them.) The 139 // initial use case for this interface is GraphNodeConfigVariable, which was 140 // having trouble interpolating for module variables in targeted scenarios that 141 // filtered out the resource node being referenced. 142 type RemovableIfNotTargeted interface { 143 RemoveIfNotTargeted() bool 144 }