github.com/anfernee/terraform@v0.6.16-0.20160430000239-06e5085a92f2/terraform/transform_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"strings"
     7  
     8  	"github.com/hashicorp/go-multierror"
     9  	"github.com/hashicorp/terraform/config"
    10  	"github.com/hashicorp/terraform/dag"
    11  	"github.com/hashicorp/terraform/dot"
    12  )
    13  
    14  // GraphNodeProvider is an interface that nodes that can be a provider
    15  // must implement. The ProviderName returned is the name of the provider
    16  // they satisfy.
    17  type GraphNodeProvider interface {
    18  	ProviderName() string
    19  	ProviderConfig() *config.RawConfig
    20  }
    21  
    22  // GraphNodeCloseProvider is an interface that nodes that can be a close
    23  // provider must implement. The CloseProviderName returned is the name of
    24  // the provider they satisfy.
    25  type GraphNodeCloseProvider interface {
    26  	CloseProviderName() string
    27  }
    28  
    29  // GraphNodeProviderConsumer is an interface that nodes that require
    30  // a provider must implement. ProvidedBy must return the name of the provider
    31  // to use.
    32  type GraphNodeProviderConsumer interface {
    33  	ProvidedBy() []string
    34  }
    35  
    36  // DisableProviderTransformer "disables" any providers that are only
    37  // depended on by modules.
    38  type DisableProviderTransformer struct{}
    39  
    40  func (t *DisableProviderTransformer) Transform(g *Graph) error {
    41  	for _, v := range g.Vertices() {
    42  		// We only care about providers
    43  		pn, ok := v.(GraphNodeProvider)
    44  		if !ok || pn.ProviderName() == "" {
    45  			continue
    46  		}
    47  
    48  		// Go through all the up-edges (things that depend on this
    49  		// provider) and if any is not a module, then ignore this node.
    50  		nonModule := false
    51  		for _, sourceRaw := range g.UpEdges(v).List() {
    52  			source := sourceRaw.(dag.Vertex)
    53  			cn, ok := source.(graphNodeConfig)
    54  			if !ok {
    55  				nonModule = true
    56  				break
    57  			}
    58  
    59  			if cn.ConfigType() != GraphNodeConfigTypeModule {
    60  				nonModule = true
    61  				break
    62  			}
    63  		}
    64  		if nonModule {
    65  			// We found something that depends on this provider that
    66  			// isn't a module, so skip it.
    67  			continue
    68  		}
    69  
    70  		// Disable the provider by replacing it with a "disabled" provider
    71  		disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn}
    72  		if !g.Replace(v, disabled) {
    73  			panic(fmt.Sprintf(
    74  				"vertex disappeared from under us: %s",
    75  				dag.VertexName(v)))
    76  		}
    77  	}
    78  
    79  	return nil
    80  }
    81  
    82  // ProviderTransformer is a GraphTransformer that maps resources to
    83  // providers within the graph. This will error if there are any resources
    84  // that don't map to proper resources.
    85  type ProviderTransformer struct{}
    86  
    87  func (t *ProviderTransformer) Transform(g *Graph) error {
    88  	// Go through the other nodes and match them to providers they need
    89  	var err error
    90  	m := providerVertexMap(g)
    91  	for _, v := range g.Vertices() {
    92  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
    93  			for _, p := range pv.ProvidedBy() {
    94  				target := m[p]
    95  				if target == nil {
    96  					err = multierror.Append(err, fmt.Errorf(
    97  						"%s: provider %s couldn't be found",
    98  						dag.VertexName(v), p))
    99  					continue
   100  				}
   101  
   102  				g.Connect(dag.BasicEdge(v, target))
   103  			}
   104  		}
   105  	}
   106  
   107  	return err
   108  }
   109  
   110  // CloseProviderTransformer is a GraphTransformer that adds nodes to the
   111  // graph that will close open provider connections that aren't needed anymore.
   112  // A provider connection is not needed anymore once all depended resources
   113  // in the graph are evaluated.
   114  type CloseProviderTransformer struct{}
   115  
   116  func (t *CloseProviderTransformer) Transform(g *Graph) error {
   117  	pm := providerVertexMap(g)
   118  	cpm := closeProviderVertexMap(g)
   119  	var err error
   120  	for _, v := range g.Vertices() {
   121  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
   122  			for _, p := range pv.ProvidedBy() {
   123  				source := cpm[p]
   124  
   125  				if source == nil {
   126  					// Create a new graphNodeCloseProvider and add it to the graph
   127  					source = &graphNodeCloseProvider{ProviderNameValue: p}
   128  					g.Add(source)
   129  
   130  					// Close node needs to depend on provider
   131  					provider, ok := pm[p]
   132  					if !ok {
   133  						err = multierror.Append(err, fmt.Errorf(
   134  							"%s: provider %s couldn't be found for closing",
   135  							dag.VertexName(v), p))
   136  						continue
   137  					}
   138  					g.Connect(dag.BasicEdge(source, provider))
   139  
   140  					// Make sure we also add the new graphNodeCloseProvider to the map
   141  					// so we don't create and add any duplicate graphNodeCloseProviders.
   142  					cpm[p] = source
   143  				}
   144  
   145  				// Close node depends on all nodes provided by the provider
   146  				g.Connect(dag.BasicEdge(source, v))
   147  			}
   148  		}
   149  	}
   150  
   151  	return err
   152  }
   153  
   154  // MissingProviderTransformer is a GraphTransformer that adds nodes
   155  // for missing providers into the graph. Specifically, it creates provider
   156  // configuration nodes for all the providers that we support. These are
   157  // pruned later during an optimization pass.
   158  type MissingProviderTransformer struct {
   159  	// Providers is the list of providers we support.
   160  	Providers []string
   161  }
   162  
   163  func (t *MissingProviderTransformer) Transform(g *Graph) error {
   164  	// Create a set of our supported providers
   165  	supported := make(map[string]struct{}, len(t.Providers))
   166  	for _, v := range t.Providers {
   167  		supported[v] = struct{}{}
   168  	}
   169  
   170  	// Get the map of providers we already have in our graph
   171  	m := providerVertexMap(g)
   172  
   173  	// Go through all the provider consumers and make sure we add
   174  	// that provider if it is missing.
   175  	for _, v := range g.Vertices() {
   176  		pv, ok := v.(GraphNodeProviderConsumer)
   177  		if !ok {
   178  			continue
   179  		}
   180  
   181  		for _, p := range pv.ProvidedBy() {
   182  			if _, ok := m[p]; ok {
   183  				// This provider already exists as a configure node
   184  				continue
   185  			}
   186  
   187  			// If the provider has an alias in it, we just want the type
   188  			ptype := p
   189  			if idx := strings.IndexRune(p, '.'); idx != -1 {
   190  				ptype = p[:idx]
   191  			}
   192  
   193  			if _, ok := supported[ptype]; !ok {
   194  				// If we don't support the provider type, skip it.
   195  				// Validation later will catch this as an error.
   196  				continue
   197  			}
   198  
   199  			// Add the missing provider node to the graph
   200  			m[p] = g.Add(&graphNodeProvider{ProviderNameValue: p})
   201  		}
   202  	}
   203  
   204  	return nil
   205  }
   206  
   207  // PruneProviderTransformer is a GraphTransformer that prunes all the
   208  // providers that aren't needed from the graph. A provider is unneeded if
   209  // no resource or module is using that provider.
   210  type PruneProviderTransformer struct{}
   211  
   212  func (t *PruneProviderTransformer) Transform(g *Graph) error {
   213  	for _, v := range g.Vertices() {
   214  		// We only care about the providers
   215  		if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" {
   216  			continue
   217  		}
   218  		// Does anything depend on this? If not, then prune it.
   219  		if s := g.UpEdges(v); s.Len() == 0 {
   220  			if nv, ok := v.(dag.NamedVertex); ok {
   221  				log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name())
   222  			}
   223  			g.Remove(v)
   224  		}
   225  	}
   226  
   227  	return nil
   228  }
   229  
   230  func providerVertexMap(g *Graph) map[string]dag.Vertex {
   231  	m := make(map[string]dag.Vertex)
   232  	for _, v := range g.Vertices() {
   233  		if pv, ok := v.(GraphNodeProvider); ok {
   234  			m[pv.ProviderName()] = v
   235  		}
   236  	}
   237  
   238  	return m
   239  }
   240  
   241  func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
   242  	m := make(map[string]dag.Vertex)
   243  	for _, v := range g.Vertices() {
   244  		if pv, ok := v.(GraphNodeCloseProvider); ok {
   245  			m[pv.CloseProviderName()] = v
   246  		}
   247  	}
   248  
   249  	return m
   250  }
   251  
   252  type graphNodeDisabledProvider struct {
   253  	GraphNodeProvider
   254  }
   255  
   256  // GraphNodeEvalable impl.
   257  func (n *graphNodeDisabledProvider) EvalTree() EvalNode {
   258  	var resourceConfig *ResourceConfig
   259  
   260  	return &EvalOpFilter{
   261  		Ops: []walkOperation{walkInput, walkValidate, walkRefresh, walkPlan, walkApply, walkDestroy},
   262  		Node: &EvalSequence{
   263  			Nodes: []EvalNode{
   264  				&EvalInterpolate{
   265  					Config: n.ProviderConfig(),
   266  					Output: &resourceConfig,
   267  				},
   268  				&EvalBuildProviderConfig{
   269  					Provider: n.ProviderName(),
   270  					Config:   &resourceConfig,
   271  					Output:   &resourceConfig,
   272  				},
   273  				&EvalSetProviderConfig{
   274  					Provider: n.ProviderName(),
   275  					Config:   &resourceConfig,
   276  				},
   277  			},
   278  		},
   279  	}
   280  }
   281  
   282  // GraphNodeFlattenable impl.
   283  func (n *graphNodeDisabledProvider) Flatten(p []string) (dag.Vertex, error) {
   284  	return &graphNodeDisabledProviderFlat{
   285  		graphNodeDisabledProvider: n,
   286  		PathValue:                 p,
   287  	}, nil
   288  }
   289  
   290  func (n *graphNodeDisabledProvider) Name() string {
   291  	return fmt.Sprintf("%s (disabled)", dag.VertexName(n.GraphNodeProvider))
   292  }
   293  
   294  // GraphNodeDotter impl.
   295  func (n *graphNodeDisabledProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node {
   296  	return dot.NewNode(name, map[string]string{
   297  		"label": n.Name(),
   298  		"shape": "diamond",
   299  	})
   300  }
   301  
   302  // GraphNodeDotterOrigin impl.
   303  func (n *graphNodeDisabledProvider) DotOrigin() bool {
   304  	return true
   305  }
   306  
   307  // GraphNodeDependable impl.
   308  func (n *graphNodeDisabledProvider) DependableName() []string {
   309  	return []string{"provider." + n.ProviderName()}
   310  }
   311  
   312  // GraphNodeProvider impl.
   313  func (n *graphNodeDisabledProvider) ProviderName() string {
   314  	return n.GraphNodeProvider.ProviderName()
   315  }
   316  
   317  // GraphNodeProvider impl.
   318  func (n *graphNodeDisabledProvider) ProviderConfig() *config.RawConfig {
   319  	return n.GraphNodeProvider.ProviderConfig()
   320  }
   321  
   322  // Same as graphNodeDisabledProvider, but for flattening
   323  type graphNodeDisabledProviderFlat struct {
   324  	*graphNodeDisabledProvider
   325  
   326  	PathValue []string
   327  }
   328  
   329  func (n *graphNodeDisabledProviderFlat) Name() string {
   330  	return fmt.Sprintf(
   331  		"%s.%s", modulePrefixStr(n.PathValue), n.graphNodeDisabledProvider.Name())
   332  }
   333  
   334  func (n *graphNodeDisabledProviderFlat) Path() []string {
   335  	return n.PathValue
   336  }
   337  
   338  func (n *graphNodeDisabledProviderFlat) ProviderName() string {
   339  	return fmt.Sprintf(
   340  		"%s.%s", modulePrefixStr(n.PathValue),
   341  		n.graphNodeDisabledProvider.ProviderName())
   342  }
   343  
   344  // GraphNodeDependable impl.
   345  func (n *graphNodeDisabledProviderFlat) DependableName() []string {
   346  	return modulePrefixList(
   347  		n.graphNodeDisabledProvider.DependableName(),
   348  		modulePrefixStr(n.PathValue))
   349  }
   350  
   351  func (n *graphNodeDisabledProviderFlat) DependentOn() []string {
   352  	var result []string
   353  
   354  	// If we're in a module, then depend on our parent's provider
   355  	if len(n.PathValue) > 1 {
   356  		prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1])
   357  		result = modulePrefixList(
   358  			n.graphNodeDisabledProvider.DependableName(), prefix)
   359  	}
   360  
   361  	return result
   362  }
   363  
   364  type graphNodeCloseProvider struct {
   365  	ProviderNameValue string
   366  }
   367  
   368  func (n *graphNodeCloseProvider) Name() string {
   369  	return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue)
   370  }
   371  
   372  // GraphNodeEvalable impl.
   373  func (n *graphNodeCloseProvider) EvalTree() EvalNode {
   374  	return CloseProviderEvalTree(n.ProviderNameValue)
   375  }
   376  
   377  // GraphNodeDependable impl.
   378  func (n *graphNodeCloseProvider) DependableName() []string {
   379  	return []string{n.Name()}
   380  }
   381  
   382  func (n *graphNodeCloseProvider) CloseProviderName() string {
   383  	return n.ProviderNameValue
   384  }
   385  
   386  // GraphNodeDotter impl.
   387  func (n *graphNodeCloseProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node {
   388  	if !opts.Verbose {
   389  		return nil
   390  	}
   391  	return dot.NewNode(name, map[string]string{
   392  		"label": n.Name(),
   393  		"shape": "diamond",
   394  	})
   395  }
   396  
   397  type graphNodeProvider struct {
   398  	ProviderNameValue string
   399  }
   400  
   401  func (n *graphNodeProvider) Name() string {
   402  	return fmt.Sprintf("provider.%s", n.ProviderNameValue)
   403  }
   404  
   405  // GraphNodeEvalable impl.
   406  func (n *graphNodeProvider) EvalTree() EvalNode {
   407  	return ProviderEvalTree(n.ProviderNameValue, nil)
   408  }
   409  
   410  // GraphNodeDependable impl.
   411  func (n *graphNodeProvider) DependableName() []string {
   412  	return []string{n.Name()}
   413  }
   414  
   415  func (n *graphNodeProvider) ProviderName() string {
   416  	return n.ProviderNameValue
   417  }
   418  
   419  func (n *graphNodeProvider) ProviderConfig() *config.RawConfig {
   420  	return nil
   421  }
   422  
   423  // GraphNodeDotter impl.
   424  func (n *graphNodeProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node {
   425  	return dot.NewNode(name, map[string]string{
   426  		"label": n.Name(),
   427  		"shape": "diamond",
   428  	})
   429  }
   430  
   431  // GraphNodeDotterOrigin impl.
   432  func (n *graphNodeProvider) DotOrigin() bool {
   433  	return true
   434  }
   435  
   436  // GraphNodeFlattenable impl.
   437  func (n *graphNodeProvider) Flatten(p []string) (dag.Vertex, error) {
   438  	return &graphNodeProviderFlat{
   439  		graphNodeProvider: n,
   440  		PathValue:         p,
   441  	}, nil
   442  }
   443  
   444  // Same as graphNodeMissingProvider, but for flattening
   445  type graphNodeProviderFlat struct {
   446  	*graphNodeProvider
   447  
   448  	PathValue []string
   449  }
   450  
   451  func (n *graphNodeProviderFlat) Name() string {
   452  	return fmt.Sprintf(
   453  		"%s.%s", modulePrefixStr(n.PathValue), n.graphNodeProvider.Name())
   454  }
   455  
   456  func (n *graphNodeProviderFlat) Path() []string {
   457  	return n.PathValue
   458  }
   459  
   460  func (n *graphNodeProviderFlat) ProviderName() string {
   461  	return fmt.Sprintf(
   462  		"%s.%s", modulePrefixStr(n.PathValue),
   463  		n.graphNodeProvider.ProviderName())
   464  }
   465  
   466  // GraphNodeDependable impl.
   467  func (n *graphNodeProviderFlat) DependableName() []string {
   468  	return []string{n.Name()}
   469  }
   470  
   471  func (n *graphNodeProviderFlat) DependentOn() []string {
   472  	var result []string
   473  
   474  	// If we're in a module, then depend on our parent's provider
   475  	if len(n.PathValue) > 1 {
   476  		prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1])
   477  		result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix)
   478  	}
   479  
   480  	return result
   481  }