mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-29 10:21:01 -06:00
3b49028b77
In the initial move to HCL2 we started relying only on full expression evaluation to catch attribute errors, but that's not sufficient for resource attributes in practice because during validation we can't know yet whether a resource reference evaluates to a single object or to a list of objects (if count is set). To address this, here we reinstate some static validation of resource references by analyzing directly the reference objects, disregarding any instance index if present, and produce errors if the remaining subsequent traversal steps do not correspond to items within the resource type schema. This also allows us to produce some more specialized error messages for certain situations. In particular, we can recognize a reference like aws_instance.foo.count, which in 0.11 and prior was a weird special case for determining the count value of a resource block, and offer a helpful error showing the new length(aws_instance.foo) usage pattern. This eventually delegates to the static traversal validation logic that was added to the configschema package in a previous commit, which also includes some specialized error messages that distinguish between attributes and block types in the schema so that the errors relate more directly to constructs the user can see in the configuration. In future we could potentially move more of the checks from the dynamic schema construction step to the static validation step, but resources are the reference type that most needs this immediately due to the ambiguity caused by the instance indexing syntax. We can safely refactor other reference types to be statically validated in later releases. This is verified by two pre-existing context validate tests which we temporarily disabled during earlier work (now re-enabled) and also by a new validate test aimed specifically at the special case for the "count" attribute.
58 lines
2.1 KiB
Go
58 lines
2.1 KiB
Go
package lang
|
|
|
|
import (
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/tfdiags"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
type dataForTests struct {
|
|
CountAttrs map[string]cty.Value
|
|
ResourceInstances map[string]cty.Value
|
|
LocalValues map[string]cty.Value
|
|
Modules map[string]cty.Value
|
|
PathAttrs map[string]cty.Value
|
|
TerraformAttrs map[string]cty.Value
|
|
InputVariables map[string]cty.Value
|
|
}
|
|
|
|
var _ Data = &dataForTests{}
|
|
|
|
func (d *dataForTests) StaticValidateReferences(refs []*addrs.Reference, self addrs.Referenceable) tfdiags.Diagnostics {
|
|
return nil // does nothing in this stub implementation
|
|
}
|
|
|
|
func (d *dataForTests) GetCountAttr(addr addrs.CountAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.CountAttrs[addr.Name], nil
|
|
}
|
|
|
|
func (d *dataForTests) GetResourceInstance(addr addrs.ResourceInstance, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.ResourceInstances[addr.String()], nil
|
|
}
|
|
|
|
func (d *dataForTests) GetInputVariable(addr addrs.InputVariable, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.InputVariables[addr.Name], nil
|
|
}
|
|
|
|
func (d *dataForTests) GetLocalValue(addr addrs.LocalValue, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.LocalValues[addr.Name], nil
|
|
}
|
|
|
|
func (d *dataForTests) GetModuleInstance(addr addrs.ModuleCallInstance, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.Modules[addr.String()], nil
|
|
}
|
|
|
|
func (d *dataForTests) GetModuleInstanceOutput(addr addrs.ModuleCallOutput, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
// This will panic if the module object does not have the requested attribute
|
|
obj := d.Modules[addr.Call.String()]
|
|
return obj.GetAttr(addr.Name), nil
|
|
}
|
|
|
|
func (d *dataForTests) GetPathAttr(addr addrs.PathAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.PathAttrs[addr.Name], nil
|
|
}
|
|
|
|
func (d *dataForTests) GetTerraformAttr(addr addrs.TerraformAttr, rng tfdiags.SourceRange) (cty.Value, tfdiags.Diagnostics) {
|
|
return d.TerraformAttrs[addr.Name], nil
|
|
}
|