Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

configs: Refined error messages for mismatched provider passing #30639

Merged
merged 1 commit into from Mar 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion internal/configs/config_build.go
Expand Up @@ -31,7 +31,7 @@ func BuildConfig(root *Module, walker ModuleWalker) (*Config, hcl.Diagnostics) {
cfg.resolveProviderTypes()
}

diags = append(diags, validateProviderConfigs(nil, cfg, false)...)
diags = append(diags, validateProviderConfigs(nil, cfg, nil)...)

return cfg, diags
}
Expand Down
8 changes: 4 additions & 4 deletions internal/configs/config_build_test.go
Expand Up @@ -224,7 +224,7 @@ func TestBuildConfigInvalidModules(t *testing.T) {
}

if !found {
t.Errorf("Expected error diagnostic containing %q", msg)
t.Errorf("Expected error diagnostic containing:\n %s", msg)
}
}

Expand All @@ -241,7 +241,7 @@ func TestBuildConfigInvalidModules(t *testing.T) {
}

if !found {
t.Errorf("Unexpected error: %q", diag)
t.Errorf("Unexpected error:\n %s", diag)
}
}

Expand All @@ -255,7 +255,7 @@ func TestBuildConfigInvalidModules(t *testing.T) {
}

if !found {
t.Errorf("Expected warning diagnostic containing %q", msg)
t.Errorf("Expected warning diagnostic containing:\n %s", msg)
}
}

Expand All @@ -272,7 +272,7 @@ func TestBuildConfigInvalidModules(t *testing.T) {
}

if !found {
t.Errorf("Unexpected warning: %q", diag)
t.Errorf("Unexpected warning:\n %s", diag)
}
}

Expand Down
5 changes: 5 additions & 0 deletions internal/configs/provider.go
Expand Up @@ -46,6 +46,11 @@ func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
name := block.Labels[0]
nameDiags := checkProviderNameNormalized(name, block.DefRange)
diags = append(diags, nameDiags...)
if nameDiags.HasErrors() {
// If the name is invalid then we mustn't produce a result because
// downstreams could try to use it as a provider type and then crash.
return nil, diags
}

provider := &Provider{
Name: name,
Expand Down
261 changes: 197 additions & 64 deletions internal/configs/provider_validation.go

Large diffs are not rendered by default.

@@ -1,4 +1,4 @@
empty-configs/mod/main.tf:10,1-15: Empty provider configuration blocks are not required; Remove the foo provider block from module.mod
empty-configs/mod/main.tf:13,1-15: Empty provider configuration blocks are not required; Remove the foo.bar provider block from module.mod
empty-configs/mod/main.tf:17,1-15: Empty provider configuration blocks are not required; Remove the baz provider block from module.mod.\nTo ensure the correct provider configuration is used, add baz to the required_providers configuration
empty-configs/mod/main.tf:20,1-15: Empty provider configuration blocks are not required; Remove the baz.bing provider block from module.mod. Add baz.bing to the list of configuration_aliases for baz in required_providers to define the provider configuration name
empty-configs/mod/main.tf:10,1-15: Redundant empty provider block; Earlier versions of Terraform used empty provider blocks ("proxy provider configurations") for child modules to declare their need to be passed a provider configuration by their callers. That approach was ambiguous and is now deprecated.
If you control this module, you can migrate to the new declaration syntax by removing all of the empty provider "foo" blocks and then adding or updating an entry like the following to the required_providers block of module.mod:
empty-configs/mod/main.tf:17,1-15: Redundant empty provider block; Earlier versions of Terraform used empty provider blocks ("proxy provider configurations") for child modules to declare their need to be passed a provider configuration by their callers. That approach was ambiguous and is now deprecated.
If you control this module, you can migrate to the new declaration syntax by removing all of the empty provider "baz" blocks and then adding or updating an entry like the following to the required_providers block of module.mod:
@@ -1 +1 @@
incorrect-type/main.tf:15,5-8: Invalid type for provider module.mod.provider["example.com/vendor/foo"]; Cannot use configuration from provider["registry.terraform.io/hashicorp/foo"] for module.mod.provider["example.com/vendor/foo"]
incorrect-type/main.tf:15,11-14: Provider type mismatch; The local name "foo" in the root module represents provider "hashicorp/foo", but "foo" in module.mod represents "example.com/vendor/foo".
@@ -1 +1 @@
incorrect-type/main.tf:16,5-8: Provider baz is undefined; Module module.mod does not declare a provider named baz.\nIf you wish to specify a provider configuration for the module
incorrect-type/main.tf:16,5-8: Reference to undefined provider; There is no explicit declaration for local provider name "baz" in module.mod, so Terraform is assuming you mean to pass a configuration for "hashicorp/baz".

This file was deleted.

@@ -1,3 +1 @@
Module module.child.module.child2 contains provider configuration; Providers cannot be configured within modules using count, for_each or depends_on


nested-provider/root.tf:2,11-12: Module is incompatible with count, for_each, and depends_on; The module at module.child.module.child2 is a legacy module which contains its own local provider configurations, and so calls to it may not use the count, for_each, or depends_on arguments.
@@ -1 +1 @@
override-provider/main.tf:17,5-8: Cannot override provider configuration; Provider bar is configured within the module module.mod and cannot be overridden.
override-provider/main.tf:17,5-8: Cannot override provider configuration; The configuration of module.mod has its own local configuration for bar, and so it cannot accept an overridden configuration provided by the root module.
Expand Up @@ -5,3 +5,19 @@ provider "test" {
module "mod" {
source = "./mod"
}

# FIXME: This test is for an awkward interaction that we've preserved for
# compatibility with what was arguably a bug in earlier versions: if a
# child module tries to use an inherited provider configuration explicitly by
# name then Terraform would historically use the wrong provider configuration.
#
# Since we weren't able to address that bug without breaking backward
# compatibility, instead we emit a warning to prompt the author to be explicit,
# passing in the configuration they intend to use.
#
# This case is particularly awkward because a change in the child module
# (previously referring to a provider only implicitly, but now naming it
# explicitly) can cause a required change in _this_ module (the caller),
# even though the author of the child module would've seen no explicit warning
# that they were making a breaking change. Hopefully we can improve on this
# in a future language edition.
@@ -1 +1 @@
pass-inherited-provider/mod/main.tf:15,16-20: No configuration passed in for provider test in module.mod; Provider test is referenced within module.mod, but no configuration has been supplied
pass-inherited-provider/main.tf:5,1-13: Missing required provider configuration; The configuration for module.mod expects to inherit a configuration for provider hashicorp/test with local name "test", but the root module doesn't pass a configuration under that name.
@@ -1 +1 @@
required-alias/main.tf:1,1-13: No configuration for provider foo.bar; Configuration required for module.mod.provider["registry.terraform.io/hashicorp/foo"].bar
required-alias/main.tf:1,1-13: Missing required provider configuration; The child module requires an additional configuration for provider hashicorp/foo, with the local name "foo.bar".
@@ -1,2 +1 @@
unexpected-provider/main.tf:13,5-8: Provider foo is undefined; Module module.mod does not declare a provider named foo.

unexpected-provider/main.tf:13,5-8: Reference to undefined provider; There is no explicit declaration for local provider name "foo" in module.mod, so Terraform is assuming you mean to pass a configuration for "hashicorp/foo".
@@ -1 +1 @@
unknown-root-provider/main.tf:5,11-14: Provider bar is undefined; No provider named bar has been declared in the root module
unknown-root-provider/main.tf:5,11-14: Reference to undefined provider; There is no explicit declaration for local provider name "bar" in the root module, so Terraform is assuming you mean to pass a configuration for provider "hashicorp/bar".