From 45671a354dca35dc6930b81b63054bbb68c3e06d Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Tue, 10 Nov 2020 15:12:45 -0500 Subject: [PATCH] configs: Fix provider lookup local name mismatch When a resource has no `provider` argument specified, its provider is derived from the implied provider type based on the resource type. For example, a `boop_instance` resource has an implied provider local name of `boop`. Correspondingly, its provider configuration is specified with a `provider "boop"` block. However, users can use the `required_providers` configuration to give a different local name to a given provider than its defined type. For example, a provider may be published at `foobar/beep`, but provide resources such as `boop_instance`. The most convenient way to use this provider is with a `required_providers` map: terraform { required_providers { boop = { source = "foobar/beep" } } } Once that local name is defined, it is used for provider configuration (a `provider "boop"` block, not `provider "beep"`). It should also be used when looking up a resource's provider configuration or provider. This commit fixes a bug with this edge case, where previously we were looking up the local provider configuration block using the resource's assigned provider type. Instead, if no provider argument is specified, we should be using the implied provider type, as that is what binds the resource to the local provider configuration. --- configs/resource.go | 6 +++++- terraform/evaluate_valid_test.go | 14 ++++++++++++++ .../static-validate-refs/static-validate-refs.tf | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/configs/resource.go b/configs/resource.go index e5cc8c606..a6946854d 100644 --- a/configs/resource.go +++ b/configs/resource.go @@ -66,8 +66,12 @@ func (r *Resource) Addr() addrs.Resource { // config addr if an explicit "provider" argument was not provided. func (r *Resource) ProviderConfigAddr() addrs.LocalProviderConfig { if r.ProviderConfigRef == nil { + // If no specific "provider" argument is given, we want to look up the + // provider config where the local name matches the implied provider + // from the resource type. This may be different from the resource's + // provider type. return addrs.LocalProviderConfig{ - LocalName: r.Provider.Type, + LocalName: r.Addr().ImpliedProvider(), } } diff --git a/terraform/evaluate_valid_test.go b/terraform/evaluate_valid_test.go index 9be7b278b..086ca3037 100644 --- a/terraform/evaluate_valid_test.go +++ b/terraform/evaluate_valid_test.go @@ -50,6 +50,14 @@ For example, to correlate with indices of a referring resource, use: aws_instance.count[count.index] - Unsupported attribute: This object has no argument, nested block, or exported attribute named "foo".`, }, + { + "boop_instance.yep", + ``, + }, + { + "boop_whatever.nope", + `Invalid resource type: A managed resource type "boop_whatever" is not supported by provider "registry.terraform.io/foobar/beep".`, + }, } cfg := testModule(t, "static-validate-refs") @@ -62,6 +70,12 @@ For example, to correlate with indices of a referring resource, use: "aws_instance": {}, }, }, + addrs.MustParseProviderSourceString("foobar/beep"): { + ResourceTypes: map[string]*configschema.Block{ + // intentional mismatch between resource type prefix and provider type + "boop_instance": {}, + }, + }, }, }, } diff --git a/terraform/testdata/static-validate-refs/static-validate-refs.tf b/terraform/testdata/static-validate-refs/static-validate-refs.tf index 9d945279c..e9f9344a8 100644 --- a/terraform/testdata/static-validate-refs/static-validate-refs.tf +++ b/terraform/testdata/static-validate-refs/static-validate-refs.tf @@ -1,6 +1,20 @@ +terraform { + required_providers { + boop = { + source = "foobar/beep" # intentional mismatch between local name and type + } + } +} + resource "aws_instance" "no_count" { } resource "aws_instance" "count" { count = 1 } + +resource "boop_instance" "yep" { +} + +resource "boop_whatever" "nope" { +}