github.com/mikesimons/terraform@v0.6.13-0.20160304043642-f11448c69214/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 t.ParsedTargets = addrs 32 } 33 if len(t.ParsedTargets) > 0 { 34 targetedNodes, err := t.selectTargetedNodes(g, t.ParsedTargets) 35 if err != nil { 36 return err 37 } 38 39 for _, v := range g.Vertices() { 40 if _, ok := v.(GraphNodeAddressable); ok { 41 if !targetedNodes.Include(v) { 42 log.Printf("[DEBUG] Removing %q, filtered by targeting.", dag.VertexName(v)) 43 g.Remove(v) 44 } 45 } 46 } 47 } 48 return nil 49 } 50 51 func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) { 52 addrs := make([]ResourceAddress, len(t.Targets)) 53 for i, target := range t.Targets { 54 ta, err := ParseResourceAddress(target) 55 if err != nil { 56 return nil, err 57 } 58 addrs[i] = *ta 59 } 60 return addrs, nil 61 } 62 63 // Returns the list of targeted nodes. A targeted node is either addressed 64 // directly, or is an Ancestor of a targeted node. Destroy mode keeps 65 // Descendents instead of Ancestors. 66 func (t *TargetsTransformer) selectTargetedNodes( 67 g *Graph, addrs []ResourceAddress) (*dag.Set, error) { 68 targetedNodes := new(dag.Set) 69 for _, v := range g.Vertices() { 70 if t.nodeIsTarget(v, addrs) { 71 targetedNodes.Add(v) 72 73 // We inform nodes that ask about the list of targets - helps for nodes 74 // that need to dynamically expand. Note that this only occurs for nodes 75 // that are already directly targeted. 76 if tn, ok := v.(GraphNodeTargetable); ok { 77 tn.SetTargets(addrs) 78 } 79 80 var deps *dag.Set 81 var err error 82 if t.Destroy { 83 deps, err = g.Descendents(v) 84 } else { 85 deps, err = g.Ancestors(v) 86 } 87 if err != nil { 88 return nil, err 89 } 90 91 for _, d := range deps.List() { 92 targetedNodes.Add(d) 93 } 94 } 95 } 96 return targetedNodes, nil 97 } 98 99 func (t *TargetsTransformer) nodeIsTarget( 100 v dag.Vertex, addrs []ResourceAddress) bool { 101 r, ok := v.(GraphNodeAddressable) 102 if !ok { 103 return false 104 } 105 addr := r.ResourceAddress() 106 for _, targetAddr := range addrs { 107 if targetAddr.Equals(addr) { 108 return true 109 } 110 } 111 return false 112 }