Merge pull request #16619 from hashicorp/jbardin/implicit-providers
Allow overriding an implicitly used provider
This commit is contained in:
commit
fc2913d610
|
@ -0,0 +1,10 @@
|
||||||
|
provider "aws" {
|
||||||
|
alias = "foo"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "mod" {
|
||||||
|
source = "./mod"
|
||||||
|
providers = {
|
||||||
|
"aws" = "aws.foo"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
resource "aws_instance" "bar" {
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
provider "aws" {
|
||||||
|
}
|
||||||
|
|
||||||
|
module "mod" {
|
||||||
|
source = "./mod"
|
||||||
|
|
||||||
|
# aws.foo doesn't exist, and should report an error
|
||||||
|
providers = {
|
||||||
|
"aws" = "aws.foo"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
resource "aws_resource" "foo" {
|
||||||
|
}
|
|
@ -412,6 +412,8 @@ type ProviderConfigTransformer struct {
|
||||||
// each provider node is stored here so that the proxy nodes can look up
|
// each provider node is stored here so that the proxy nodes can look up
|
||||||
// their targets by name.
|
// their targets by name.
|
||||||
providers map[string]GraphNodeProvider
|
providers map[string]GraphNodeProvider
|
||||||
|
// record providers that can be overriden with a proxy
|
||||||
|
proxiable map[string]bool
|
||||||
|
|
||||||
// Module is the module to add resources from.
|
// Module is the module to add resources from.
|
||||||
Module *module.Tree
|
Module *module.Tree
|
||||||
|
@ -429,10 +431,11 @@ func (t *ProviderConfigTransformer) Transform(g *Graph) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
t.providers = make(map[string]GraphNodeProvider)
|
t.providers = make(map[string]GraphNodeProvider)
|
||||||
|
t.proxiable = make(map[string]bool)
|
||||||
|
|
||||||
// Start the transformation process
|
// Start the transformation process
|
||||||
if err := t.transform(g, t.Module); err != nil {
|
if err := t.transform(g, t.Module); err != nil {
|
||||||
return nil
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally attach the configs to the new nodes
|
// finally attach the configs to the new nodes
|
||||||
|
@ -471,19 +474,13 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) er
|
||||||
path = append([]string{RootModuleName}, path...)
|
path = append([]string{RootModuleName}, path...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add all provider configs
|
// add all providers from the configuration
|
||||||
for _, p := range conf.ProviderConfigs {
|
for _, p := range conf.ProviderConfigs {
|
||||||
name := p.Name
|
name := p.Name
|
||||||
if p.Alias != "" {
|
if p.Alias != "" {
|
||||||
name += "." + p.Alias
|
name += "." + p.Alias
|
||||||
}
|
}
|
||||||
|
|
||||||
// if this is an empty config placeholder to accept a provier from a
|
|
||||||
// parent module, add a proxy and continue.
|
|
||||||
if t.addProxyProvider(g, m, p, name) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
v := t.Concrete(&NodeAbstractProvider{
|
v := t.Concrete(&NodeAbstractProvider{
|
||||||
NameValue: name,
|
NameValue: name,
|
||||||
PathValue: path,
|
PathValue: path,
|
||||||
|
@ -491,26 +488,29 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) er
|
||||||
|
|
||||||
// Add it to the graph
|
// Add it to the graph
|
||||||
g.Add(v)
|
g.Add(v)
|
||||||
t.providers[ResolveProviderName(name, path)] = v.(GraphNodeProvider)
|
fullName := ResolveProviderName(name, path)
|
||||||
|
t.providers[fullName] = v.(GraphNodeProvider)
|
||||||
|
t.proxiable[fullName] = len(p.RawConfig.RawMap()) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
// Now replace the provider nodes with proxy nodes if a provider was being
|
||||||
|
// passed in, and create implicit proxies if there was no config. Any extra
|
||||||
|
// proxies will be removed in the prune step.
|
||||||
|
return t.addProxyProviders(g, m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// add a ProxyProviderConfig if this was inherited from a parent module. Return
|
func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, m *module.Tree) error {
|
||||||
// whether the proxy was added to the graph or not.
|
|
||||||
func (t *ProviderConfigTransformer) addProxyProvider(g *Graph, m *module.Tree, pc *config.ProviderConfig, name string) bool {
|
|
||||||
path := m.Path()
|
path := m.Path()
|
||||||
|
|
||||||
// This isn't a proxy if there's a config, or we're at the root
|
// can't add proxies at the root
|
||||||
if len(pc.RawConfig.RawMap()) > 0 || len(path) == 0 {
|
if len(path) == 0 {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
parentPath := path[:len(path)-1]
|
parentPath := path[:len(path)-1]
|
||||||
parent := t.Module.Child(parentPath)
|
parent := t.Module.Child(parentPath)
|
||||||
if parent == nil {
|
if parent == nil {
|
||||||
return false
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var parentCfg *config.Module
|
var parentCfg *config.Module
|
||||||
|
@ -522,35 +522,48 @@ func (t *ProviderConfigTransformer) addProxyProvider(g *Graph, m *module.Tree, p
|
||||||
}
|
}
|
||||||
|
|
||||||
if parentCfg == nil {
|
if parentCfg == nil {
|
||||||
panic("immaculately conceived module " + m.Name())
|
// this can't really happen during normal execution.
|
||||||
|
return fmt.Errorf("parent module config not found for %s", m.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
parentProviderName, ok := parentCfg.Providers[name]
|
// Go through all the providers the parent is passing in, and add proxies to
|
||||||
if !ok {
|
// the parent provider nodes.
|
||||||
// this provider isn't listed in a parent module block, so we just have
|
for name, parentName := range parentCfg.Providers {
|
||||||
// an empty config
|
fullName := ResolveProviderName(name, path)
|
||||||
return false
|
fullParentName := ResolveProviderName(parentName, parentPath)
|
||||||
|
|
||||||
|
parentProvider := t.providers[fullParentName]
|
||||||
|
|
||||||
|
if parentProvider == nil {
|
||||||
|
return fmt.Errorf("missing provider %s", fullParentName)
|
||||||
|
}
|
||||||
|
|
||||||
|
proxy := &graphNodeProxyProvider{
|
||||||
|
nameValue: name,
|
||||||
|
path: path,
|
||||||
|
target: parentProvider,
|
||||||
|
}
|
||||||
|
|
||||||
|
concreteProvider := t.providers[fullName]
|
||||||
|
|
||||||
|
// replace the concrete node with the provider passed in
|
||||||
|
if concreteProvider != nil && t.proxiable[fullName] {
|
||||||
|
g.Replace(concreteProvider, proxy)
|
||||||
|
t.providers[fullName] = proxy
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// aliased providers can't be implicitly passed in
|
||||||
|
if strings.Contains(name, ".") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// There was no concrete provider, so add this as an implicit provider.
|
||||||
|
// The extra proxy will be pruned later if it's unused.
|
||||||
|
g.Add(proxy)
|
||||||
|
t.providers[fullName] = proxy
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
// the parent module is passing in a provider
|
|
||||||
fullParentName := ResolveProviderName(parentProviderName, parentPath)
|
|
||||||
parentProvider := t.providers[fullParentName]
|
|
||||||
|
|
||||||
if parentProvider == nil {
|
|
||||||
log.Printf("[ERROR] missing provider %s in module %s", parentProviderName, m.Name())
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
v := &graphNodeProxyProvider{
|
|
||||||
nameValue: name,
|
|
||||||
path: path,
|
|
||||||
target: parentProvider,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add it to the graph
|
|
||||||
g.Add(v)
|
|
||||||
t.providers[ResolveProviderName(name, path)] = v
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {
|
func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {
|
||||||
|
|
|
@ -511,6 +511,69 @@ func TestProviderConfigTransformer_grandparentProviders(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pass a specific provider into a module using it implicitly
|
||||||
|
func TestProviderConfigTransformer_implicitModule(t *testing.T) {
|
||||||
|
mod := testModule(t, "transform-provider-implicit-module")
|
||||||
|
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
|
||||||
|
|
||||||
|
g := Graph{Path: RootModulePath}
|
||||||
|
{
|
||||||
|
tf := &ConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
tf := &AttachResourceConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
tf := TransformProviders([]string{"aws"}, concrete, mod)
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(`module.mod.aws_instance.bar
|
||||||
|
provider.aws.foo
|
||||||
|
provider.aws.foo`)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// error out when a non-existent provider is named in a module providers map
|
||||||
|
func TestProviderConfigTransformer_invalidProvider(t *testing.T) {
|
||||||
|
mod := testModule(t, "transform-provider-invalid")
|
||||||
|
concrete := func(a *NodeAbstractProvider) dag.Vertex { return a }
|
||||||
|
|
||||||
|
g := Graph{Path: RootModulePath}
|
||||||
|
{
|
||||||
|
tf := &ConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
tf := &AttachResourceConfigTransformer{Module: mod}
|
||||||
|
if err := tf.Transform(&g); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tf := TransformProviders([]string{"aws"}, concrete, mod)
|
||||||
|
err := tf.Transform(&g)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatal("expected missing provider error")
|
||||||
|
}
|
||||||
|
if !strings.Contains(err.Error(), "provider.aws.foo") {
|
||||||
|
t.Fatalf("error should reference missing provider, got: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testTransformProviderBasicStr = `
|
const testTransformProviderBasicStr = `
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
provider.aws
|
provider.aws
|
||||||
|
|
Loading…
Reference in New Issue