mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
addrs: ImpliedProviderForUnqualifiedType function
This encapsulates the logic for selecting an implied FQN for an unqualified type name, which could either come from a local name used in a module without specifying an explicit source for it or from the prefix of a resource type on a resource that doesn't explicitly set "provider". This replaces the previous behavior of just directly calling NewDefaultProvider everywhere so that we can use a different implication for the local name "terraform", to refer to the built-in terraform provider rather than the stale one that's on registry.terraform.io for compatibility with other Terraform versions.
This commit is contained in:
parent
27a794062e
commit
7caf0b9246
@ -78,6 +78,30 @@ func NewProvider(hostname svchost.Hostname, namespace, typeName string) Provider
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ImpliedProviderForUnqualifiedType represents the rules for inferring what
|
||||||
|
// provider FQN a user intended when only a naked type name is available.
|
||||||
|
//
|
||||||
|
// For all except the type name "terraform" this returns a so-called "default"
|
||||||
|
// provider, which is under the registry.terraform.io/hashicorp/ namespace.
|
||||||
|
//
|
||||||
|
// As a special case, the string "terraform" maps to
|
||||||
|
// "terraform.io/builtin/terraform" because that is the more likely user
|
||||||
|
// intent than the now-unmaintained "registry.terraform.io/hashicorp/terraform"
|
||||||
|
// which remains only for compatibility with older Terraform versions.
|
||||||
|
func ImpliedProviderForUnqualifiedType(typeName string) Provider {
|
||||||
|
switch typeName {
|
||||||
|
case "terraform":
|
||||||
|
// Note for future maintainers: any additional strings we add here
|
||||||
|
// as implied to be builtin must never also be use as provider names
|
||||||
|
// in the registry.terraform.io/hashicorp/... namespace, because
|
||||||
|
// otherwise older versions of Terraform could implicitly select
|
||||||
|
// the registry name instead of the internal one.
|
||||||
|
return NewBuiltInProvider(typeName)
|
||||||
|
default:
|
||||||
|
return NewDefaultProvider(typeName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// NewDefaultProvider returns the default address of a HashiCorp-maintained,
|
// NewDefaultProvider returns the default address of a HashiCorp-maintained,
|
||||||
// Registry-hosted provider.
|
// Registry-hosted provider.
|
||||||
func NewDefaultProvider(name string) Provider {
|
func NewDefaultProvider(name string) Provider {
|
||||||
|
@ -310,7 +310,7 @@ func (c *Config) ResolveAbsProviderAddr(addr addrs.ProviderConfig, inModule addr
|
|||||||
if providerReq, exists := c.Module.ProviderRequirements[addr.LocalName]; exists {
|
if providerReq, exists := c.Module.ProviderRequirements[addr.LocalName]; exists {
|
||||||
provider = providerReq.Type
|
provider = providerReq.Type
|
||||||
} else {
|
} else {
|
||||||
provider = addrs.NewDefaultProvider(addr.LocalName)
|
provider = addrs.ImpliedProviderForUnqualifiedType(addr.LocalName)
|
||||||
}
|
}
|
||||||
|
|
||||||
return addrs.AbsProviderConfig{
|
return addrs.AbsProviderConfig{
|
||||||
|
@ -124,6 +124,7 @@ func TestConfigProviderRequirements(t *testing.T) {
|
|||||||
nullProvider := addrs.NewDefaultProvider("null")
|
nullProvider := addrs.NewDefaultProvider("null")
|
||||||
randomProvider := addrs.NewDefaultProvider("random")
|
randomProvider := addrs.NewDefaultProvider("random")
|
||||||
impliedProvider := addrs.NewDefaultProvider("implied")
|
impliedProvider := addrs.NewDefaultProvider("implied")
|
||||||
|
terraformProvider := addrs.NewBuiltInProvider("terraform")
|
||||||
|
|
||||||
got, diags := cfg.ProviderRequirements()
|
got, diags := cfg.ProviderRequirements()
|
||||||
assertNoDiagnostics(t, diags)
|
assertNoDiagnostics(t, diags)
|
||||||
@ -134,6 +135,7 @@ func TestConfigProviderRequirements(t *testing.T) {
|
|||||||
tlsProvider: getproviders.MustParseVersionConstraints("~> 3.0"),
|
tlsProvider: getproviders.MustParseVersionConstraints("~> 3.0"),
|
||||||
impliedProvider: nil,
|
impliedProvider: nil,
|
||||||
happycloudProvider: nil,
|
happycloudProvider: nil,
|
||||||
|
terraformProvider: nil,
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := cmp.Diff(want, got); diff != "" {
|
if diff := cmp.Diff(want, got); diff != "" {
|
||||||
|
@ -195,7 +195,7 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
|||||||
}
|
}
|
||||||
diags = append(diags, hclDiags...)
|
diags = append(diags, hclDiags...)
|
||||||
} else {
|
} else {
|
||||||
fqn = addrs.NewDefaultProvider(reqd.Name)
|
fqn = addrs.ImpliedProviderForUnqualifiedType(reqd.Name)
|
||||||
}
|
}
|
||||||
if existing, exists := m.ProviderRequirements[reqd.Name]; exists {
|
if existing, exists := m.ProviderRequirements[reqd.Name]; exists {
|
||||||
if existing.Type != fqn {
|
if existing.Type != fqn {
|
||||||
@ -286,11 +286,11 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
|||||||
if existing, exists := m.ProviderRequirements[r.ProviderConfigAddr().LocalName]; exists {
|
if existing, exists := m.ProviderRequirements[r.ProviderConfigAddr().LocalName]; exists {
|
||||||
r.Provider = existing.Type
|
r.Provider = existing.Type
|
||||||
} else {
|
} else {
|
||||||
r.Provider = addrs.NewDefaultProvider(r.ProviderConfigAddr().LocalName)
|
r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.ProviderConfigAddr().LocalName)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r.Provider = addrs.NewDefaultProvider(r.Addr().ImpliedProvider())
|
r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.Addr().ImpliedProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range file.DataResources {
|
for _, r := range file.DataResources {
|
||||||
@ -310,13 +310,12 @@ func (m *Module) appendFile(file *File) hcl.Diagnostics {
|
|||||||
if r.ProviderConfigRef != nil {
|
if r.ProviderConfigRef != nil {
|
||||||
if existing, exists := m.ProviderRequirements[r.ProviderConfigAddr().LocalName]; exists {
|
if existing, exists := m.ProviderRequirements[r.ProviderConfigAddr().LocalName]; exists {
|
||||||
r.Provider = existing.Type
|
r.Provider = existing.Type
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
r.Provider = addrs.NewDefaultProvider(r.ProviderConfigAddr().LocalName)
|
r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.ProviderConfigAddr().LocalName)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
r.Provider = addrs.NewDefaultProvider(r.Addr().ImpliedProvider())
|
r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.Addr().ImpliedProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
return diags
|
return diags
|
||||||
@ -511,5 +510,5 @@ func (m *Module) ProviderForLocalConfig(pc addrs.LocalProviderConfig) addrs.Prov
|
|||||||
if provider, exists := m.ProviderRequirements[pc.LocalName]; exists {
|
if provider, exists := m.ProviderRequirements[pc.LocalName]; exists {
|
||||||
return provider.Type
|
return provider.Type
|
||||||
}
|
}
|
||||||
return addrs.NewDefaultProvider(pc.LocalName)
|
return addrs.ImpliedProviderForUnqualifiedType(pc.LocalName)
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ func mergeProviderVersionConstraints(recv map[string]ProviderRequirements, ovrd
|
|||||||
// any errors parsing the source string will have already been captured.
|
// any errors parsing the source string will have already been captured.
|
||||||
fqn, _ = addrs.ParseProviderSourceString(reqd.Source.SourceStr)
|
fqn, _ = addrs.ParseProviderSourceString(reqd.Source.SourceStr)
|
||||||
} else {
|
} else {
|
||||||
fqn = addrs.NewDefaultProvider(reqd.Name)
|
fqn = addrs.ImpliedProviderForUnqualifiedType(reqd.Name)
|
||||||
}
|
}
|
||||||
recv[reqd.Name] = ProviderRequirements{Type: fqn, VersionConstraints: []VersionConstraint{reqd.Requirement}}
|
recv[reqd.Name] = ProviderRequirements{Type: fqn, VersionConstraints: []VersionConstraint{reqd.Requirement}}
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ func (r *Resource) merge(or *Resource, prs map[string]ProviderRequirements) hcl.
|
|||||||
if existing, exists := prs[or.ProviderConfigRef.Name]; exists {
|
if existing, exists := prs[or.ProviderConfigRef.Name]; exists {
|
||||||
r.Provider = existing.Type
|
r.Provider = existing.Type
|
||||||
} else {
|
} else {
|
||||||
r.Provider = addrs.NewDefaultProvider(r.ProviderConfigRef.Name)
|
r.Provider = addrs.ImpliedProviderForUnqualifiedType(r.ProviderConfigRef.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,6 +33,18 @@ func TestNewModule_provider_local_name(t *testing.T) {
|
|||||||
if localName != "nonexist" {
|
if localName != "nonexist" {
|
||||||
t.Error("wrong local name returned for a non-local provider")
|
t.Error("wrong local name returned for a non-local provider")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// can also look up the "terraform" provider and see that it sources is
|
||||||
|
// allowed to be overridden, even though there is a builtin provider
|
||||||
|
// called "terraform".
|
||||||
|
p = addrs.NewProvider(addrs.DefaultRegistryHost, "not-builtin", "not-terraform")
|
||||||
|
if name, exists := mod.ProviderLocalNames[p]; !exists {
|
||||||
|
t.Fatal("provider FQN not-builtin/not-terraform not found")
|
||||||
|
} else {
|
||||||
|
if name != "terraform" {
|
||||||
|
t.Fatalf("provider localname mismatch: got %s, want terraform", name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This test validates the provider FQNs set in each Resource
|
// This test validates the provider FQNs set in each Resource
|
||||||
|
@ -19,3 +19,10 @@ resource "implied_foo" "bar" {
|
|||||||
module "child" {
|
module "child" {
|
||||||
source = "./child"
|
source = "./child"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# There is no provider in required_providers called "terraform", but for
|
||||||
|
# this name in particular we imply terraform.io/builtin/terraform instead,
|
||||||
|
# to avoid selecting the now-unmaintained
|
||||||
|
# registry.terraform.io/hashicorp/terraform.
|
||||||
|
data "terraform_remote_state" "bar" {
|
||||||
|
}
|
||||||
|
@ -4,5 +4,8 @@ terraform {
|
|||||||
foo-test = {
|
foo-test = {
|
||||||
source = "foo/test"
|
source = "foo/test"
|
||||||
}
|
}
|
||||||
|
terraform = {
|
||||||
|
source = "not-builtin/not-terraform"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -105,7 +105,7 @@ func (c *Config) addProviderRequirements(reqs getproviders.Requirements) tfdiags
|
|||||||
fqn = addr
|
fqn = addr
|
||||||
}
|
}
|
||||||
if fqn.IsZero() {
|
if fqn.IsZero() {
|
||||||
fqn = addrs.NewDefaultProvider(localName)
|
fqn = addrs.ImpliedProviderForUnqualifiedType(localName)
|
||||||
}
|
}
|
||||||
if _, ok := reqs[fqn]; !ok {
|
if _, ok := reqs[fqn]; !ok {
|
||||||
// We'll at least have an unconstrained dependency then, but might
|
// We'll at least have an unconstrained dependency then, but might
|
||||||
|
@ -305,7 +305,7 @@ func (n *NodeAbstractResource) Provider() addrs.Provider {
|
|||||||
if n.Config != nil {
|
if n.Config != nil {
|
||||||
return n.Config.Provider
|
return n.Config.Provider
|
||||||
}
|
}
|
||||||
return addrs.NewDefaultProvider(n.Addr.Resource.ImpliedProvider())
|
return addrs.ImpliedProviderForUnqualifiedType(n.Addr.Resource.ImpliedProvider())
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeProviderConsumer
|
// GraphNodeProviderConsumer
|
||||||
|
Loading…
Reference in New Issue
Block a user