github.com/r3labs/terraform@v0.8.4/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  )
    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  // ProviderTransformer is a GraphTransformer that maps resources to
    36  // providers within the graph. This will error if there are any resources
    37  // that don't map to proper resources.
    38  type ProviderTransformer struct{}
    39  
    40  func (t *ProviderTransformer) Transform(g *Graph) error {
    41  	// Go through the other nodes and match them to providers they need
    42  	var err error
    43  	m := providerVertexMap(g)
    44  	for _, v := range g.Vertices() {
    45  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
    46  			for _, p := range pv.ProvidedBy() {
    47  				target := m[providerMapKey(p, pv)]
    48  				if target == nil {
    49  					println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv)))
    50  					err = multierror.Append(err, fmt.Errorf(
    51  						"%s: provider %s couldn't be found",
    52  						dag.VertexName(v), p))
    53  					continue
    54  				}
    55  
    56  				g.Connect(dag.BasicEdge(v, target))
    57  			}
    58  		}
    59  	}
    60  
    61  	return err
    62  }
    63  
    64  // CloseProviderTransformer is a GraphTransformer that adds nodes to the
    65  // graph that will close open provider connections that aren't needed anymore.
    66  // A provider connection is not needed anymore once all depended resources
    67  // in the graph are evaluated.
    68  type CloseProviderTransformer struct{}
    69  
    70  func (t *CloseProviderTransformer) Transform(g *Graph) error {
    71  	pm := providerVertexMap(g)
    72  	cpm := closeProviderVertexMap(g)
    73  	var err error
    74  	for _, v := range g.Vertices() {
    75  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
    76  			for _, p := range pv.ProvidedBy() {
    77  				key := p
    78  				source := cpm[key]
    79  
    80  				if source == nil {
    81  					// Create a new graphNodeCloseProvider and add it to the graph
    82  					source = &graphNodeCloseProvider{ProviderNameValue: p}
    83  					g.Add(source)
    84  
    85  					// Close node needs to depend on provider
    86  					provider, ok := pm[key]
    87  					if !ok {
    88  						err = multierror.Append(err, fmt.Errorf(
    89  							"%s: provider %s couldn't be found for closing",
    90  							dag.VertexName(v), p))
    91  						continue
    92  					}
    93  					g.Connect(dag.BasicEdge(source, provider))
    94  
    95  					// Make sure we also add the new graphNodeCloseProvider to the map
    96  					// so we don't create and add any duplicate graphNodeCloseProviders.
    97  					cpm[key] = source
    98  				}
    99  
   100  				// Close node depends on all nodes provided by the provider
   101  				g.Connect(dag.BasicEdge(source, v))
   102  			}
   103  		}
   104  	}
   105  
   106  	return err
   107  }
   108  
   109  // MissingProviderTransformer is a GraphTransformer that adds nodes
   110  // for missing providers into the graph. Specifically, it creates provider
   111  // configuration nodes for all the providers that we support. These are
   112  // pruned later during an optimization pass.
   113  type MissingProviderTransformer struct {
   114  	// Providers is the list of providers we support.
   115  	Providers []string
   116  
   117  	// AllowAny will not check that a provider is supported before adding
   118  	// it to the graph.
   119  	AllowAny bool
   120  
   121  	// Concrete, if set, overrides how the providers are made.
   122  	Concrete ConcreteProviderNodeFunc
   123  }
   124  
   125  func (t *MissingProviderTransformer) Transform(g *Graph) error {
   126  	// Initialize factory
   127  	if t.Concrete == nil {
   128  		t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
   129  			return &graphNodeProvider{ProviderNameValue: a.NameValue}
   130  		}
   131  	}
   132  
   133  	// Create a set of our supported providers
   134  	supported := make(map[string]struct{}, len(t.Providers))
   135  	for _, v := range t.Providers {
   136  		supported[v] = struct{}{}
   137  	}
   138  
   139  	// Get the map of providers we already have in our graph
   140  	m := providerVertexMap(g)
   141  
   142  	// Go through all the provider consumers and make sure we add
   143  	// that provider if it is missing. We use a for loop here instead
   144  	// of "range" since we'll modify check as we go to add more to check.
   145  	check := g.Vertices()
   146  	for i := 0; i < len(check); i++ {
   147  		v := check[i]
   148  
   149  		pv, ok := v.(GraphNodeProviderConsumer)
   150  		if !ok {
   151  			continue
   152  		}
   153  
   154  		// If this node has a subpath, then we use that as a prefix
   155  		// into our map to check for an existing provider.
   156  		var path []string
   157  		if sp, ok := pv.(GraphNodeSubPath); ok {
   158  			raw := normalizeModulePath(sp.Path())
   159  			if len(raw) > len(rootModulePath) {
   160  				path = raw
   161  			}
   162  		}
   163  
   164  		for _, p := range pv.ProvidedBy() {
   165  			key := providerMapKey(p, pv)
   166  			if _, ok := m[key]; ok {
   167  				// This provider already exists as a configure node
   168  				continue
   169  			}
   170  
   171  			// If the provider has an alias in it, we just want the type
   172  			ptype := p
   173  			if idx := strings.IndexRune(p, '.'); idx != -1 {
   174  				ptype = p[:idx]
   175  			}
   176  
   177  			if !t.AllowAny {
   178  				if _, ok := supported[ptype]; !ok {
   179  					// If we don't support the provider type, skip it.
   180  					// Validation later will catch this as an error.
   181  					continue
   182  				}
   183  			}
   184  
   185  			// Add the missing provider node to the graph
   186  			v := t.Concrete(&NodeAbstractProvider{
   187  				NameValue: p,
   188  				PathValue: path,
   189  			}).(dag.Vertex)
   190  			if len(path) > 0 {
   191  				if fn, ok := v.(GraphNodeFlattenable); ok {
   192  					var err error
   193  					v, err = fn.Flatten(path)
   194  					if err != nil {
   195  						return err
   196  					}
   197  				}
   198  
   199  				// We'll need the parent provider as well, so let's
   200  				// add a dummy node to check to make sure that we add
   201  				// that parent provider.
   202  				check = append(check, &graphNodeProviderConsumerDummy{
   203  					ProviderValue: p,
   204  					PathValue:     path[:len(path)-1],
   205  				})
   206  			}
   207  
   208  			m[key] = g.Add(v)
   209  		}
   210  	}
   211  
   212  	return nil
   213  }
   214  
   215  // ParentProviderTransformer connects provider nodes to their parents.
   216  //
   217  // This works by finding nodes that are both GraphNodeProviders and
   218  // GraphNodeSubPath. It then connects the providers to their parent
   219  // path.
   220  type ParentProviderTransformer struct{}
   221  
   222  func (t *ParentProviderTransformer) Transform(g *Graph) error {
   223  	// Make a mapping of path to dag.Vertex, where path is: "path.name"
   224  	m := make(map[string]dag.Vertex)
   225  
   226  	// Also create a map that maps a provider to its parent
   227  	parentMap := make(map[dag.Vertex]string)
   228  	for _, raw := range g.Vertices() {
   229  		// If it is the flat version, then make it the non-flat version.
   230  		// We eventually want to get rid of the flat version entirely so
   231  		// this is a stop-gap while it still exists.
   232  		var v dag.Vertex = raw
   233  		if f, ok := v.(*graphNodeProviderFlat); ok {
   234  			v = f.graphNodeProvider
   235  		}
   236  
   237  		// Only care about providers
   238  		pn, ok := v.(GraphNodeProvider)
   239  		if !ok || pn.ProviderName() == "" {
   240  			continue
   241  		}
   242  
   243  		// Also require a subpath, if there is no subpath then we
   244  		// just totally ignore it. The expectation of this transform is
   245  		// that it is used with a graph builder that is already flattened.
   246  		var path []string
   247  		if pn, ok := raw.(GraphNodeSubPath); ok {
   248  			path = pn.Path()
   249  		}
   250  		path = normalizeModulePath(path)
   251  
   252  		// Build the key with path.name i.e. "child.subchild.aws"
   253  		key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
   254  		m[key] = raw
   255  
   256  		// Determine the parent if we're non-root. This is length 1 since
   257  		// the 0 index should be "root" since we normalize above.
   258  		if len(path) > 1 {
   259  			path = path[:len(path)-1]
   260  			key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName())
   261  			parentMap[raw] = key
   262  		}
   263  	}
   264  
   265  	// Connect!
   266  	for v, key := range parentMap {
   267  		if parent, ok := m[key]; ok {
   268  			g.Connect(dag.BasicEdge(v, parent))
   269  		}
   270  	}
   271  
   272  	return nil
   273  }
   274  
   275  // PruneProviderTransformer is a GraphTransformer that prunes all the
   276  // providers that aren't needed from the graph. A provider is unneeded if
   277  // no resource or module is using that provider.
   278  type PruneProviderTransformer struct{}
   279  
   280  func (t *PruneProviderTransformer) Transform(g *Graph) error {
   281  	for _, v := range g.Vertices() {
   282  		// We only care about the providers
   283  		if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" {
   284  			continue
   285  		}
   286  		// Does anything depend on this? If not, then prune it.
   287  		if s := g.UpEdges(v); s.Len() == 0 {
   288  			if nv, ok := v.(dag.NamedVertex); ok {
   289  				log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name())
   290  			}
   291  			g.Remove(v)
   292  		}
   293  	}
   294  
   295  	return nil
   296  }
   297  
   298  // providerMapKey is a helper that gives us the key to use for the
   299  // maps returned by things such as providerVertexMap.
   300  func providerMapKey(k string, v dag.Vertex) string {
   301  	pathPrefix := ""
   302  	if sp, ok := v.(GraphNodeSubPath); ok {
   303  		raw := normalizeModulePath(sp.Path())
   304  		if len(raw) > len(rootModulePath) {
   305  			pathPrefix = modulePrefixStr(raw) + "."
   306  		}
   307  	}
   308  
   309  	return pathPrefix + k
   310  }
   311  
   312  func providerVertexMap(g *Graph) map[string]dag.Vertex {
   313  	m := make(map[string]dag.Vertex)
   314  	for _, v := range g.Vertices() {
   315  		if pv, ok := v.(GraphNodeProvider); ok {
   316  			key := pv.ProviderName()
   317  
   318  			// This special case is because the new world view of providers
   319  			// is that they should return only their pure name (not the full
   320  			// module path with ProviderName). Working towards this future.
   321  			if _, ok := v.(*NodeApplyableProvider); ok {
   322  				key = providerMapKey(pv.ProviderName(), v)
   323  			}
   324  
   325  			m[key] = v
   326  		}
   327  	}
   328  
   329  	return m
   330  }
   331  
   332  func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
   333  	m := make(map[string]dag.Vertex)
   334  	for _, v := range g.Vertices() {
   335  		if pv, ok := v.(GraphNodeCloseProvider); ok {
   336  			m[pv.CloseProviderName()] = v
   337  		}
   338  	}
   339  
   340  	return m
   341  }
   342  
   343  type graphNodeCloseProvider struct {
   344  	ProviderNameValue string
   345  }
   346  
   347  func (n *graphNodeCloseProvider) Name() string {
   348  	return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue)
   349  }
   350  
   351  // GraphNodeEvalable impl.
   352  func (n *graphNodeCloseProvider) EvalTree() EvalNode {
   353  	return CloseProviderEvalTree(n.ProviderNameValue)
   354  }
   355  
   356  // GraphNodeDependable impl.
   357  func (n *graphNodeCloseProvider) DependableName() []string {
   358  	return []string{n.Name()}
   359  }
   360  
   361  func (n *graphNodeCloseProvider) CloseProviderName() string {
   362  	return n.ProviderNameValue
   363  }
   364  
   365  // GraphNodeDotter impl.
   366  func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   367  	if !opts.Verbose {
   368  		return nil
   369  	}
   370  	return &dag.DotNode{
   371  		Name: name,
   372  		Attrs: map[string]string{
   373  			"label": n.Name(),
   374  			"shape": "diamond",
   375  		},
   376  	}
   377  }
   378  
   379  type graphNodeProvider struct {
   380  	ProviderNameValue string
   381  }
   382  
   383  func (n *graphNodeProvider) Name() string {
   384  	return fmt.Sprintf("provider.%s", n.ProviderNameValue)
   385  }
   386  
   387  // GraphNodeEvalable impl.
   388  func (n *graphNodeProvider) EvalTree() EvalNode {
   389  	return ProviderEvalTree(n.ProviderNameValue, nil)
   390  }
   391  
   392  // GraphNodeDependable impl.
   393  func (n *graphNodeProvider) DependableName() []string {
   394  	return []string{n.Name()}
   395  }
   396  
   397  // GraphNodeProvider
   398  func (n *graphNodeProvider) ProviderName() string {
   399  	return n.ProviderNameValue
   400  }
   401  
   402  func (n *graphNodeProvider) ProviderConfig() *config.RawConfig {
   403  	return nil
   404  }
   405  
   406  // GraphNodeDotter impl.
   407  func (n *graphNodeProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   408  	return &dag.DotNode{
   409  		Name: name,
   410  		Attrs: map[string]string{
   411  			"label": n.Name(),
   412  			"shape": "diamond",
   413  		},
   414  	}
   415  }
   416  
   417  // GraphNodeDotterOrigin impl.
   418  func (n *graphNodeProvider) DotOrigin() bool {
   419  	return true
   420  }
   421  
   422  // GraphNodeFlattenable impl.
   423  func (n *graphNodeProvider) Flatten(p []string) (dag.Vertex, error) {
   424  	return &graphNodeProviderFlat{
   425  		graphNodeProvider: n,
   426  		PathValue:         p,
   427  	}, nil
   428  }
   429  
   430  // Same as graphNodeMissingProvider, but for flattening
   431  type graphNodeProviderFlat struct {
   432  	*graphNodeProvider
   433  
   434  	PathValue []string
   435  }
   436  
   437  func (n *graphNodeProviderFlat) Name() string {
   438  	return fmt.Sprintf(
   439  		"%s.%s", modulePrefixStr(n.PathValue), n.graphNodeProvider.Name())
   440  }
   441  
   442  func (n *graphNodeProviderFlat) Path() []string {
   443  	return n.PathValue
   444  }
   445  
   446  func (n *graphNodeProviderFlat) ProviderName() string {
   447  	return fmt.Sprintf(
   448  		"%s.%s", modulePrefixStr(n.PathValue),
   449  		n.graphNodeProvider.ProviderName())
   450  }
   451  
   452  // GraphNodeDependable impl.
   453  func (n *graphNodeProviderFlat) DependableName() []string {
   454  	return []string{n.Name()}
   455  }
   456  
   457  func (n *graphNodeProviderFlat) DependentOn() []string {
   458  	var result []string
   459  
   460  	// If we're in a module, then depend on all parent providers. Some of
   461  	// these may not exist, hence we depend on all of them.
   462  	for i := len(n.PathValue); i > 1; i-- {
   463  		prefix := modulePrefixStr(n.PathValue[:i-1])
   464  		result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix)
   465  	}
   466  
   467  	return result
   468  }
   469  
   470  // graphNodeProviderConsumerDummy is a struct that never enters the real
   471  // graph (though it could to no ill effect). It implements
   472  // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force
   473  // certain transformations.
   474  type graphNodeProviderConsumerDummy struct {
   475  	ProviderValue string
   476  	PathValue     []string
   477  }
   478  
   479  func (n *graphNodeProviderConsumerDummy) Path() []string {
   480  	return n.PathValue
   481  }
   482  
   483  func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string {
   484  	return []string{n.ProviderValue}
   485  }