github.com/eliastor/durgaform@v0.0.0-20220816172711-d0ab2d17673e/internal/durgaform/transform_provider.go (about)

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