github.com/jgadling/terraform@v0.3.8-0.20150227214559-abd68c2c87bc/terraform/transform_provisioner.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/go-multierror"
     7  	"github.com/hashicorp/terraform/dag"
     8  )
     9  
    10  // GraphNodeProvisioner is an interface that nodes that can be a provisioner
    11  // must implement. The ProvisionerName returned is the name of the provisioner
    12  // they satisfy.
    13  type GraphNodeProvisioner interface {
    14  	ProvisionerName() string
    15  }
    16  
    17  // GraphNodeProvisionerConsumer is an interface that nodes that require
    18  // a provisioner must implement. ProvisionedBy must return the name of the
    19  // provisioner to use.
    20  type GraphNodeProvisionerConsumer interface {
    21  	ProvisionedBy() []string
    22  }
    23  
    24  // ProvisionerTransformer is a GraphTransformer that maps resources to
    25  // provisioners within the graph. This will error if there are any resources
    26  // that don't map to proper resources.
    27  type ProvisionerTransformer struct{}
    28  
    29  func (t *ProvisionerTransformer) Transform(g *Graph) error {
    30  	// Go through the other nodes and match them to provisioners they need
    31  	var err error
    32  	m := provisionerVertexMap(g)
    33  	for _, v := range g.Vertices() {
    34  		if pv, ok := v.(GraphNodeProvisionerConsumer); ok {
    35  			for _, provisionerName := range pv.ProvisionedBy() {
    36  				target := m[provisionerName]
    37  				if target == nil {
    38  					err = multierror.Append(err, fmt.Errorf(
    39  						"%s: provisioner %s couldn't be found",
    40  						dag.VertexName(v), provisionerName))
    41  					continue
    42  				}
    43  
    44  				g.Connect(dag.BasicEdge(v, target))
    45  			}
    46  		}
    47  	}
    48  
    49  	return err
    50  }
    51  
    52  // MissingProvisionerTransformer is a GraphTransformer that adds nodes
    53  // for missing provisioners into the graph. Specifically, it creates provisioner
    54  // configuration nodes for all the provisioners that we support. These are
    55  // pruned later during an optimization pass.
    56  type MissingProvisionerTransformer struct {
    57  	// Provisioners is the list of provisioners we support.
    58  	Provisioners []string
    59  }
    60  
    61  func (t *MissingProvisionerTransformer) Transform(g *Graph) error {
    62  	m := provisionerVertexMap(g)
    63  	for _, p := range t.Provisioners {
    64  		if _, ok := m[p]; ok {
    65  			// This provisioner already exists as a configured node
    66  			continue
    67  		}
    68  
    69  		// Add our own missing provisioner node to the graph
    70  		g.Add(&graphNodeMissingProvisioner{ProvisionerNameValue: p})
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  // PruneProvisionerTransformer is a GraphTransformer that prunes all the
    77  // provisioners that aren't needed from the graph. A provisioner is unneeded if
    78  // no resource or module is using that provisioner.
    79  type PruneProvisionerTransformer struct{}
    80  
    81  func (t *PruneProvisionerTransformer) Transform(g *Graph) error {
    82  	for _, v := range g.Vertices() {
    83  		// We only care about the provisioners
    84  		if _, ok := v.(GraphNodeProvisioner); !ok {
    85  			continue
    86  		}
    87  
    88  		// Does anything depend on this? If not, then prune it.
    89  		if s := g.UpEdges(v); s.Len() == 0 {
    90  			g.Remove(v)
    91  		}
    92  	}
    93  
    94  	return nil
    95  }
    96  
    97  type graphNodeMissingProvisioner struct {
    98  	ProvisionerNameValue string
    99  }
   100  
   101  func (n *graphNodeMissingProvisioner) Name() string {
   102  	return fmt.Sprintf("provisioner.%s", n.ProvisionerNameValue)
   103  }
   104  
   105  // GraphNodeEvalable impl.
   106  func (n *graphNodeMissingProvisioner) EvalTree() EvalNode {
   107  	return &EvalInitProvisioner{Name: n.ProvisionerNameValue}
   108  }
   109  
   110  func (n *graphNodeMissingProvisioner) ProvisionerName() string {
   111  	return n.ProvisionerNameValue
   112  }
   113  
   114  func provisionerVertexMap(g *Graph) map[string]dag.Vertex {
   115  	m := make(map[string]dag.Vertex)
   116  	for _, v := range g.Vertices() {
   117  		if pv, ok := v.(GraphNodeProvisioner); ok {
   118  			m[pv.ProvisionerName()] = v
   119  		}
   120  	}
   121  
   122  	return m
   123  }