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