Repository: opentofu/opentofu
File: internal/tofu/transform_provider.go (Go)

Code before:
// transformer needing to be known in other parts of the application.
// Ideally, this would not be needed and be built like the ProviderTransformer. Unfortunately, it's
// a significant refactor to get to that point which adds a lot of complexity.
type ProviderFunctionMapping map[ProviderFunctionReference]FunctionProvidedBy

func (m ProviderFunctionMapping) Lookup(module addrs.Module, pf addrs.ProviderFunction) (FunctionProvidedBy, bool) {
	providedBy, ok := m[ProviderFunctionReference{
		ModulePath:    module.String(),
		ProviderName:  pf.ProviderName,
		ProviderAlias: pf.ProviderAlias,
	}]
	return providedBy, ok
}

// ProviderFunctionTransformer is a GraphTransformer that maps nodes which reference functions to providers
// within the graph. This will error if there are any provider functions that don't map to known providers.
type ProviderFunctionTransformer struct {
	Config                  *configs.Config
	ProviderFunctionTracker ProviderFunctionMapping
}

func createStubProvider(g *Graph, providerVerts map[string]GraphNodeProvider, pAddr addrs.AbsProviderConfig) *NodeEvalableProvider {
	stubAddr := addrs.AbsProviderConfig{
		Module:   addrs.RootModule,
		Provider: pAddr.Provider,
		Alias:    "",
	}

	log.Printf("[TRACE] ProviderFunctionTransformer: creating init-only node for %s", stubAddr)
	stubProvider := &NodeEvalableProvider{
		&NodeAbstractProvider{
			Addr: stubAddr,
		},
	}

	providerVerts[stubAddr.String()] = stubProvider
	g.Add(stubProvider)
	return stubProvider
}

func (t *ProviderFunctionTransformer) Transform(_ context.Context, g *Graph) error {
	var diags tfdiags.Diagnostics

	if t.Config == nil {
		// This is probably a test case, inherited from ProviderTransformer
		log.Printf("[WARN] Skipping provider function transformer due to missing config")
		return nil
	}

	// Locate all providerVerts in the graph
	providerVerts := providerVertexMap(g)

Review comment (bug):
I know that this was like this before, but wondering if this is not a bug 🤔.
I don't understand why we drop the possible existing alias of the provider.
Maybe somebody can shine some light on this.

Code after:
// transformer needing to be known in other parts of the application.
// Ideally, this would not be needed and be built like the ProviderTransformer. Unfortunately, it's
// a significant refactor to get to that point which adds a lot of complexity.
type ProviderFunctionMapping map[ProviderFunctionReference]FunctionProvidedBy

func (m ProviderFunctionMapping) Lookup(module addrs.Module, pf addrs.ProviderFunction) (FunctionProvidedBy, bool) {
	providedBy, ok := m[ProviderFunctionReference{
		ModulePath:    module.String(),
		ProviderName:  pf.ProviderName,
		ProviderAlias: pf.ProviderAlias,
	}]
	return providedBy, ok
}

// ProviderUnconfiguredTransformer converts NodeApplyableProvider nodes to NodeEvalableProvider
// nodes so provider's functions can be used without configuration.
type ProviderUnconfiguredTransformer struct{}

func (t *ProviderUnconfiguredTransformer) Transform(_ context.Context, g *Graph) error {
	// Locate all providerVerts in the graph
	providerVerts := providerVertexMap(g)
	// Iterate through the providers to identify their dependencies (edges). If a provider
	// lacks both references and configuration, use a NodeEvalableProvider.
	for _, p := range providerVerts {
		applyableProvider, ok := p.(*NodeApplyableProvider)
		// There are three conditions to skip the conversion
		// from NodeApplyableProvider to NodeEvalableProvider:
		//   1. The node is not an NodeApplyableProvider
		//   2. The provider has existing configuration
		//   3. The provider node is referenced by another node
		edges := append(g.EdgesFrom(applyableProvider), g.EdgesTo(applyableProvider)...)
		if !ok || applyableProvider.Config != nil || len(edges) > 0 {
			continue
		}

		pAddr := applyableProvider.ProviderAddr()
		log.Printf("[TRACE] ProviderFunctionTransformer: replacing NodeApplyableProvider with NodeEvalableProvider for %s since it's missing configuration and there are no consumers of it", pAddr)
		unconfiguredProvider := &NodeEvalableProvider{
			&NodeAbstractProvider{
				Addr: pAddr,
			},
		}
		g.Replace(applyableProvider, unconfiguredProvider)
	}
	return nil
}

// ProviderFunctionTransformer is a GraphTransformer that maps nodes which reference functions to providers
// within the graph. This will error if there are any provider functions that don't map to known providers.
type ProviderFunctionTransformer struct {
	Config                  *configs.Config