core: "Did you mean" hint for missing data. prefix in references

It's a relatively common mistake to try to refer to a data resource
without including the data. prefix, making Terraform understand it as a
reference to a managed resource.

To help with that case, we'll include an additonal suggestion if we can
see that there's a data resource declared with the same type and name as
in the given address.
This commit is contained in:
Martin Atkins 2021-05-14 09:58:28 -07:00
parent 3e40a9a4eb
commit 358fb54f75
3 changed files with 21 additions and 1 deletions

View File

@ -203,10 +203,21 @@ func (d *evaluationStateData) staticValidateResourceReference(modCfg *configs.Co
cfg := modCfg.Module.ResourceByAddr(addr) cfg := modCfg.Module.ResourceByAddr(addr)
if cfg == nil { if cfg == nil {
var suggestion string
// A common mistake is omitting the data. prefix when trying to refer
// to a data resource, so we'll add a special hint for that.
if addr.Mode == addrs.ManagedResourceMode {
candidateAddr := addr // not a pointer, so this is a copy
candidateAddr.Mode = addrs.DataResourceMode
if candidateCfg := modCfg.Module.ResourceByAddr(candidateAddr); candidateCfg != nil {
suggestion = fmt.Sprintf("\n\nDid you mean the data resource %s?", candidateAddr)
}
}
diags = diags.Append(&hcl.Diagnostic{ diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError, Severity: hcl.DiagError,
Summary: `Reference to undeclared resource`, Summary: `Reference to undeclared resource`,
Detail: fmt.Sprintf(`A %s resource %q %q has not been declared in %s.`, modeAdjective, addr.Type, addr.Name, moduleConfigDisplayAddr(modCfg.Path)), Detail: fmt.Sprintf(`A %s resource %q %q has not been declared in %s.%s`, modeAdjective, addr.Type, addr.Name, moduleConfigDisplayAddr(modCfg.Path), suggestion),
Subject: rng.ToHCL().Ptr(), Subject: rng.ToHCL().Ptr(),
}) })
return diags return diags

View File

@ -32,6 +32,12 @@ func TestStaticValidateReferences(t *testing.T) {
"aws_instance.nonexist", "aws_instance.nonexist",
`Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`, `Reference to undeclared resource: A managed resource "aws_instance" "nonexist" has not been declared in the root module.`,
}, },
{
"beep.boop",
`Reference to undeclared resource: A managed resource "beep" "boop" has not been declared in the root module.
Did you mean the data resource data.beep.boop?`,
},
{ {
"aws_instance.no_count[0]", "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.`, `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.`,

View File

@ -18,3 +18,6 @@ resource "boop_instance" "yep" {
resource "boop_whatever" "nope" { resource "boop_whatever" "nope" {
} }
data "beep" "boop" {
}