mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-27 09:21:14 -06:00
45671a354d
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.
118 lines
3.1 KiB
Go
118 lines
3.1 KiB
Go
package terraform
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/hclsyntax"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/configs/configschema"
|
|
"github.com/hashicorp/terraform/lang"
|
|
)
|
|
|
|
func TestStaticValidateReferences(t *testing.T) {
|
|
tests := []struct {
|
|
Ref string
|
|
WantErr string
|
|
}{
|
|
{
|
|
"aws_instance.no_count",
|
|
``,
|
|
},
|
|
{
|
|
"aws_instance.count",
|
|
``,
|
|
},
|
|
{
|
|
"aws_instance.count[0]",
|
|
``,
|
|
},
|
|
{
|
|
"aws_instance.nonexist",
|
|
`Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`,
|
|
},
|
|
{
|
|
"aws_instance.no_count[0]",
|
|
`Unexpected resource instance key: Because aws_instance.no_count does not have "count" or "for_each" set, references to it must not include an index key. Remove the bracketed index to refer to the single instance of this resource.`,
|
|
},
|
|
{
|
|
"aws_instance.count.foo",
|
|
// In this case we return two errors that are somewhat redundant with
|
|
// one another, but we'll accept that because they both report the
|
|
// problem from different perspectives and so give the user more
|
|
// opportunity to understand what's going on here.
|
|
`2 problems:
|
|
|
|
- Missing resource instance key: Because aws_instance.count has "count" set, its attributes must be accessed on specific instances.
|
|
|
|
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")
|
|
evaluator := &Evaluator{
|
|
Config: cfg,
|
|
Schemas: &Schemas{
|
|
Providers: map[addrs.Provider]*ProviderSchema{
|
|
addrs.NewDefaultProvider("aws"): {
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
"aws_instance": {},
|
|
},
|
|
},
|
|
addrs.MustParseProviderSourceString("foobar/beep"): {
|
|
ResourceTypes: map[string]*configschema.Block{
|
|
// intentional mismatch between resource type prefix and provider type
|
|
"boop_instance": {},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.Ref, func(t *testing.T) {
|
|
traversal, hclDiags := hclsyntax.ParseTraversalAbs([]byte(test.Ref), "", hcl.Pos{Line: 1, Column: 1})
|
|
if hclDiags.HasErrors() {
|
|
t.Fatal(hclDiags.Error())
|
|
}
|
|
|
|
refs, diags := lang.References([]hcl.Traversal{traversal})
|
|
if diags.HasErrors() {
|
|
t.Fatal(diags.Err())
|
|
}
|
|
|
|
data := &evaluationStateData{
|
|
Evaluator: evaluator,
|
|
}
|
|
|
|
diags = data.StaticValidateReferences(refs, nil)
|
|
if diags.HasErrors() {
|
|
if test.WantErr == "" {
|
|
t.Fatalf("Unexpected diagnostics: %s", diags.Err())
|
|
}
|
|
|
|
gotErr := diags.Err().Error()
|
|
if gotErr != test.WantErr {
|
|
t.Fatalf("Wrong diagnostics\ngot: %s\nwant: %s", gotErr, test.WantErr)
|
|
}
|
|
return
|
|
}
|
|
|
|
if test.WantErr != "" {
|
|
t.Fatalf("Expected diagnostics, but got none\nwant: %s", test.WantErr)
|
|
}
|
|
})
|
|
}
|
|
}
|