rewrite the ProviderConfigTransformer

It's become apparent that passing in a provider config for an implicitly
used provider would be very useful. While the ProviderConfigTransformer
efficiently added providers to the graph, the algorithm was reversed
from what would be needed to allow overriding implicit providers.

Change the ProviderConfigTransformer to fist add all configured
provider, even if they are empty stubs. Then run through all providers
being passed in from the parent, and replace the provider nodes we
created with proxies, and add implicit proxies where none existed. The
extra nodes will then be pruned later.
This commit is contained in:
James Bardin 2017-11-09 23:22:40 -05:00
parent aef082d1ec
commit 8bf270daa9
1 changed files with 54 additions and 42 deletions

View File

@ -405,6 +405,8 @@ type ProviderConfigTransformer struct {
// each provider node is stored here so that the proxy nodes can look up
// their targets by name.
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 *module.Tree
@ -422,6 +424,7 @@ func (t *ProviderConfigTransformer) Transform(g *Graph) error {
}
t.providers = make(map[string]GraphNodeProvider)
t.proxiable = make(map[string]bool)
// Start the transformation process
if err := t.transform(g, t.Module); err != nil {
@ -464,19 +467,13 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) er
path = append([]string{RootModuleName}, path...)
}
// add all provider configs
// add all providers from the configuration
for _, p := range conf.ProviderConfigs {
name := p.Name
if 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{
NameValue: name,
PathValue: path,
@ -484,26 +481,29 @@ func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) er
// Add it to the graph
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
// 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 {
func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, m *module.Tree) error {
path := m.Path()
// This isn't a proxy if there's a config, or we're at the root
if len(pc.RawConfig.RawMap()) > 0 || len(path) == 0 {
return false
// can't add proxies at the root
if len(path) == 0 {
return nil
}
parentPath := path[:len(path)-1]
parent := t.Module.Child(parentPath)
if parent == nil {
return false
return nil
}
var parentCfg *config.Module
@ -515,35 +515,47 @@ func (t *ProviderConfigTransformer) addProxyProvider(g *Graph, m *module.Tree, p
}
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]
if !ok {
// this provider isn't listed in a parent module block, so we just have
// an empty config
return false
// Go through all the providers the parent is passing in, and add proxies to
// the parent provider nodes.
for name, parentName := range parentCfg.Providers {
fullName := ResolveProviderName(name, path)
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
}
// 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
return nil
}
func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error {