mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-11 08:32:19 -06:00
Check for duplicate types in required_providers
Adding multiple local names for the same provider type in required_providers was not prevented, which can lead to ambiguous behavior in Terraform. Providers are always indexed by the providers fully qualified name, so duplicate local names cannot be differentiated.
This commit is contained in:
parent
2f1a8bbbd8
commit
2581bc93cb
@ -158,6 +158,12 @@ func TestConfigProviderRequirements(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestConfigProviderRequirementsDuplicate(t *testing.T) {
|
||||
_, diags := testNestedModuleConfigFromDir(t, "testdata/duplicate-local-name")
|
||||
assertDiagnosticCount(t, diags, 2)
|
||||
assertDiagnosticSummary(t, diags, "Duplicate required provider")
|
||||
}
|
||||
|
||||
func TestConfigProviderRequirementsShallow(t *testing.T) {
|
||||
cfg, diags := testNestedModuleConfigFromDir(t, "testdata/provider-reqs")
|
||||
// TODO: Version Constraint Deprecation.
|
||||
|
@ -82,7 +82,54 @@ func validateProviderConfigs(parentCall *ModuleCall, cfg *Config, noProviderConf
|
||||
}
|
||||
|
||||
if mod.ProviderRequirements != nil {
|
||||
// Track all known local types too to ensure we don't have duplicated
|
||||
// with different local names.
|
||||
localTypes := map[string]bool{}
|
||||
|
||||
// check for duplicate requirements of the same type
|
||||
for _, req := range mod.ProviderRequirements.RequiredProviders {
|
||||
if localTypes[req.Type.String()] {
|
||||
// find the last declaration to give a better error
|
||||
prevDecl := ""
|
||||
for localName, typ := range localNames {
|
||||
if typ.Equals(req.Type) {
|
||||
prevDecl = localName
|
||||
}
|
||||
}
|
||||
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "Duplicate required provider",
|
||||
Detail: fmt.Sprintf(
|
||||
"Provider %s with the local name %q was previously required as %q. A provider can only be required once within required_providers.",
|
||||
req.Type.ForDisplay(), req.Name, prevDecl,
|
||||
),
|
||||
Subject: &req.DeclRange,
|
||||
})
|
||||
} else if req.Type.IsDefault() {
|
||||
// Now check for possible implied duplicates, where a provider
|
||||
// block uses a default namespaced provider, but that provider
|
||||
// was required via a different name.
|
||||
impliedLocalName := req.Type.Type
|
||||
// We have to search through the configs for a match, since the keys contains any aliases.
|
||||
for _, pc := range mod.ProviderConfigs {
|
||||
if pc.Name == impliedLocalName && req.Name != impliedLocalName {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagWarning,
|
||||
Summary: "Duplicate required provider",
|
||||
Detail: fmt.Sprintf(
|
||||
"Provider %s with the local name %q was implicitly required via a configuration block as %q. Make sure the provider configuration block name matches the name used in required_providers.",
|
||||
req.Type.ForDisplay(), req.Name, req.Type.Type,
|
||||
),
|
||||
Subject: &req.DeclRange,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
localTypes[req.Type.String()] = true
|
||||
|
||||
localNames[req.Name] = req.Type
|
||||
for _, alias := range req.Aliases {
|
||||
addr := addrs.AbsProviderConfig{
|
||||
|
16
internal/configs/testdata/duplicate-local-name/main.tf
vendored
Normal file
16
internal/configs/testdata/duplicate-local-name/main.tf
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
terraform {
|
||||
required_providers {
|
||||
test = {
|
||||
source = "hashicorp/test"
|
||||
}
|
||||
dupe = {
|
||||
source = "hashicorp/test"
|
||||
}
|
||||
other = {
|
||||
source = "hashicorp/default"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
provider "default" {
|
||||
}
|
Loading…
Reference in New Issue
Block a user