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.
This commit is contained in:
Alisdair McDiarmid 2020-11-10 15:12:45 -05:00
parent 7c98be92c2
commit 45671a354d
3 changed files with 33 additions and 1 deletions

View File

@ -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(),
}
}

View File

@ -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": {},
},
},
},
},
}

View File

@ -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" {
}