github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/transform_provider.go (about)

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