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