github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/terraform/transform_targets.go (about)

     1  package terraform
     2  
     3  import "github.com/hashicorp/terraform/dag"
     4  
     5  // TargetsTransformer is a GraphTransformer that, when the user specifies a
     6  // list of resources to target, limits the graph to only those resources and
     7  // their dependencies.
     8  type TargetsTransformer struct {
     9  	// List of targeted resource names specified by the user
    10  	Targets []string
    11  
    12  	// Set to true when we're in a `terraform destroy` or a
    13  	// `terraform plan -destroy`
    14  	Destroy bool
    15  }
    16  
    17  func (t *TargetsTransformer) Transform(g *Graph) error {
    18  	if len(t.Targets) > 0 {
    19  		// TODO: duplicated in OrphanTransformer; pull up parsing earlier
    20  		addrs, err := t.parseTargetAddresses()
    21  		if err != nil {
    22  			return err
    23  		}
    24  
    25  		targetedNodes, err := t.selectTargetedNodes(g, addrs)
    26  		if err != nil {
    27  			return err
    28  		}
    29  
    30  		for _, v := range g.Vertices() {
    31  			if targetedNodes.Include(v) {
    32  			} else {
    33  				g.Remove(v)
    34  			}
    35  		}
    36  	}
    37  	return nil
    38  }
    39  
    40  func (t *TargetsTransformer) parseTargetAddresses() ([]ResourceAddress, error) {
    41  	addrs := make([]ResourceAddress, len(t.Targets))
    42  	for i, target := range t.Targets {
    43  		ta, err := ParseResourceAddress(target)
    44  		if err != nil {
    45  			return nil, err
    46  		}
    47  		addrs[i] = *ta
    48  	}
    49  	return addrs, nil
    50  }
    51  
    52  func (t *TargetsTransformer) selectTargetedNodes(
    53  	g *Graph, addrs []ResourceAddress) (*dag.Set, error) {
    54  	targetedNodes := new(dag.Set)
    55  	for _, v := range g.Vertices() {
    56  		// Keep all providers; they'll be pruned later if necessary
    57  		if r, ok := v.(GraphNodeProvider); ok {
    58  			targetedNodes.Add(r)
    59  			continue
    60  		}
    61  
    62  		// For the remaining filter, we only care about addressable nodes
    63  		r, ok := v.(GraphNodeAddressable)
    64  		if !ok {
    65  			continue
    66  		}
    67  
    68  		if t.nodeIsTarget(r, addrs) {
    69  			targetedNodes.Add(r)
    70  			// If the node would like to know about targets, tell it.
    71  			if n, ok := r.(GraphNodeTargetable); ok {
    72  				n.SetTargets(addrs)
    73  			}
    74  
    75  			var deps *dag.Set
    76  			var err error
    77  			if t.Destroy {
    78  				deps, err = g.Descendents(r)
    79  			} else {
    80  				deps, err = g.Ancestors(r)
    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  	r GraphNodeAddressable, addrs []ResourceAddress) bool {
    96  	addr := r.ResourceAddress()
    97  	for _, targetAddr := range addrs {
    98  		if targetAddr.Equals(addr) {
    99  			return true
   100  		}
   101  	}
   102  	return false
   103  }