github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/transform_provider.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  
     7  	"github.com/hashicorp/hcl/v2"
     8  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
     9  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/dag"
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
    12  )
    13  
    14  func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, config *configs.Config) GraphTransformer {
    15  	return GraphTransformMulti(
    16  		// Add providers from the config
    17  		&ProviderConfigTransformer{
    18  			Config:    config,
    19  			Providers: providers,
    20  			Concrete:  concrete,
    21  		},
    22  		// Add any remaining missing providers
    23  		&MissingProviderTransformer{
    24  			Providers: providers,
    25  			Concrete:  concrete,
    26  		},
    27  		// Connect the providers
    28  		&ProviderTransformer{
    29  			Config: config,
    30  		},
    31  		// Remove unused providers and proxies
    32  		&PruneProviderTransformer{},
    33  		// Connect provider to their parent provider nodes
    34  		&ParentProviderTransformer{},
    35  	)
    36  }
    37  
    38  // GraphNodeProvider is an interface that nodes that can be a provider
    39  // must implement.
    40  //
    41  // ProviderAddr returns the address of the provider configuration this
    42  // satisfies, which is relative to the path returned by method Path().
    43  //
    44  // Name returns the full name of the provider in the config.
    45  type GraphNodeProvider interface {
    46  	GraphNodeSubPath
    47  	ProviderAddr() addrs.AbsProviderConfig
    48  	Name() string
    49  }
    50  
    51  // GraphNodeCloseProvider is an interface that nodes that can be a close
    52  // provider must implement. The CloseProviderName returned is the name of
    53  // the provider they satisfy.
    54  type GraphNodeCloseProvider interface {
    55  	GraphNodeSubPath
    56  	CloseProviderAddr() addrs.AbsProviderConfig
    57  }
    58  
    59  // GraphNodeProviderConsumer is an interface that nodes that require
    60  // a provider must implement. ProvidedBy must return the address of the provider
    61  // to use, which will be resolved to a configuration either in the same module
    62  // or in an ancestor module, with the resulting absolute address passed to
    63  // SetProvider.
    64  type GraphNodeProviderConsumer interface {
    65  	// ProvidedBy returns the address of the provider configuration the node
    66  	// refers to. If the returned "exact" value is true, this address will
    67  	// be taken exactly. If "exact" is false, a provider configuration from
    68  	// an ancestor module may be selected instead.
    69  	ProvidedBy() (addr addrs.AbsProviderConfig, exact bool)
    70  	// Set the resolved provider address for this resource.
    71  	SetProvider(addrs.AbsProviderConfig)
    72  }
    73  
    74  // ProviderTransformer is a GraphTransformer that maps resources to
    75  // providers within the graph. This will error if there are any resources
    76  // that don't map to proper resources.
    77  type ProviderTransformer struct {
    78  	Config *configs.Config
    79  }
    80  
    81  func (t *ProviderTransformer) Transform(g *Graph) error {
    82  	// We need to find a provider configuration address for each resource
    83  	// either directly represented by a node or referenced by a node in
    84  	// the graph, and then create graph edges from provider to provider user
    85  	// so that the providers will get initialized first.
    86  
    87  	var diags tfdiags.Diagnostics
    88  
    89  	// To start, we'll collect the _requested_ provider addresses for each
    90  	// node, which we'll then resolve (handling provider inheritence, etc) in
    91  	// the next step.
    92  	// Our "requested" map is from graph vertices to string representations of
    93  	// provider config addresses (for deduping) to requests.
    94  	type ProviderRequest struct {
    95  		Addr  addrs.AbsProviderConfig
    96  		Exact bool // If true, inheritence from parent modules is not attempted
    97  	}
    98  	requested := map[dag.Vertex]map[string]ProviderRequest{}
    99  	needConfigured := map[string]addrs.AbsProviderConfig{}
   100  	for _, v := range g.Vertices() {
   101  
   102  		// Does the vertex _directly_ use a provider?
   103  		if pv, ok := v.(GraphNodeProviderConsumer); ok {
   104  			requested[v] = make(map[string]ProviderRequest)
   105  
   106  			p, exact := pv.ProvidedBy()
   107  			if exact {
   108  				log.Printf("[TRACE] ProviderTransformer: %s is provided by %s exactly", dag.VertexName(v), p)
   109  			} else {
   110  				log.Printf("[TRACE] ProviderTransformer: %s is provided by %s or inherited equivalent", dag.VertexName(v), p)
   111  			}
   112  
   113  			requested[v][p.String()] = ProviderRequest{
   114  				Addr:  p,
   115  				Exact: exact,
   116  			}
   117  
   118  			// Direct references need the provider configured as well as initialized
   119  			needConfigured[p.String()] = p
   120  		}
   121  	}
   122  
   123  	// Now we'll go through all the requested addresses we just collected and
   124  	// figure out which _actual_ config address each belongs to, after resolving
   125  	// for provider inheritance and passing.
   126  	m := providerVertexMap(g)
   127  	for v, reqs := range requested {
   128  		for key, req := range reqs {
   129  			p := req.Addr
   130  			target := m[key]
   131  
   132  			_, ok := v.(GraphNodeSubPath)
   133  			if !ok && target == nil {
   134  				// No target and no path to traverse up from
   135  				diags = diags.Append(fmt.Errorf("%s: provider %s couldn't be found", dag.VertexName(v), p))
   136  				continue
   137  			}
   138  
   139  			if target != nil {
   140  				log.Printf("[TRACE] ProviderTransformer: exact match for %s serving %s", p, dag.VertexName(v))
   141  			}
   142  
   143  			// if we don't have a provider at this level, walk up the path looking for one,
   144  			// unless we were told to be exact.
   145  			if target == nil && !req.Exact {
   146  				for pp, ok := p.Inherited(); ok; pp, ok = pp.Inherited() {
   147  					key := pp.String()
   148  					target = m[key]
   149  					if target != nil {
   150  						log.Printf("[TRACE] ProviderTransformer: %s uses inherited configuration %s", dag.VertexName(v), pp)
   151  						break
   152  					}
   153  					log.Printf("[TRACE] ProviderTransformer: looking for %s to serve %s", pp, dag.VertexName(v))
   154  				}
   155  			}
   156  
   157  			// If this provider doesn't need to be configured then we can just
   158  			// stub it out with an init-only provider node, which will just
   159  			// start up the provider and fetch its schema.
   160  			if _, exists := needConfigured[key]; target == nil && !exists {
   161  				stubAddr := p.ProviderConfig.Absolute(addrs.RootModuleInstance)
   162  				stub := &NodeEvalableProvider{
   163  					&NodeAbstractProvider{
   164  						Addr: stubAddr,
   165  					},
   166  				}
   167  				m[stubAddr.String()] = stub
   168  				log.Printf("[TRACE] ProviderTransformer: creating init-only node for %s", stubAddr)
   169  				target = stub
   170  				g.Add(target)
   171  			}
   172  
   173  			if target == nil {
   174  				diags = diags.Append(tfdiags.Sourceless(
   175  					tfdiags.Error,
   176  					"Provider configuration not present",
   177  					fmt.Sprintf(
   178  						"To work with %s its original provider configuration at %s is required, but it has been removed. This occurs when a provider configuration is removed while objects created by that provider still exist in the state. Re-add the provider configuration to destroy %s, after which you can remove the provider configuration again.",
   179  						dag.VertexName(v), p, dag.VertexName(v),
   180  					),
   181  				))
   182  				break
   183  			}
   184  
   185  			// see if this in  an inherited provider
   186  			if p, ok := target.(*graphNodeProxyProvider); ok {
   187  				g.Remove(p)
   188  				target = p.Target()
   189  				key = target.(GraphNodeProvider).ProviderAddr().String()
   190  			}
   191  
   192  			log.Printf("[DEBUG] ProviderTransformer: %q (%T) needs %s", dag.VertexName(v), v, dag.VertexName(target))
   193  			if pv, ok := v.(GraphNodeProviderConsumer); ok {
   194  				pv.SetProvider(target.ProviderAddr())
   195  			}
   196  			g.Connect(dag.BasicEdge(v, target))
   197  		}
   198  	}
   199  
   200  	return diags.Err()
   201  }
   202  
   203  // CloseProviderTransformer is a GraphTransformer that adds nodes to the
   204  // graph that will close open provider connections that aren't needed anymore.
   205  // A provider connection is not needed anymore once all depended resources
   206  // in the graph are evaluated.
   207  type CloseProviderTransformer struct{}
   208  
   209  func (t *CloseProviderTransformer) Transform(g *Graph) error {
   210  	pm := providerVertexMap(g)
   211  	cpm := make(map[string]*graphNodeCloseProvider)
   212  	var err error
   213  
   214  	for _, v := range pm {
   215  		p := v.(GraphNodeProvider)
   216  		key := p.ProviderAddr().String()
   217  
   218  		// get the close provider of this type if we alread created it
   219  		closer := cpm[key]
   220  
   221  		if closer == nil {
   222  			// create a closer for this provider type
   223  			closer = &graphNodeCloseProvider{Addr: p.ProviderAddr()}
   224  			g.Add(closer)
   225  			cpm[key] = closer
   226  		}
   227  
   228  		// Close node depends on the provider itself
   229  		// this is added unconditionally, so it will connect to all instances
   230  		// of the provider. Extra edges will be removed by transitive
   231  		// reduction.
   232  		g.Connect(dag.BasicEdge(closer, p))
   233  
   234  		// connect all the provider's resources to the close node
   235  		for _, s := range g.UpEdges(p).List() {
   236  			if _, ok := s.(GraphNodeProviderConsumer); ok {
   237  				g.Connect(dag.BasicEdge(closer, s))
   238  			}
   239  		}
   240  	}
   241  
   242  	return err
   243  }
   244  
   245  // MissingProviderTransformer is a GraphTransformer that adds to the graph
   246  // a node for each default provider configuration that is referenced by another
   247  // node but not already present in the graph.
   248  //
   249  // These "default" nodes are always added to the root module, regardless of
   250  // where they are requested. This is important because our inheritance
   251  // resolution behavior in ProviderTransformer will then treat these as a
   252  // last-ditch fallback after walking up the tree, rather than preferring them
   253  // as it would if they were placed in the same module as the requester.
   254  //
   255  // This transformer may create extra nodes that are not needed in practice,
   256  // due to overriding provider configurations in child modules.
   257  // PruneProviderTransformer can then remove these once ProviderTransformer
   258  // has resolved all of the inheritence, etc.
   259  type MissingProviderTransformer struct {
   260  	// Providers is the list of providers we support.
   261  	Providers []string
   262  
   263  	// Concrete, if set, overrides how the providers are made.
   264  	Concrete ConcreteProviderNodeFunc
   265  }
   266  
   267  func (t *MissingProviderTransformer) Transform(g *Graph) error {
   268  	// Initialize factory
   269  	if t.Concrete == nil {
   270  		t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
   271  			return a
   272  		}
   273  	}
   274  
   275  	var err error
   276  	m := providerVertexMap(g)
   277  	for _, v := range g.Vertices() {
   278  		pv, ok := v.(GraphNodeProviderConsumer)
   279  		if !ok {
   280  			continue
   281  		}
   282  
   283  		// For our work here we actually care only about the provider type and
   284  		// we plan to place all default providers in the root module, and so
   285  		// it's safe for us to rely on ProvidedBy here rather than waiting for
   286  		// the later proper resolution of provider inheritance done by
   287  		// ProviderTransformer.
   288  		p, _ := pv.ProvidedBy()
   289  		if p.ProviderConfig.Alias != "" {
   290  			// We do not create default aliased configurations.
   291  			log.Println("[TRACE] MissingProviderTransformer: skipping implication of aliased config", p)
   292  			continue
   293  		}
   294  
   295  		// We're going to create an implicit _default_ configuration for the
   296  		// referenced provider type in the _root_ module, ignoring all other
   297  		// aspects of the resource's declared provider address.
   298  		defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(p.ProviderConfig.Type)
   299  		key := defaultAddr.String()
   300  		provider := m[key]
   301  
   302  		if provider != nil {
   303  			// There's already an explicit default configuration for this
   304  			// provider type in the root module, so we have nothing to do.
   305  			continue
   306  		}
   307  
   308  		log.Printf("[DEBUG] adding implicit provider configuration %s, implied first by %s", defaultAddr, dag.VertexName(v))
   309  
   310  		// create the missing top-level provider
   311  		provider = t.Concrete(&NodeAbstractProvider{
   312  			Addr: defaultAddr,
   313  		}).(GraphNodeProvider)
   314  
   315  		g.Add(provider)
   316  		m[key] = provider
   317  	}
   318  
   319  	return err
   320  }
   321  
   322  // ParentProviderTransformer connects provider nodes to their parents.
   323  //
   324  // This works by finding nodes that are both GraphNodeProviders and
   325  // GraphNodeSubPath. It then connects the providers to their parent
   326  // path. The parent provider is always at the root level.
   327  type ParentProviderTransformer struct{}
   328  
   329  func (t *ParentProviderTransformer) Transform(g *Graph) error {
   330  	pm := providerVertexMap(g)
   331  	for _, v := range g.Vertices() {
   332  		// Only care about providers
   333  		pn, ok := v.(GraphNodeProvider)
   334  		if !ok {
   335  			continue
   336  		}
   337  
   338  		// Also require non-empty path, since otherwise we're in the root
   339  		// module and so cannot have a parent.
   340  		if len(pn.Path()) <= 1 {
   341  			continue
   342  		}
   343  
   344  		// this provider may be disabled, but we can only get it's name from
   345  		// the ProviderName string
   346  		addr := pn.ProviderAddr()
   347  		parentAddr, ok := addr.Inherited()
   348  		if ok {
   349  			parent := pm[parentAddr.String()]
   350  			if parent != nil {
   351  				g.Connect(dag.BasicEdge(v, parent))
   352  			}
   353  		}
   354  	}
   355  	return nil
   356  }
   357  
   358  // PruneProviderTransformer removes any providers that are not actually used by
   359  // anything, and provider proxies. This avoids the provider being initialized
   360  // and configured.  This both saves resources but also avoids errors since
   361  // configuration may imply initialization which may require auth.
   362  type PruneProviderTransformer struct{}
   363  
   364  func (t *PruneProviderTransformer) Transform(g *Graph) error {
   365  	for _, v := range g.Vertices() {
   366  		// We only care about providers
   367  		_, ok := v.(GraphNodeProvider)
   368  		if !ok {
   369  			continue
   370  		}
   371  
   372  		// ProxyProviders will have up edges, but we're now done with them in the graph
   373  		if _, ok := v.(*graphNodeProxyProvider); ok {
   374  			log.Printf("[DEBUG] pruning proxy %s", dag.VertexName(v))
   375  			g.Remove(v)
   376  		}
   377  
   378  		// Remove providers with no dependencies.
   379  		if g.UpEdges(v).Len() == 0 {
   380  			log.Printf("[DEBUG] pruning unused %s", dag.VertexName(v))
   381  			g.Remove(v)
   382  		}
   383  	}
   384  
   385  	return nil
   386  }
   387  
   388  func providerVertexMap(g *Graph) map[string]GraphNodeProvider {
   389  	m := make(map[string]GraphNodeProvider)
   390  	for _, v := range g.Vertices() {
   391  		if pv, ok := v.(GraphNodeProvider); ok {
   392  			addr := pv.ProviderAddr()
   393  			m[addr.String()] = pv
   394  		}
   395  	}
   396  
   397  	return m
   398  }
   399  
   400  type graphNodeCloseProvider struct {
   401  	Addr addrs.AbsProviderConfig
   402  }
   403  
   404  var (
   405  	_ GraphNodeCloseProvider = (*graphNodeCloseProvider)(nil)
   406  )
   407  
   408  func (n *graphNodeCloseProvider) Name() string {
   409  	return n.Addr.String() + " (close)"
   410  }
   411  
   412  // GraphNodeSubPath impl.
   413  func (n *graphNodeCloseProvider) Path() addrs.ModuleInstance {
   414  	return n.Addr.Module
   415  }
   416  
   417  // GraphNodeEvalable impl.
   418  func (n *graphNodeCloseProvider) EvalTree() EvalNode {
   419  	return CloseProviderEvalTree(n.Addr)
   420  }
   421  
   422  // GraphNodeDependable impl.
   423  func (n *graphNodeCloseProvider) DependableName() []string {
   424  	return []string{n.Name()}
   425  }
   426  
   427  func (n *graphNodeCloseProvider) CloseProviderAddr() addrs.AbsProviderConfig {
   428  	return n.Addr
   429  }
   430  
   431  // GraphNodeDotter impl.
   432  func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   433  	if !opts.Verbose {
   434  		return nil
   435  	}
   436  	return &dag.DotNode{
   437  		Name: name,
   438  		Attrs: map[string]string{
   439  			"label": n.Name(),
   440  			"shape": "diamond",
   441  		},
   442  	}
   443  }
   444  
   445  // RemovableIfNotTargeted
   446  func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
   447  	// We need to add this so that this node will be removed if
   448  	// it isn't targeted or a dependency of a target.
   449  	return true
   450  }
   451  
   452  // graphNodeProxyProvider is a GraphNodeProvider implementation that is used to
   453  // store the name and value of a provider node for inheritance between modules.
   454  // These nodes are only used to store the data while loading the provider
   455  // configurations, and are removed after all the resources have been connected
   456  // to their providers.
   457  type graphNodeProxyProvider struct {
   458  	addr   addrs.AbsProviderConfig
   459  	target GraphNodeProvider
   460  }
   461  
   462  var (
   463  	_ GraphNodeProvider = (*graphNodeProxyProvider)(nil)
   464  )
   465  
   466  func (n *graphNodeProxyProvider) ProviderAddr() addrs.AbsProviderConfig {
   467  	return n.addr
   468  }
   469  
   470  func (n *graphNodeProxyProvider) Path() addrs.ModuleInstance {
   471  	return n.addr.Module
   472  }
   473  
   474  func (n *graphNodeProxyProvider) Name() string {
   475  	return n.addr.String() + " (proxy)"
   476  }
   477  
   478  // find the concrete provider instance
   479  func (n *graphNodeProxyProvider) Target() GraphNodeProvider {
   480  	switch t := n.target.(type) {
   481  	case *graphNodeProxyProvider:
   482  		return t.Target()
   483  	default:
   484  		return n.target
   485  	}
   486  }
   487  
   488  // ProviderConfigTransformer adds all provider nodes from the configuration and
   489  // attaches the configs.
   490  type ProviderConfigTransformer struct {
   491  	Providers []string
   492  	Concrete  ConcreteProviderNodeFunc
   493  
   494  	// each provider node is stored here so that the proxy nodes can look up
   495  	// their targets by name.
   496  	providers map[string]GraphNodeProvider
   497  	// record providers that can be overriden with a proxy
   498  	proxiable map[string]bool
   499  
   500  	// Config is the root node of the configuration tree to add providers from.
   501  	Config *configs.Config
   502  }
   503  
   504  func (t *ProviderConfigTransformer) Transform(g *Graph) error {
   505  	// If no configuration is given, we don't do anything
   506  	if t.Config == nil {
   507  		return nil
   508  	}
   509  
   510  	t.providers = make(map[string]GraphNodeProvider)
   511  	t.proxiable = make(map[string]bool)
   512  
   513  	// Start the transformation process
   514  	if err := t.transform(g, t.Config); err != nil {
   515  		return err
   516  	}
   517  
   518  	// finally attach the configs to the new nodes
   519  	return t.attachProviderConfigs(g)
   520  }
   521  
   522  func (t *ProviderConfigTransformer) transform(g *Graph, c *configs.Config) error {
   523  	// If no config, do nothing
   524  	if c == nil {
   525  		return nil
   526  	}
   527  
   528  	// Add our resources
   529  	if err := t.transformSingle(g, c); err != nil {
   530  		return err
   531  	}
   532  
   533  	// Transform all the children.
   534  	for _, cc := range c.Children {
   535  		if err := t.transform(g, cc); err != nil {
   536  			return err
   537  		}
   538  	}
   539  	return nil
   540  }
   541  
   542  func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config) error {
   543  	// Get the module associated with this configuration tree node
   544  	mod := c.Module
   545  	staticPath := c.Path
   546  
   547  	// We actually need a dynamic module path here, but we've not yet updated
   548  	// our graph builders enough to support expansion of module calls with
   549  	// "count" and "for_each" set, so for now we'll shim this by converting to
   550  	// a dynamic path with no keys. At the time of writing this is the only
   551  	// possible kind of dynamic path anyway.
   552  	path := make(addrs.ModuleInstance, len(staticPath))
   553  	for i, name := range staticPath {
   554  		path[i] = addrs.ModuleInstanceStep{
   555  			Name: name,
   556  		}
   557  	}
   558  
   559  	// add all providers from the configuration
   560  	for _, p := range mod.ProviderConfigs {
   561  		relAddr := p.Addr()
   562  		addr := relAddr.Absolute(path)
   563  
   564  		abstract := &NodeAbstractProvider{
   565  			Addr: addr,
   566  		}
   567  		var v dag.Vertex
   568  		if t.Concrete != nil {
   569  			v = t.Concrete(abstract)
   570  		} else {
   571  			v = abstract
   572  		}
   573  
   574  		// Add it to the graph
   575  		g.Add(v)
   576  		key := addr.String()
   577  		t.providers[key] = v.(GraphNodeProvider)
   578  
   579  		// A provider configuration is "proxyable" if its configuration is
   580  		// entirely empty. This means it's standing in for a provider
   581  		// configuration that must be passed in from the parent module.
   582  		// We decide this by evaluating the config with an empty schema;
   583  		// if this succeeds, then we know there's nothing in the body.
   584  		_, diags := p.Config.Content(&hcl.BodySchema{})
   585  		t.proxiable[key] = !diags.HasErrors()
   586  	}
   587  
   588  	// Now replace the provider nodes with proxy nodes if a provider was being
   589  	// passed in, and create implicit proxies if there was no config. Any extra
   590  	// proxies will be removed in the prune step.
   591  	return t.addProxyProviders(g, c)
   592  }
   593  
   594  func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Config) error {
   595  	path := c.Path
   596  
   597  	// can't add proxies at the root
   598  	if len(path) == 0 {
   599  		return nil
   600  	}
   601  
   602  	parentPath, callAddr := path.Call()
   603  	parent := c.Parent
   604  	if parent == nil {
   605  		return nil
   606  	}
   607  
   608  	callName := callAddr.Name
   609  	var parentCfg *configs.ModuleCall
   610  	for name, mod := range parent.Module.ModuleCalls {
   611  		if name == callName {
   612  			parentCfg = mod
   613  			break
   614  		}
   615  	}
   616  
   617  	// We currently don't support count/for_each for modules and so we must
   618  	// shim our path and parentPath into module instances here so that the
   619  	// rest of Terraform can behave as if we do. This shimming should be
   620  	// removed later as part of implementing count/for_each for modules.
   621  	instPath := make(addrs.ModuleInstance, len(path))
   622  	for i, name := range path {
   623  		instPath[i] = addrs.ModuleInstanceStep{Name: name}
   624  	}
   625  	parentInstPath := make(addrs.ModuleInstance, len(parentPath))
   626  	for i, name := range parentPath {
   627  		parentInstPath[i] = addrs.ModuleInstanceStep{Name: name}
   628  	}
   629  
   630  	if parentCfg == nil {
   631  		// this can't really happen during normal execution.
   632  		return fmt.Errorf("parent module config not found for %s", c.Path.String())
   633  	}
   634  
   635  	// Go through all the providers the parent is passing in, and add proxies to
   636  	// the parent provider nodes.
   637  	for _, pair := range parentCfg.Providers {
   638  		fullAddr := pair.InChild.Addr().Absolute(instPath)
   639  		fullParentAddr := pair.InParent.Addr().Absolute(parentInstPath)
   640  		fullName := fullAddr.String()
   641  		fullParentName := fullParentAddr.String()
   642  
   643  		parentProvider := t.providers[fullParentName]
   644  
   645  		if parentProvider == nil {
   646  			return fmt.Errorf("missing provider %s", fullParentName)
   647  		}
   648  
   649  		proxy := &graphNodeProxyProvider{
   650  			addr:   fullAddr,
   651  			target: parentProvider,
   652  		}
   653  
   654  		concreteProvider := t.providers[fullName]
   655  
   656  		// replace the concrete node with the provider passed in
   657  		if concreteProvider != nil && t.proxiable[fullName] {
   658  			g.Replace(concreteProvider, proxy)
   659  			t.providers[fullName] = proxy
   660  			continue
   661  		}
   662  
   663  		// aliased configurations can't be implicitly passed in
   664  		if fullAddr.ProviderConfig.Alias != "" {
   665  			continue
   666  		}
   667  
   668  		// There was no concrete provider, so add this as an implicit provider.
   669  		// The extra proxy will be pruned later if it's unused.
   670  		g.Add(proxy)
   671  		t.providers[fullName] = proxy
   672  	}
   673  	return nil
   674  }
   675  
   676  func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {
   677  	for _, v := range g.Vertices() {
   678  		// Only care about GraphNodeAttachProvider implementations
   679  		apn, ok := v.(GraphNodeAttachProvider)
   680  		if !ok {
   681  			continue
   682  		}
   683  
   684  		// Determine what we're looking for
   685  		addr := apn.ProviderAddr()
   686  
   687  		// Get the configuration.
   688  		mc := t.Config.DescendentForInstance(addr.Module)
   689  		if mc == nil {
   690  			log.Printf("[TRACE] ProviderConfigTransformer: no configuration available for %s", addr.String())
   691  			continue
   692  		}
   693  
   694  		// Go through the provider configs to find the matching config
   695  		for _, p := range mc.Module.ProviderConfigs {
   696  			if p.Name == addr.ProviderConfig.Type && p.Alias == addr.ProviderConfig.Alias {
   697  				log.Printf("[TRACE] ProviderConfigTransformer: attaching to %q provider configuration from %s", dag.VertexName(v), p.DeclRange)
   698  				apn.AttachProvider(p)
   699  				break
   700  			}
   701  		}
   702  	}
   703  
   704  	return nil
   705  }