github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/terraform/transform_provider.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  // GraphNodeProvider is an interface that nodes that can be a provider
    11  // must implement. The ProviderName returned is the name of the provider
    12  // they satisfy.
    13  type GraphNodeProvider interface {
    14  	ProviderName() string
    15  }
    16  
    17  // GraphNodeProviderConsumer is an interface that nodes that require
    18  // a provider must implement. ProvidedBy must return the name of the provider
    19  // to use.
    20  type GraphNodeProviderConsumer interface {
    21  	ProvidedBy() []string
    22  }
    23  
    24  // ProviderTransformer is a GraphTransformer that maps resources to
    25  // providers within the graph. This will error if there are any resources
    26  // that don't map to proper resources.
    27  type ProviderTransformer struct{}
    28  
    29  func (t *ProviderTransformer) Transform(g *Graph) error {
    30  	// Go through the other nodes and match them to providers they need
    31  	var err error
    32  	m := providerVertexMap(g)
    33  	for _, v := range g.Vertices() {
    34  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
    35  			for _, p := range pv.ProvidedBy() {
    36  				target := m[p]
    37  				if target == nil {
    38  					err = multierror.Append(err, fmt.Errorf(
    39  						"%s: provider %s couldn't be found",
    40  						dag.VertexName(v), p))
    41  					continue
    42  				}
    43  
    44  				g.Connect(dag.BasicEdge(v, target))
    45  			}
    46  		}
    47  	}
    48  
    49  	return err
    50  }
    51  
    52  // MissingProviderTransformer is a GraphTransformer that adds nodes
    53  // for missing providers into the graph. Specifically, it creates provider
    54  // configuration nodes for all the providers that we support. These are
    55  // pruned later during an optimization pass.
    56  type MissingProviderTransformer struct {
    57  	// Providers is the list of providers we support.
    58  	Providers []string
    59  }
    60  
    61  func (t *MissingProviderTransformer) Transform(g *Graph) error {
    62  	m := providerVertexMap(g)
    63  	for _, p := range t.Providers {
    64  		if _, ok := m[p]; ok {
    65  			// This provider already exists as a configured node
    66  			continue
    67  		}
    68  
    69  		// Add our own missing provider node to the graph
    70  		g.Add(&graphNodeMissingProvider{ProviderNameValue: p})
    71  	}
    72  
    73  	return nil
    74  }
    75  
    76  // PruneProviderTransformer is a GraphTransformer that prunes all the
    77  // providers that aren't needed from the graph. A provider is unneeded if
    78  // no resource or module is using that provider.
    79  type PruneProviderTransformer struct{}
    80  
    81  func (t *PruneProviderTransformer) Transform(g *Graph) error {
    82  	for _, v := range g.Vertices() {
    83  		// We only care about the providers
    84  		if _, ok := v.(GraphNodeProvider); !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 graphNodeMissingProvider struct {
    98  	ProviderNameValue string
    99  }
   100  
   101  func (n *graphNodeMissingProvider) Name() string {
   102  	return fmt.Sprintf("provider.%s", n.ProviderNameValue)
   103  }
   104  
   105  // GraphNodeEvalable impl.
   106  func (n *graphNodeMissingProvider) EvalTree() EvalNode {
   107  	return ProviderEvalTree(n.ProviderNameValue, nil)
   108  }
   109  
   110  func (n *graphNodeMissingProvider) ProviderName() string {
   111  	return n.ProviderNameValue
   112  }
   113  
   114  // GraphNodeDotter impl.
   115  func (n *graphNodeMissingProvider) Dot(name string) string {
   116  	return fmt.Sprintf(
   117  		"\"%s\" [\n"+
   118  			"\tlabel=\"%s\"\n"+
   119  			"\tshape=diamond\n"+
   120  			"];",
   121  		name,
   122  		n.Name())
   123  }
   124  
   125  func providerVertexMap(g *Graph) map[string]dag.Vertex {
   126  	m := make(map[string]dag.Vertex)
   127  	for _, v := range g.Vertices() {
   128  		if pv, ok := v.(GraphNodeProvider); ok {
   129  			m[pv.ProviderName()] = v
   130  		}
   131  	}
   132  
   133  	return m
   134  }