blob: 793b647f4280840302c0302201a2dec3e5a9917e [file] [log] [blame]
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package graph
import (
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/dag"
"github.com/hashicorp/terraform/internal/terraform"
"github.com/hashicorp/terraform/internal/tfdiags"
)
// TestProvidersTransformer is a GraphTransformer that gathers all the providers
// from the module configurations that the test runs depend on and attaches the
// required providers to the test run nodes.
type TestProvidersTransformer struct{}
func (t *TestProvidersTransformer) Transform(g *terraform.Graph) error {
configsProviderMap := make(map[string]map[string]bool)
runProviderMap := make(map[*NodeTestRun]map[string]bool)
// a root provider node that will add the providers to the context
rootProviderNode := t.createRootNode(g, runProviderMap)
for _, v := range g.Vertices() {
node, ok := v.(*NodeTestRun)
if !ok {
continue
}
// Get the providers that the test run depends on
configKey := node.run.GetModuleConfigID()
if _, ok := configsProviderMap[configKey]; !ok {
providers := t.transformSingleConfig(node.run.ModuleConfig)
configsProviderMap[configKey] = providers
}
runProviderMap[node] = configsProviderMap[configKey]
// Add an edge from the test run node to the root provider node
g.Connect(dag.BasicEdge(v, rootProviderNode))
}
return nil
}
func (t *TestProvidersTransformer) transformSingleConfig(config *configs.Config) map[string]bool {
providers := make(map[string]bool)
// First, let's look at the required providers first.
for _, provider := range config.Module.ProviderRequirements.RequiredProviders {
providers[provider.Name] = true
for _, alias := range provider.Aliases {
providers[alias.StringCompact()] = true
}
}
// Second, we look at the defined provider configs.
for _, provider := range config.Module.ProviderConfigs {
providers[provider.Addr().StringCompact()] = true
}
// Third, we look at the resources and data sources.
for _, resource := range config.Module.ManagedResources {
if resource.ProviderConfigRef != nil {
providers[resource.ProviderConfigRef.String()] = true
continue
}
providers[resource.Provider.Type] = true
}
for _, datasource := range config.Module.DataResources {
if datasource.ProviderConfigRef != nil {
providers[datasource.ProviderConfigRef.String()] = true
continue
}
providers[datasource.Provider.Type] = true
}
// Finally, we look at any module calls to see if any providers are used
// in there.
for _, module := range config.Module.ModuleCalls {
for _, provider := range module.Providers {
providers[provider.InParent.String()] = true
}
}
return providers
}
func (t *TestProvidersTransformer) createRootNode(g *terraform.Graph, providerMap map[*NodeTestRun]map[string]bool) *dynamicNode {
node := &dynamicNode{
eval: func(ctx *EvalContext) tfdiags.Diagnostics {
for node, providers := range providerMap {
ctx.SetProviders(node.run, providers)
}
return nil
},
}
g.Add(node)
return node
}