add default provider nodes to root modules
If a root modules declares a required_provider but has no configuration, add a graph node for the provider as if there were an empty configuration. This will allow the provider to be referenced by name in module call provider maps, so that a module can pass a default provider by name to a submodule. Normally these nodes are added by the MissingProviderTransformer, but they need to be in place earlier to resolve any possible "proxy provider nodes" within modules.
This commit is contained in:
parent
95b86bf7ad
commit
f738246a03
|
@ -2093,3 +2093,71 @@ resource "test_instance" "c" {
|
||||||
t.Fatal(diags.ErrWithWarnings())
|
t.Fatal(diags.ErrWithWarnings())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestContext2Validate_passInheritedProvider(t *testing.T) {
|
||||||
|
m := testModuleInline(t, map[string]string{
|
||||||
|
"main.tf": `
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
test = {
|
||||||
|
source = "hashicorp/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module "first" {
|
||||||
|
source = "./first"
|
||||||
|
providers = {
|
||||||
|
test = test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
|
||||||
|
// This module does not define a config for the test provider, but we
|
||||||
|
// should be able to pass whatever the implied config is to a child
|
||||||
|
// module.
|
||||||
|
"first/main.tf": `
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
test = {
|
||||||
|
source = "hashicorp/test"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module "second" {
|
||||||
|
source = "./second"
|
||||||
|
providers = {
|
||||||
|
test.alias = test
|
||||||
|
}
|
||||||
|
}`,
|
||||||
|
|
||||||
|
"first/second/main.tf": `
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
test = {
|
||||||
|
source = "hashicorp/test"
|
||||||
|
configuration_aliases = [test.alias]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "test_object" "t" {
|
||||||
|
provider = test.alias
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
|
||||||
|
p := simpleMockProvider()
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Config: m,
|
||||||
|
Providers: map[addrs.Provider]providers.Factory{
|
||||||
|
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
diags := ctx.Validate()
|
||||||
|
if diags.HasErrors() {
|
||||||
|
t.Fatal(diags.ErrWithWarnings())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -534,6 +534,37 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config)
|
||||||
mod := c.Module
|
mod := c.Module
|
||||||
path := c.Path
|
path := c.Path
|
||||||
|
|
||||||
|
// If this is the root module, we can add nodes for required providers that
|
||||||
|
// have no configuration, equivalent to having an empty configuration
|
||||||
|
// block. This will ensure that a provider node exists for modules to
|
||||||
|
// access when passing around configuration and inheritance.
|
||||||
|
if path.IsRoot() && c.Module.ProviderRequirements != nil {
|
||||||
|
for name, p := range c.Module.ProviderRequirements.RequiredProviders {
|
||||||
|
if _, configured := mod.ProviderConfigs[name]; configured {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
addr := addrs.AbsProviderConfig{
|
||||||
|
Provider: p.Type,
|
||||||
|
Module: path,
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract := &NodeAbstractProvider{
|
||||||
|
Addr: addr,
|
||||||
|
}
|
||||||
|
|
||||||
|
var v dag.Vertex
|
||||||
|
if t.Concrete != nil {
|
||||||
|
v = t.Concrete(abstract)
|
||||||
|
} else {
|
||||||
|
v = abstract
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Add(v)
|
||||||
|
t.providers[addr.String()] = v.(GraphNodeProvider)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// add all providers from the configuration
|
// add all providers from the configuration
|
||||||
for _, p := range mod.ProviderConfigs {
|
for _, p := range mod.ProviderConfigs {
|
||||||
fqn := mod.ProviderForLocalConfig(p.Addr())
|
fqn := mod.ProviderForLocalConfig(p.Addr())
|
||||||
|
@ -558,13 +589,17 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config)
|
||||||
key := addr.String()
|
key := addr.String()
|
||||||
t.providers[key] = v.(GraphNodeProvider)
|
t.providers[key] = v.(GraphNodeProvider)
|
||||||
|
|
||||||
// A provider configuration is "proxyable" if its configuration is
|
// While deprecated, we still accept empty configuration blocks within
|
||||||
// entirely empty. This means it's standing in for a provider
|
// modules as being a possible proxy for passed configuration.
|
||||||
// configuration that must be passed in from the parent module.
|
if !path.IsRoot() {
|
||||||
// We decide this by evaluating the config with an empty schema;
|
// A provider configuration is "proxyable" if its configuration is
|
||||||
// if this succeeds, then we know there's nothing in the body.
|
// entirely empty. This means it's standing in for a provider
|
||||||
_, diags := p.Config.Content(&hcl.BodySchema{})
|
// configuration that must be passed in from the parent module.
|
||||||
t.proxiable[key] = !diags.HasErrors()
|
// We decide this by evaluating the config with an empty schema;
|
||||||
|
// if this succeeds, then we know there's nothing in the body.
|
||||||
|
_, diags := p.Config.Content(&hcl.BodySchema{})
|
||||||
|
t.proxiable[key] = !diags.HasErrors()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now replace the provider nodes with proxy nodes if a provider was being
|
// Now replace the provider nodes with proxy nodes if a provider was being
|
||||||
|
@ -577,7 +612,7 @@ func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Confi
|
||||||
path := c.Path
|
path := c.Path
|
||||||
|
|
||||||
// can't add proxies at the root
|
// can't add proxies at the root
|
||||||
if len(path) == 0 {
|
if path.IsRoot() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -648,6 +683,7 @@ func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Confi
|
||||||
g.Add(proxy)
|
g.Add(proxy)
|
||||||
t.providers[fullName] = proxy
|
t.providers[fullName] = proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue