terraform: refactor ProvidedBy() to return an addrs.ProviderConfig interface (#24295)
* terraform: refactor ProvidedBy() to return an addrs.ProviderConfig interface This refactor allows terraform to indicate whether a specific provider configuration was found for the resource or if it is instead returning the assumed default. With that additional information the provider transformer can check if there is a specific (non-default) provider FQN.
This commit is contained in:
parent
e6592dc710
commit
6118d22c1f
|
@ -285,25 +285,17 @@ func (n *NodeAbstractResource) SetProvider(p addrs.AbsProviderConfig) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *NodeAbstractResource) ProvidedBy() (addrs.AbsProviderConfig, bool) {
|
func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) {
|
||||||
// If we have a config we prefer that above all else
|
// If we have a config we prefer that above all else
|
||||||
if n.Config != nil {
|
if n.Config != nil {
|
||||||
relAddr := n.Config.ProviderConfigAddr()
|
relAddr := n.Config.ProviderConfigAddr()
|
||||||
// FIXME: this will need to lookup the provider and see if there's an
|
return addrs.LocalProviderConfig{
|
||||||
// FQN associated with the local config
|
LocalName: relAddr.LocalName,
|
||||||
fqn := addrs.NewLegacyProvider(relAddr.LocalName)
|
Alias: relAddr.Alias,
|
||||||
return addrs.AbsProviderConfig{
|
|
||||||
Provider: fqn,
|
|
||||||
Module: n.Path(),
|
|
||||||
Alias: relAddr.Alias,
|
|
||||||
}, false
|
}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use our type and containing module path to guess a provider configuration address.
|
// Use our type and containing module path to guess a provider configuration address.
|
||||||
// FIXME: This is relying on the FQN-to-local matching true only of legacy
|
|
||||||
// addresses, so this will need to switch to using an addrs.LocalProviderConfig
|
|
||||||
// with the local name here, once we've done the work elsewhere to make
|
|
||||||
// that possible.
|
|
||||||
defaultFQN := n.Addr.Resource.DefaultProvider()
|
defaultFQN := n.Addr.Resource.DefaultProvider()
|
||||||
return addrs.AbsProviderConfig{
|
return addrs.AbsProviderConfig{
|
||||||
Provider: defaultFQN,
|
Provider: defaultFQN,
|
||||||
|
@ -312,19 +304,13 @@ func (n *NodeAbstractResource) ProvidedBy() (addrs.AbsProviderConfig, bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.AbsProviderConfig, bool) {
|
func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.ProviderConfig, bool) {
|
||||||
// If we have a config we prefer that above all else
|
// If we have a config we prefer that above all else
|
||||||
if n.Config != nil {
|
if n.Config != nil {
|
||||||
relAddr := n.Config.ProviderConfigAddr()
|
relAddr := n.Config.ProviderConfigAddr()
|
||||||
// Use our type and containing module path to guess a provider configuration address.
|
return addrs.LocalProviderConfig{
|
||||||
// FIXME: This is relying on the FQN-to-local matching true only of legacy
|
LocalName: relAddr.LocalName,
|
||||||
// addresses.
|
Alias: relAddr.Alias,
|
||||||
fqn := addrs.NewLegacyProvider(relAddr.LocalName)
|
|
||||||
|
|
||||||
return addrs.AbsProviderConfig{
|
|
||||||
Provider: fqn,
|
|
||||||
Module: n.Path(),
|
|
||||||
Alias: relAddr.Alias,
|
|
||||||
}, false
|
}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,10 +323,6 @@ func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.AbsProviderConfig, bo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use our type and containing module path to guess a provider configuration address
|
// Use our type and containing module path to guess a provider configuration address
|
||||||
// FIXME: This is relying on the FQN-to-local matching true only of legacy
|
|
||||||
// addresses, so this will need to switch to using an addrs.LocalProviderConfig
|
|
||||||
// with the local name here, once we've done the work elsewhere to make
|
|
||||||
// that possible.
|
|
||||||
defaultFQN := n.Addr.Resource.DefaultProvider()
|
defaultFQN := n.Addr.Resource.DefaultProvider()
|
||||||
return addrs.AbsProviderConfig{
|
return addrs.AbsProviderConfig{
|
||||||
Provider: defaultFQN,
|
Provider: defaultFQN,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/addrs"
|
||||||
"github.com/hashicorp/terraform/configs/configschema"
|
"github.com/hashicorp/terraform/configs/configschema"
|
||||||
"github.com/hashicorp/terraform/dag"
|
"github.com/hashicorp/terraform/dag"
|
||||||
)
|
)
|
||||||
|
@ -59,8 +60,17 @@ func (t *AttachSchemaTransformer) Transform(g *Graph) error {
|
||||||
mode := addr.Resource.Mode
|
mode := addr.Resource.Mode
|
||||||
typeName := addr.Resource.Type
|
typeName := addr.Resource.Type
|
||||||
providerAddr, _ := tv.ProvidedBy()
|
providerAddr, _ := tv.ProvidedBy()
|
||||||
|
var providerFqn addrs.Provider
|
||||||
|
|
||||||
schema, version := t.Schemas.ResourceTypeConfig(providerAddr.Provider, mode, typeName)
|
switch p := providerAddr.(type) {
|
||||||
|
case addrs.LocalProviderConfig:
|
||||||
|
// FIXME: need to look up the providerFQN in the config
|
||||||
|
providerFqn = addrs.NewLegacyProvider(p.LocalName)
|
||||||
|
case addrs.AbsProviderConfig:
|
||||||
|
providerFqn = p.Provider
|
||||||
|
}
|
||||||
|
|
||||||
|
schema, version := t.Schemas.ResourceTypeConfig(providerFqn, mode, typeName)
|
||||||
if schema == nil {
|
if schema == nil {
|
||||||
log.Printf("[ERROR] AttachSchemaTransformer: No resource schema available for %s", addr)
|
log.Printf("[ERROR] AttachSchemaTransformer: No resource schema available for %s", addr)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -59,7 +59,7 @@ func (n *graphNodeImportState) Name() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
func (n *graphNodeImportState) ProvidedBy() (addrs.AbsProviderConfig, bool) {
|
func (n *graphNodeImportState) ProvidedBy() (addrs.ProviderConfig, bool) {
|
||||||
// We assume that n.ProviderAddr has been properly populated here.
|
// We assume that n.ProviderAddr has been properly populated here.
|
||||||
// It's the responsibility of the code creating a graphNodeImportState
|
// It's the responsibility of the code creating a graphNodeImportState
|
||||||
// to populate this, possibly by calling DefaultProviderConfig() on the
|
// to populate this, possibly by calling DefaultProviderConfig() on the
|
||||||
|
|
|
@ -62,11 +62,12 @@ type GraphNodeCloseProvider interface {
|
||||||
// or in an ancestor module, with the resulting absolute address passed to
|
// or in an ancestor module, with the resulting absolute address passed to
|
||||||
// SetProvider.
|
// SetProvider.
|
||||||
type GraphNodeProviderConsumer interface {
|
type GraphNodeProviderConsumer interface {
|
||||||
|
GraphNodeSubPath
|
||||||
// ProvidedBy returns the address of the provider configuration the node
|
// ProvidedBy returns the address of the provider configuration the node
|
||||||
// refers to. If the returned "exact" value is true, this address will
|
// refers to. If the returned "exact" value is true, this address will
|
||||||
// be taken exactly. If "exact" is false, a provider configuration from
|
// be taken exactly. If "exact" is false, a provider configuration from
|
||||||
// an ancestor module may be selected instead.
|
// an ancestor module may be selected instead.
|
||||||
ProvidedBy() (addr addrs.AbsProviderConfig, exact bool)
|
ProvidedBy() (addr addrs.ProviderConfig, exact bool)
|
||||||
// Set the resolved provider address for this resource.
|
// Set the resolved provider address for this resource.
|
||||||
SetProvider(addrs.AbsProviderConfig)
|
SetProvider(addrs.AbsProviderConfig)
|
||||||
}
|
}
|
||||||
|
@ -110,20 +111,77 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
||||||
if pv, ok := v.(GraphNodeProviderConsumer); ok {
|
if pv, ok := v.(GraphNodeProviderConsumer); ok {
|
||||||
requested[v] = make(map[string]ProviderRequest)
|
requested[v] = make(map[string]ProviderRequest)
|
||||||
|
|
||||||
p, exact := pv.ProvidedBy()
|
providerAddr, exact := pv.ProvidedBy()
|
||||||
if exact {
|
var absPc addrs.AbsProviderConfig
|
||||||
log.Printf("[TRACE] ProviderTransformer: %s is provided by %s exactly", dag.VertexName(v), p)
|
var providerFqn addrs.Provider
|
||||||
} else {
|
|
||||||
log.Printf("[TRACE] ProviderTransformer: %s is provided by %s or inherited equivalent", dag.VertexName(v), p)
|
switch p := providerAddr.(type) {
|
||||||
|
case addrs.AbsProviderConfig:
|
||||||
|
absPc = p
|
||||||
|
// ProvidedBy() returns an AbsProviderConfig + exact == true
|
||||||
|
// when the provider configuration is set in state, so we do not
|
||||||
|
// need to verify the FQN matches.
|
||||||
|
if exact {
|
||||||
|
log.Printf("[TRACE] ProviderTransformer: %s is provided by %s exactly", dag.VertexName(v), absPc)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// if there is no config at all, the assumed default provider
|
||||||
|
// must be correct.
|
||||||
|
if t.Config == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
// If `exact` is false, an AbsProviderConfig indicates that
|
||||||
|
// ProvidedBy() returned an inferred default FQN. We must check
|
||||||
|
// if the inferred type name matches a non-default provider
|
||||||
|
// source in the config.
|
||||||
|
modConfig := t.Config.DescendentForInstance(pv.Path())
|
||||||
|
if modConfig != nil {
|
||||||
|
providerFqn = modConfig.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{
|
||||||
|
LocalName: p.Provider.Type,
|
||||||
|
})
|
||||||
|
// This is only a change to the absPc if
|
||||||
|
// ProviderForLocalConfig returns a different Provider
|
||||||
|
absPc.Provider = providerFqn
|
||||||
|
}
|
||||||
|
|
||||||
|
case addrs.LocalProviderConfig:
|
||||||
|
// ProvidedBy() return a LocalProviderConfig when the resource
|
||||||
|
// contains a `provider` attribute
|
||||||
|
modPath := pv.Path()
|
||||||
|
if t.Config == nil {
|
||||||
|
absPc.Provider = addrs.NewLegacyProvider(p.LocalName)
|
||||||
|
absPc.Module = modPath
|
||||||
|
absPc.Alias = p.Alias
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
modConfig := t.Config.DescendentForInstance(modPath)
|
||||||
|
if modConfig == nil {
|
||||||
|
absPc.Provider = addrs.NewLegacyProvider(p.LocalName)
|
||||||
|
} else {
|
||||||
|
absPc.Provider = modConfig.Module.ProviderForLocalConfig(p)
|
||||||
|
}
|
||||||
|
absPc.Module = modPath
|
||||||
|
absPc.Alias = p.Alias
|
||||||
|
|
||||||
|
default:
|
||||||
|
// This should never happen, the case statements are exhaustive
|
||||||
|
panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), absPc))
|
||||||
}
|
}
|
||||||
|
|
||||||
requested[v][p.String()] = ProviderRequest{
|
if !exact {
|
||||||
Addr: p,
|
log.Printf("[TRACE] ProviderTransformer: %s is provided by %s or inherited equivalent", dag.VertexName(v), absPc)
|
||||||
|
}
|
||||||
|
|
||||||
|
requested[v][absPc.String()] = ProviderRequest{
|
||||||
|
Addr: absPc,
|
||||||
Exact: exact,
|
Exact: exact,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Direct references need the provider configured as well as initialized
|
// Direct references need the provider configured as well as initialized
|
||||||
needConfigured[p.String()] = p
|
needConfigured[absPc.String()] = absPc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,16 +361,26 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
|
||||||
// the later proper resolution of provider inheritance done by
|
// the later proper resolution of provider inheritance done by
|
||||||
// ProviderTransformer.
|
// ProviderTransformer.
|
||||||
p, _ := pv.ProvidedBy()
|
p, _ := pv.ProvidedBy()
|
||||||
if p.Alias != "" {
|
var providerFqn addrs.Provider
|
||||||
// We do not create default aliased configurations.
|
switch p.(type) {
|
||||||
log.Println("[TRACE] MissingProviderTransformer: skipping implication of aliased config", p)
|
case addrs.LocalProviderConfig:
|
||||||
continue
|
if p.(addrs.LocalProviderConfig).Alias != "" {
|
||||||
|
// We do not create default aliased configurations.
|
||||||
|
log.Println("[TRACE] MissingProviderTransformer: skipping implication of aliased config", p)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
providerFqn = addrs.NewLegacyProvider(p.(addrs.LocalProviderConfig).LocalName)
|
||||||
|
case addrs.AbsProviderConfig:
|
||||||
|
providerFqn = p.(addrs.AbsProviderConfig).Provider
|
||||||
|
default:
|
||||||
|
// This should never happen, the case statements are exhaustive
|
||||||
|
panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), p))
|
||||||
}
|
}
|
||||||
|
|
||||||
// We're going to create an implicit _default_ configuration for the
|
// We're going to create an implicit _default_ configuration for the
|
||||||
// referenced provider type in the _root_ module, ignoring all other
|
// referenced provider type in the _root_ module, ignoring all other
|
||||||
// aspects of the resource's declared provider address.
|
// aspects of the resource's declared provider address.
|
||||||
defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(p.Provider)
|
defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(providerFqn)
|
||||||
key := defaultAddr.String()
|
key := defaultAddr.String()
|
||||||
provider := m[key]
|
provider := m[key]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue