Mildwonkey/ps schema (#24312)
* add Config to AttachSchemaTransformer for providerFqn lookup * terraform: refactor ProvidedBy() to return nil when provider is not set in config or state
This commit is contained in:
parent
ca26efc5af
commit
c7cc0afb80
|
@ -190,20 +190,19 @@ func (c *Config) gatherProviderTypes(m map[addrs.Provider]struct{}) {
|
|||
return
|
||||
}
|
||||
|
||||
// FIXME: These are currently all assuming legacy provider addresses.
|
||||
// As part of phasing those out we'll need to change this to look up
|
||||
// the true provider addresses via the local-to-FQN mapping table
|
||||
// stored inside c.Module.
|
||||
for _, pc := range c.Module.ProviderConfigs {
|
||||
m[addrs.NewLegacyProvider(pc.Name)] = struct{}{}
|
||||
fqn := c.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: pc.Name})
|
||||
m[fqn] = struct{}{}
|
||||
}
|
||||
for _, rc := range c.Module.ManagedResources {
|
||||
providerAddr := rc.ProviderConfigAddr()
|
||||
m[addrs.NewLegacyProvider(providerAddr.LocalName)] = struct{}{}
|
||||
fqn := c.Module.ProviderForLocalConfig(providerAddr)
|
||||
m[fqn] = struct{}{}
|
||||
}
|
||||
for _, rc := range c.Module.DataResources {
|
||||
providerAddr := rc.ProviderConfigAddr()
|
||||
m[addrs.NewLegacyProvider(providerAddr.LocalName)] = struct{}{}
|
||||
fqn := c.Module.ProviderForLocalConfig(providerAddr)
|
||||
m[fqn] = struct{}{}
|
||||
}
|
||||
|
||||
// Must also visit our child modules, recursively.
|
||||
|
@ -263,5 +262,8 @@ func (c *Config) ResolveAbsProviderAddr(addr addrs.ProviderConfig, inModule addr
|
|||
// by checking for the provider in module.ProviderRequirements and falling
|
||||
// back to addrs.NewLegacyProvider if it is not found.
|
||||
func (c *Config) ProviderForConfigAddr(addr addrs.LocalProviderConfig) addrs.Provider {
|
||||
if provider, exists := c.Module.ProviderRequirements[addr.LocalName]; exists {
|
||||
return provider.Type
|
||||
}
|
||||
return c.ResolveAbsProviderAddr(addr, addrs.RootModuleInstance).Provider
|
||||
}
|
||||
|
|
|
@ -81,13 +81,7 @@ func TestConfigResolveAbsProviderAddr(t *testing.T) {
|
|||
got := cfg.ResolveAbsProviderAddr(addr, addrs.RootModuleInstance)
|
||||
want := addrs.AbsProviderConfig{
|
||||
Module: addrs.RootModuleInstance,
|
||||
// FIXME: At the time of writing we're not actually supporting
|
||||
// the explicit mapping to FQNs because we're still in
|
||||
// legacy-only mode, so this is temporarily correct. However,
|
||||
// once we are fully supporting this we should expect to see
|
||||
// the "registry.terraform.io/foo/test" FQN here, while still
|
||||
// preserving the "boop" alias.
|
||||
Provider: addrs.NewLegacyProvider("foo-test"),
|
||||
Provider: addrs.NewProvider(addrs.DefaultRegistryHost, "foo", "test"),
|
||||
Alias: "boop",
|
||||
}
|
||||
if got, want := got.String(), want.String(); got != want {
|
||||
|
|
|
@ -178,16 +178,13 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
|||
}
|
||||
|
||||
for _, reqd := range file.RequiredProviders {
|
||||
// As an interim *testing* step, we will accept a source argument
|
||||
// but assume that the source is a legacy provider. This allows us to
|
||||
// exercise the provider local names -> fqn logic without changing
|
||||
// terraform's behavior.
|
||||
var fqn addrs.Provider
|
||||
if reqd.Source != "" {
|
||||
// Fixme: once the rest of the provider source logic is implemented,
|
||||
// update this to get the addrs.Provider by using
|
||||
// addrs.ParseProviderSourceString()
|
||||
// FIXME: capture errors
|
||||
fqn, _ = addrs.ParseProviderSourceString(reqd.Source)
|
||||
} else {
|
||||
fqn = addrs.NewLegacyProvider(reqd.Name)
|
||||
}
|
||||
fqn := addrs.NewLegacyProvider(reqd.Name)
|
||||
if existing, exists := m.ProviderRequirements[reqd.Name]; exists {
|
||||
if existing.Type != fqn {
|
||||
panic("provider fqn mismatch")
|
||||
|
@ -476,7 +473,7 @@ func (m *Module) LocalNameForProvider(p addrs.Provider) string {
|
|||
|
||||
// ProviderForLocalConfig returns the provider FQN for a given LocalProviderConfig
|
||||
func (m *Module) ProviderForLocalConfig(pc addrs.LocalProviderConfig) addrs.Provider {
|
||||
if provider, exists := m.ProviderRequirements[pc.String()]; exists {
|
||||
if provider, exists := m.ProviderRequirements[pc.LocalName]; exists {
|
||||
return provider.Type
|
||||
}
|
||||
return addrs.NewLegacyProvider(pc.LocalName)
|
||||
|
|
|
@ -13,11 +13,7 @@ func TestNewModule_provider_local_name(t *testing.T) {
|
|||
t.Fatal(diags.Error())
|
||||
}
|
||||
|
||||
// FIXME: while the provider source is set to "foo/test", terraform
|
||||
// currently assumes everything is a legacy provider and the localname and
|
||||
// type match. This test will be updated when provider source is fully
|
||||
// implemented.
|
||||
p := addrs.NewLegacyProvider("foo-test")
|
||||
p := addrs.NewProvider(addrs.DefaultRegistryHost, "foo", "test")
|
||||
if name, exists := mod.ProviderLocalNames[p]; !exists {
|
||||
t.Fatal("provider FQN foo/test not found")
|
||||
} else {
|
||||
|
|
|
@ -151,7 +151,7 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
// Must attach schemas before ReferenceTransformer so that we can
|
||||
// analyze the configuration to find references.
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas},
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas, Config: b.Config},
|
||||
|
||||
// Create expansion nodes for all of the module calls. This must
|
||||
// come after all other transformers that create nodes representing
|
||||
|
|
|
@ -87,7 +87,7 @@ func (b *EvalGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
// Must attach schemas before ReferenceTransformer so that we can
|
||||
// analyze the configuration to find references.
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas},
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas, Config: b.Config},
|
||||
|
||||
// Connect so that the references are ready for targeting. We'll
|
||||
// have to connect again later for providers and so on.
|
||||
|
|
|
@ -77,7 +77,7 @@ func (b *ImportGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
// Must attach schemas before ReferenceTransformer so that we can
|
||||
// analyze the configuration to find references.
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas},
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas, Config: b.Config},
|
||||
|
||||
// Connect so that the references are ready for targeting. We'll
|
||||
// have to connect again later for providers and so on.
|
||||
|
|
|
@ -135,7 +135,7 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
// Must attach schemas before ReferenceTransformer so that we can
|
||||
// analyze the configuration to find references.
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas},
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas, Config: b.Config},
|
||||
|
||||
// Create expansion nodes for all of the module calls. This must
|
||||
// come after all other transformers that create nodes representing
|
||||
|
|
|
@ -160,7 +160,7 @@ func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
|
|||
|
||||
// Must attach schemas before ReferenceTransformer so that we can
|
||||
// analyze the configuration to find references.
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas},
|
||||
&AttachSchemaTransformer{Schemas: b.Schemas, Config: b.Config},
|
||||
|
||||
// Create expansion nodes for all of the module calls. This must
|
||||
// come after all other transformers that create nodes representing
|
||||
|
|
|
@ -295,12 +295,13 @@ func (n *NodeAbstractResource) ProvidedBy() (addrs.ProviderConfig, bool) {
|
|||
}, false
|
||||
}
|
||||
|
||||
// Use our type and containing module path to guess a provider configuration address.
|
||||
defaultFQN := n.Addr.Resource.DefaultProvider()
|
||||
return addrs.AbsProviderConfig{
|
||||
Provider: defaultFQN,
|
||||
Module: n.Addr.Module,
|
||||
}, false
|
||||
// No provider configuration found
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GraphNodeProviderConsumer
|
||||
func (n *NodeAbstractResource) ImpliedProvider() addrs.Provider {
|
||||
return n.Addr.Resource.DefaultProvider()
|
||||
}
|
||||
|
||||
// GraphNodeProviderConsumer
|
||||
|
@ -322,12 +323,13 @@ func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.ProviderConfig, bool)
|
|||
return n.ResourceState.ProviderConfig, true
|
||||
}
|
||||
|
||||
// Use our type and containing module path to guess a provider configuration address
|
||||
defaultFQN := n.Addr.Resource.DefaultProvider()
|
||||
return addrs.AbsProviderConfig{
|
||||
Provider: defaultFQN,
|
||||
Module: n.Addr.Module,
|
||||
}, false
|
||||
// No provider configuration found
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// GraphNodeProviderConsumer
|
||||
func (n *NodeAbstractResourceInstance) ImpliedProvider() addrs.Provider {
|
||||
return n.Addr.Resource.DefaultProvider()
|
||||
}
|
||||
|
||||
// GraphNodeProvisionerConsumer
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/dag"
|
||||
)
|
||||
|
@ -44,6 +45,7 @@ type GraphNodeAttachProvisionerSchema interface {
|
|||
// and then passes them to a method implemented by the node.
|
||||
type AttachSchemaTransformer struct {
|
||||
Schemas *Schemas
|
||||
Config *configs.Config
|
||||
}
|
||||
|
||||
func (t *AttachSchemaTransformer) Transform(g *Graph) error {
|
||||
|
@ -60,14 +62,27 @@ func (t *AttachSchemaTransformer) Transform(g *Graph) error {
|
|||
mode := addr.Resource.Mode
|
||||
typeName := addr.Resource.Type
|
||||
providerAddr, _ := tv.ProvidedBy()
|
||||
var providerFqn addrs.Provider
|
||||
|
||||
var providerFqn addrs.Provider
|
||||
switch p := providerAddr.(type) {
|
||||
case addrs.LocalProviderConfig:
|
||||
// FIXME: need to look up the providerFQN in the config
|
||||
if t.Config == nil {
|
||||
providerFqn = addrs.NewLegacyProvider(p.LocalName)
|
||||
} else {
|
||||
modConfig := t.Config.DescendentForInstance(tv.Path())
|
||||
if modConfig == nil {
|
||||
providerFqn = addrs.NewLegacyProvider(p.LocalName)
|
||||
} else {
|
||||
providerFqn = modConfig.Module.ProviderForLocalConfig(addrs.LocalProviderConfig{LocalName: p.LocalName})
|
||||
}
|
||||
}
|
||||
case addrs.AbsProviderConfig:
|
||||
providerFqn = p.Provider
|
||||
case nil:
|
||||
providerFqn = tv.ImpliedProvider()
|
||||
default:
|
||||
// This should never happen; the case statements are meant to be exhaustive
|
||||
panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), addr))
|
||||
}
|
||||
|
||||
schema, version := t.Schemas.ResourceTypeConfig(providerFqn, mode, typeName)
|
||||
|
|
|
@ -68,6 +68,16 @@ func (n *graphNodeImportState) ProvidedBy() (addrs.ProviderConfig, bool) {
|
|||
return n.ProviderAddr, false
|
||||
}
|
||||
|
||||
// GraphNodeProviderConsumer
|
||||
func (n *graphNodeImportState) ImpliedProvider() addrs.Provider {
|
||||
// We assume that n.ProviderAddr has been properly populated here.
|
||||
// It's the responsibility of the code creating a graphNodeImportState
|
||||
// to populate this, possibly by calling DefaultProviderConfig() on the
|
||||
// resource address to infer an implied provider from the resource type
|
||||
// name.
|
||||
return n.ProviderAddr.Provider
|
||||
}
|
||||
|
||||
// GraphNodeProviderConsumer
|
||||
func (n *graphNodeImportState) SetProvider(addr addrs.AbsProviderConfig) {
|
||||
n.ResolvedProvider = addr
|
||||
|
|
|
@ -21,6 +21,7 @@ func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, c
|
|||
},
|
||||
// Add any remaining missing providers
|
||||
&MissingProviderTransformer{
|
||||
Config: config,
|
||||
Providers: providers,
|
||||
Concrete: concrete,
|
||||
},
|
||||
|
@ -64,10 +65,20 @@ type GraphNodeCloseProvider interface {
|
|||
type GraphNodeProviderConsumer interface {
|
||||
GraphNodeSubPath
|
||||
// ProvidedBy returns the address of the provider configuration the node
|
||||
// refers to. If the returned "exact" value is true, this address will
|
||||
// be taken exactly. If "exact" is false, a provider configuration from
|
||||
// an ancestor module may be selected instead.
|
||||
// refers to, if available. The following value types may be returned:
|
||||
//
|
||||
// * addrs.LocalProviderConfig: the provider was set in the resource config
|
||||
// * addrs.AbsProviderConfig: the provider configuration was taken from the
|
||||
// instance state.
|
||||
// * nil: provider was not set in config or state. It is the caller's
|
||||
// responsibility to determine the implied default provider (see ImpliedProvider())
|
||||
ProvidedBy() (addr addrs.ProviderConfig, exact bool)
|
||||
|
||||
// ImpliedProvider returns the provider FQN implied by the resource type
|
||||
// name (for eg the "null" in "null_resource"). This should be used when
|
||||
// ProvidedBy() returns nil.
|
||||
ImpliedProvider() (addrs addrs.Provider)
|
||||
|
||||
// Set the resolved provider address for this resource.
|
||||
SetProvider(addrs.AbsProviderConfig)
|
||||
}
|
||||
|
@ -113,37 +124,16 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
|||
|
||||
providerAddr, exact := pv.ProvidedBy()
|
||||
var absPc addrs.AbsProviderConfig
|
||||
var providerFqn addrs.Provider
|
||||
|
||||
switch p := providerAddr.(type) {
|
||||
case addrs.AbsProviderConfig:
|
||||
// ProvidedBy() returns an AbsProviderConfig when the provider
|
||||
// configuration is set in state, so we do not need to verify
|
||||
// the FQN matches.
|
||||
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:
|
||||
|
@ -166,13 +156,15 @@ func (t *ProviderTransformer) Transform(g *Graph) error {
|
|||
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))
|
||||
}
|
||||
|
||||
if !exact {
|
||||
case nil:
|
||||
// No provider found in config or state; fall back to implied default provider.
|
||||
absPc.Provider = pv.ImpliedProvider()
|
||||
absPc.Module = pv.Path()
|
||||
log.Printf("[TRACE] ProviderTransformer: %s is provided by %s or inherited equivalent", dag.VertexName(v), absPc)
|
||||
|
||||
default:
|
||||
// This should never happen; the case statements are meant to be exhaustive
|
||||
panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), absPc))
|
||||
}
|
||||
|
||||
requested[v][absPc.String()] = ProviderRequest{
|
||||
|
@ -328,6 +320,9 @@ type MissingProviderTransformer struct {
|
|||
// Providers is the list of providers we support.
|
||||
Providers []string
|
||||
|
||||
// MissingProviderTransformer needs the config to rule out _implied_ default providers
|
||||
Config *configs.Config
|
||||
|
||||
// Concrete, if set, overrides how the providers are made.
|
||||
Concrete ConcreteProviderNodeFunc
|
||||
}
|
||||
|
@ -360,18 +355,28 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error {
|
|||
// it's safe for us to rely on ProvidedBy here rather than waiting for
|
||||
// the later proper resolution of provider inheritance done by
|
||||
// ProviderTransformer.
|
||||
p, _ := pv.ProvidedBy()
|
||||
providerAddr, _ := pv.ProvidedBy()
|
||||
var providerFqn addrs.Provider
|
||||
switch p.(type) {
|
||||
switch p := providerAddr.(type) {
|
||||
case addrs.LocalProviderConfig:
|
||||
if p.(addrs.LocalProviderConfig).Alias != "" {
|
||||
if p.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)
|
||||
modConfig := t.Config.DescendentForInstance(pv.Path())
|
||||
if modConfig == nil {
|
||||
providerFqn = addrs.NewLegacyProvider(p.LocalName)
|
||||
} else {
|
||||
providerFqn = modConfig.Module.ProviderForLocalConfig(p)
|
||||
}
|
||||
|
||||
case addrs.AbsProviderConfig:
|
||||
providerFqn = p.(addrs.AbsProviderConfig).Provider
|
||||
providerFqn = p.Provider
|
||||
|
||||
case nil:
|
||||
providerFqn = pv.ImpliedProvider()
|
||||
|
||||
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))
|
||||
|
|
Loading…
Reference in New Issue