github.com/medzin/terraform@v0.11.11/terraform/transform_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"log"
     7  	"strings"
     8  
     9  	"github.com/hashicorp/go-multierror"
    10  	"github.com/hashicorp/terraform/config"
    11  	"github.com/hashicorp/terraform/config/module"
    12  	"github.com/hashicorp/terraform/dag"
    13  )
    14  
    15  func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, mod *module.Tree) GraphTransformer {
    16  	return GraphTransformMulti(
    17  		// Add providers from the config
    18  		&ProviderConfigTransformer{
    19  			Module:    mod,
    20  			Providers: providers,
    21  			Concrete:  concrete,
    22  		},
    23  		// Add any remaining missing providers
    24  		&MissingProviderTransformer{
    25  			Providers: providers,
    26  			Concrete:  concrete,
    27  		},
    28  		// Connect the providers
    29  		&ProviderTransformer{},
    30  		// Remove unused providers and proxies
    31  		&PruneProviderTransformer{},
    32  		// Connect provider to their parent provider nodes
    33  		&ParentProviderTransformer{},
    34  	)
    35  }
    36  
    37  // GraphNodeProvider is an interface that nodes that can be a provider
    38  // must implement.
    39  // ProviderName returns the name of the provider this satisfies.
    40  // Name returns the full name of the provider in the config.
    41  type GraphNodeProvider interface {
    42  	ProviderName() string
    43  	Name() string
    44  }
    45  
    46  // GraphNodeCloseProvider is an interface that nodes that can be a close
    47  // provider must implement. The CloseProviderName returned is the name of
    48  // the provider they satisfy.
    49  type GraphNodeCloseProvider interface {
    50  	CloseProviderName() string
    51  }
    52  
    53  // GraphNodeProviderConsumer is an interface that nodes that require
    54  // a provider must implement. ProvidedBy must return the name of the provider
    55  // to use. This may be a provider by type, type.alias or a fully resolved
    56  // provider name
    57  type GraphNodeProviderConsumer interface {
    58  	ProvidedBy() string
    59  	// Set the resolved provider address for this resource.
    60  	SetProvider(string)
    61  }
    62  
    63  // ProviderTransformer is a GraphTransformer that maps resources to
    64  // providers within the graph. This will error if there are any resources
    65  // that don't map to proper resources.
    66  type ProviderTransformer struct{}
    67  
    68  func (t *ProviderTransformer) Transform(g *Graph) error {
    69  	// Go through the other nodes and match them to providers they need
    70  	var err error
    71  	m := providerVertexMap(g)
    72  	for _, v := range g.Vertices() {
    73  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
    74  			p := pv.ProvidedBy()
    75  
    76  			key := providerMapKey(p, pv)
    77  			target := m[key]
    78  
    79  			sp, ok := pv.(GraphNodeSubPath)
    80  			if !ok && target == nil {
    81  				// no target, and no path to walk up
    82  				err = multierror.Append(err, fmt.Errorf(
    83  					"%s: provider %s couldn't be found",
    84  					dag.VertexName(v), p))
    85  				break
    86  			}
    87  
    88  			// if we don't have a provider at this level, walk up the path looking for one
    89  			for i := 1; target == nil; i++ {
    90  				path := normalizeModulePath(sp.Path())
    91  				if len(path) < i {
    92  					break
    93  				}
    94  
    95  				key = ResolveProviderName(p, path[:len(path)-i])
    96  				target = m[key]
    97  				if target != nil {
    98  					break
    99  				}
   100  			}
   101  
   102  			if target == nil {
   103  				err = multierror.Append(err, fmt.Errorf(
   104  					"%s: configuration for %s is not present; a provider configuration block is required for all operations",
   105  					dag.VertexName(v), p,
   106  				))
   107  				break
   108  			}
   109  
   110  			// see if this in  an inherited provider
   111  			if p, ok := target.(*graphNodeProxyProvider); ok {
   112  				g.Remove(p)
   113  				target = p.Target()
   114  				key = target.(GraphNodeProvider).Name()
   115  			}
   116  
   117  			log.Printf("[DEBUG] resource %s using provider %s", dag.VertexName(pv), key)
   118  			pv.SetProvider(key)
   119  			g.Connect(dag.BasicEdge(v, target))
   120  		}
   121  	}
   122  
   123  	return err
   124  }
   125  
   126  // CloseProviderTransformer is a GraphTransformer that adds nodes to the
   127  // graph that will close open provider connections that aren't needed anymore.
   128  // A provider connection is not needed anymore once all depended resources
   129  // in the graph are evaluated.
   130  type CloseProviderTransformer struct{}
   131  
   132  func (t *CloseProviderTransformer) Transform(g *Graph) error {
   133  	pm := providerVertexMap(g)
   134  	cpm := make(map[string]*graphNodeCloseProvider)
   135  	var err error
   136  
   137  	for _, v := range pm {
   138  		p := v.(GraphNodeProvider)
   139  
   140  		// get the close provider of this type if we alread created it
   141  		closer := cpm[p.Name()]
   142  
   143  		if closer == nil {
   144  			// create a closer for this provider type
   145  			closer = &graphNodeCloseProvider{ProviderNameValue: p.Name()}
   146  			g.Add(closer)
   147  			cpm[p.Name()] = closer
   148  		}
   149  
   150  		// Close node depends on the provider itself
   151  		// this is added unconditionally, so it will connect to all instances
   152  		// of the provider. Extra edges will be removed by transitive
   153  		// reduction.
   154  		g.Connect(dag.BasicEdge(closer, p))
   155  
   156  		// connect all the provider's resources to the close node
   157  		for _, s := range g.UpEdges(p).List() {
   158  			if _, ok := s.(GraphNodeProviderConsumer); ok {
   159  				g.Connect(dag.BasicEdge(closer, s))
   160  			}
   161  		}
   162  	}
   163  
   164  	return err
   165  }
   166  
   167  // MissingProviderTransformer is a GraphTransformer that adds nodes for all
   168  // required providers into the graph. Specifically, it creates provider
   169  // configuration nodes for all the providers that we support. These are pruned
   170  // later during an optimization pass.
   171  type MissingProviderTransformer struct {
   172  	// Providers is the list of providers we support.
   173  	Providers []string
   174  
   175  	// Concrete, if set, overrides how the providers are made.
   176  	Concrete ConcreteProviderNodeFunc
   177  }
   178  
   179  func (t *MissingProviderTransformer) Transform(g *Graph) error {
   180  	// Initialize factory
   181  	if t.Concrete == nil {
   182  		t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
   183  			return a
   184  		}
   185  	}
   186  
   187  	var err error
   188  	m := providerVertexMap(g)
   189  	for _, v := range g.Vertices() {
   190  		pv, ok := v.(GraphNodeProviderConsumer)
   191  		if !ok {
   192  			continue
   193  		}
   194  
   195  		p := pv.ProvidedBy()
   196  		// this may be the resolved provider from the state, so we need to get
   197  		// the base provider name.
   198  		parts := strings.SplitAfter(p, "provider.")
   199  		p = parts[len(parts)-1]
   200  
   201  		key := ResolveProviderName(p, nil)
   202  		provider := m[key]
   203  
   204  		// we already have it
   205  		if provider != nil {
   206  			continue
   207  		}
   208  
   209  		// we don't implicitly create aliased providers
   210  		if strings.Contains(p, ".") {
   211  			log.Println("[DEBUG] not adding missing provider alias:", p)
   212  			continue
   213  		}
   214  
   215  		log.Println("[DEBUG] adding missing provider:", p)
   216  
   217  		// create the misisng top-level provider
   218  		provider = t.Concrete(&NodeAbstractProvider{
   219  			NameValue: p,
   220  		}).(dag.Vertex)
   221  
   222  		m[key] = g.Add(provider)
   223  	}
   224  
   225  	return err
   226  }
   227  
   228  // ParentProviderTransformer connects provider nodes to their parents.
   229  //
   230  // This works by finding nodes that are both GraphNodeProviders and
   231  // GraphNodeSubPath. It then connects the providers to their parent
   232  // path. The parent provider is always at the root level.
   233  type ParentProviderTransformer struct{}
   234  
   235  func (t *ParentProviderTransformer) Transform(g *Graph) error {
   236  	pm := providerVertexMap(g)
   237  	for _, v := range g.Vertices() {
   238  		// Only care about providers
   239  		pn, ok := v.(GraphNodeProvider)
   240  		if !ok || pn.ProviderName() == "" {
   241  			continue
   242  		}
   243  
   244  		// Also require a subpath, if there is no subpath then we
   245  		// can't have a parent.
   246  		if pn, ok := v.(GraphNodeSubPath); ok {
   247  			if len(normalizeModulePath(pn.Path())) <= 1 {
   248  				continue
   249  			}
   250  		}
   251  
   252  		// this provider may be disabled, but we can only get it's name from
   253  		// the ProviderName string
   254  		name := ResolveProviderName(strings.SplitN(pn.ProviderName(), " ", 2)[0], nil)
   255  		parent := pm[name]
   256  		if parent != nil {
   257  			g.Connect(dag.BasicEdge(v, parent))
   258  		}
   259  
   260  	}
   261  	return nil
   262  }
   263  
   264  // PruneProviderTransformer removes any providers that are not actually used by
   265  // anything, and provider proxies. This avoids the provider being initialized
   266  // and configured.  This both saves resources but also avoids errors since
   267  // configuration may imply initialization which may require auth.
   268  type PruneProviderTransformer struct{}
   269  
   270  func (t *PruneProviderTransformer) Transform(g *Graph) error {
   271  	for _, v := range g.Vertices() {
   272  		// We only care about providers
   273  		pn, ok := v.(GraphNodeProvider)
   274  		if !ok || pn.ProviderName() == "" {
   275  			continue
   276  		}
   277  
   278  		// ProxyProviders will have up edges, but we're now done with them in the graph
   279  		if _, ok := v.(*graphNodeProxyProvider); ok {
   280  			log.Printf("[DEBUG] pruning proxy provider %s", dag.VertexName(v))
   281  			g.Remove(v)
   282  		}
   283  
   284  		// Remove providers with no dependencies.
   285  		if g.UpEdges(v).Len() == 0 {
   286  			log.Printf("[DEBUG] pruning unused provider %s", dag.VertexName(v))
   287  			g.Remove(v)
   288  		}
   289  	}
   290  
   291  	return nil
   292  }
   293  
   294  // providerMapKey is a helper that gives us the key to use for the
   295  // maps returned by things such as providerVertexMap.
   296  func providerMapKey(k string, v dag.Vertex) string {
   297  	if strings.Contains(k, "provider.") {
   298  		// this is already resolved
   299  		return k
   300  	}
   301  
   302  	// we create a dummy provider to
   303  	var path []string
   304  	if sp, ok := v.(GraphNodeSubPath); ok {
   305  		path = normalizeModulePath(sp.Path())
   306  	}
   307  	return ResolveProviderName(k, path)
   308  }
   309  
   310  func providerVertexMap(g *Graph) map[string]dag.Vertex {
   311  	m := make(map[string]dag.Vertex)
   312  	for _, v := range g.Vertices() {
   313  		if pv, ok := v.(GraphNodeProvider); ok {
   314  			// TODO:  The Name may have meta info, like " (disabled)"
   315  			name := strings.SplitN(pv.Name(), " ", 2)[0]
   316  			m[name] = v
   317  		}
   318  	}
   319  
   320  	return m
   321  }
   322  
   323  func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
   324  	m := make(map[string]dag.Vertex)
   325  	for _, v := range g.Vertices() {
   326  		if pv, ok := v.(GraphNodeCloseProvider); ok {
   327  			m[pv.CloseProviderName()] = v
   328  		}
   329  	}
   330  
   331  	return m
   332  }
   333  
   334  type graphNodeCloseProvider struct {
   335  	ProviderNameValue string
   336  }
   337  
   338  func (n *graphNodeCloseProvider) Name() string {
   339  	return n.ProviderNameValue + " (close)"
   340  }
   341  
   342  // GraphNodeEvalable impl.
   343  func (n *graphNodeCloseProvider) EvalTree() EvalNode {
   344  	return CloseProviderEvalTree(n.ProviderNameValue)
   345  }
   346  
   347  // GraphNodeDependable impl.
   348  func (n *graphNodeCloseProvider) DependableName() []string {
   349  	return []string{n.Name()}
   350  }
   351  
   352  func (n *graphNodeCloseProvider) CloseProviderName() string {
   353  	return n.ProviderNameValue
   354  }
   355  
   356  // GraphNodeDotter impl.
   357  func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   358  	if !opts.Verbose {
   359  		return nil
   360  	}
   361  	return &dag.DotNode{
   362  		Name: name,
   363  		Attrs: map[string]string{
   364  			"label": n.Name(),
   365  			"shape": "diamond",
   366  		},
   367  	}
   368  }
   369  
   370  // RemovableIfNotTargeted
   371  func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
   372  	// We need to add this so that this node will be removed if
   373  	// it isn't targeted or a dependency of a target.
   374  	return true
   375  }
   376  
   377  // graphNodeProxyProvider is a GraphNodeProvider implementation that is used to
   378  // store the name and value of a provider node for inheritance between modules.
   379  // These nodes are only used to store the data while loading the provider
   380  // configurations, and are removed after all the resources have been connected
   381  // to their providers.
   382  type graphNodeProxyProvider struct {
   383  	nameValue string
   384  	path      []string
   385  	target    GraphNodeProvider
   386  }
   387  
   388  func (n *graphNodeProxyProvider) ProviderName() string {
   389  	return n.Target().ProviderName()
   390  }
   391  
   392  func (n *graphNodeProxyProvider) Name() string {
   393  	return ResolveProviderName(n.nameValue, n.path)
   394  }
   395  
   396  // find the concrete provider instance
   397  func (n *graphNodeProxyProvider) Target() GraphNodeProvider {
   398  	switch t := n.target.(type) {
   399  	case *graphNodeProxyProvider:
   400  		return t.Target()
   401  	default:
   402  		return n.target
   403  	}
   404  }
   405  
   406  // ProviderConfigTransformer adds all provider nodes from the configuration and
   407  // attaches the configs.
   408  type ProviderConfigTransformer struct {
   409  	Providers []string
   410  	Concrete  ConcreteProviderNodeFunc
   411  
   412  	// each provider node is stored here so that the proxy nodes can look up
   413  	// their targets by name.
   414  	providers map[string]GraphNodeProvider
   415  	// record providers that can be overriden with a proxy
   416  	proxiable map[string]bool
   417  
   418  	// Module is the module to add resources from.
   419  	Module *module.Tree
   420  }
   421  
   422  func (t *ProviderConfigTransformer) Transform(g *Graph) error {
   423  	// If no module is given, we don't do anything
   424  	if t.Module == nil {
   425  		return nil
   426  	}
   427  
   428  	// If the module isn't loaded, that is simply an error
   429  	if !t.Module.Loaded() {
   430  		return errors.New("module must be loaded for ProviderConfigTransformer")
   431  	}
   432  
   433  	t.providers = make(map[string]GraphNodeProvider)
   434  	t.proxiable = make(map[string]bool)
   435  
   436  	// Start the transformation process
   437  	if err := t.transform(g, t.Module); err != nil {
   438  		return err
   439  	}
   440  
   441  	// finally attach the configs to the new nodes
   442  	return t.attachProviderConfigs(g)
   443  }
   444  
   445  func (t *ProviderConfigTransformer) transform(g *Graph, m *module.Tree) error {
   446  	// If no config, do nothing
   447  	if m == nil {
   448  		return nil
   449  	}
   450  
   451  	// Add our resources
   452  	if err := t.transformSingle(g, m); err != nil {
   453  		return err
   454  	}
   455  
   456  	// Transform all the children.
   457  	for _, c := range m.Children() {
   458  		if err := t.transform(g, c); err != nil {
   459  			return err
   460  		}
   461  	}
   462  	return nil
   463  }
   464  
   465  func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) error {
   466  	log.Printf("[TRACE] ProviderConfigTransformer: Starting for path: %v", m.Path())
   467  
   468  	// Get the configuration for this module
   469  	conf := m.Config()
   470  
   471  	// Build the path we're at
   472  	path := m.Path()
   473  	if len(path) > 0 {
   474  		path = append([]string{RootModuleName}, path...)
   475  	}
   476  
   477  	// add all providers from the configuration
   478  	for _, p := range conf.ProviderConfigs {
   479  		name := p.Name
   480  		if p.Alias != "" {
   481  			name += "." + p.Alias
   482  		}
   483  
   484  		v := t.Concrete(&NodeAbstractProvider{
   485  			NameValue: name,
   486  			PathValue: path,
   487  		})
   488  
   489  		// Add it to the graph
   490  		g.Add(v)
   491  		fullName := ResolveProviderName(name, path)
   492  		t.providers[fullName] = v.(GraphNodeProvider)
   493  		t.proxiable[fullName] = len(p.RawConfig.RawMap()) == 0
   494  	}
   495  
   496  	// Now replace the provider nodes with proxy nodes if a provider was being
   497  	// passed in, and create implicit proxies if there was no config. Any extra
   498  	// proxies will be removed in the prune step.
   499  	return t.addProxyProviders(g, m)
   500  }
   501  
   502  func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, m *module.Tree) error {
   503  	path := m.Path()
   504  
   505  	// can't add proxies at the root
   506  	if len(path) == 0 {
   507  		return nil
   508  	}
   509  
   510  	parentPath := path[:len(path)-1]
   511  	parent := t.Module.Child(parentPath)
   512  	if parent == nil {
   513  		return nil
   514  	}
   515  
   516  	var parentCfg *config.Module
   517  	for _, mod := range parent.Config().Modules {
   518  		if mod.Name == m.Name() {
   519  			parentCfg = mod
   520  			break
   521  		}
   522  	}
   523  
   524  	if parentCfg == nil {
   525  		// this can't really happen during normal execution.
   526  		return fmt.Errorf("parent module config not found for %s", m.Name())
   527  	}
   528  
   529  	// Go through all the providers the parent is passing in, and add proxies to
   530  	// the parent provider nodes.
   531  	for name, parentName := range parentCfg.Providers {
   532  		fullName := ResolveProviderName(name, path)
   533  		fullParentName := ResolveProviderName(parentName, parentPath)
   534  
   535  		parentProvider := t.providers[fullParentName]
   536  
   537  		if parentProvider == nil {
   538  			return fmt.Errorf("missing provider %s", fullParentName)
   539  		}
   540  
   541  		proxy := &graphNodeProxyProvider{
   542  			nameValue: name,
   543  			path:      path,
   544  			target:    parentProvider,
   545  		}
   546  
   547  		concreteProvider := t.providers[fullName]
   548  
   549  		// replace the concrete node with the provider passed in
   550  		if concreteProvider != nil && t.proxiable[fullName] {
   551  			g.Replace(concreteProvider, proxy)
   552  			t.providers[fullName] = proxy
   553  			continue
   554  		}
   555  
   556  		// aliased providers can't be implicitly passed in
   557  		if strings.Contains(name, ".") {
   558  			continue
   559  		}
   560  
   561  		// There was no concrete provider, so add this as an implicit provider.
   562  		// The extra proxy will be pruned later if it's unused.
   563  		g.Add(proxy)
   564  		t.providers[fullName] = proxy
   565  	}
   566  	return nil
   567  }
   568  
   569  func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {
   570  	for _, v := range g.Vertices() {
   571  		// Only care about GraphNodeAttachProvider implementations
   572  		apn, ok := v.(GraphNodeAttachProvider)
   573  		if !ok {
   574  			continue
   575  		}
   576  
   577  		// Determine what we're looking for
   578  		path := normalizeModulePath(apn.Path())[1:]
   579  		name := apn.ProviderName()
   580  		log.Printf("[TRACE] Attach provider request: %#v %s", path, name)
   581  
   582  		// Get the configuration.
   583  		tree := t.Module.Child(path)
   584  		if tree == nil {
   585  			continue
   586  		}
   587  
   588  		// Go through the provider configs to find the matching config
   589  		for _, p := range tree.Config().ProviderConfigs {
   590  			// Build the name, which is "name.alias" if an alias exists
   591  			current := p.Name
   592  			if p.Alias != "" {
   593  				current += "." + p.Alias
   594  			}
   595  
   596  			// If the configs match then attach!
   597  			if current == name {
   598  				log.Printf("[TRACE] Attaching provider config: %#v", p)
   599  				apn.AttachProvider(p)
   600  				break
   601  			}
   602  		}
   603  	}
   604  
   605  	return nil
   606  }