diff --git a/internal/terraform/node_resource_validate.go b/internal/terraform/node_resource_validate.go index 41c1231ca..867cfc257 100644 --- a/internal/terraform/node_resource_validate.go +++ b/internal/terraform/node_resource_validate.go @@ -46,9 +46,6 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (di diags = diags.Append(n.validateCheckRules(ctx, n.Config)) if managed := n.Config.Managed; managed != nil { - hasCount := n.Config.Count != nil - hasForEach := n.Config.ForEach != nil - // Validate all the provisioners for _, p := range managed.Provisioners { if p.Connection == nil { @@ -58,7 +55,7 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (di } // Validate Provisioner Config - diags = diags.Append(n.validateProvisioner(ctx, p, hasCount, hasForEach)) + diags = diags.Append(n.validateProvisioner(ctx, p)) if diags.HasErrors() { return diags } @@ -70,7 +67,7 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (di // validateProvisioner validates the configuration of a provisioner belonging to // a resource. The provisioner config is expected to contain the merged // connection configurations. -func (n *NodeValidatableResource) validateProvisioner(ctx EvalContext, p *configs.Provisioner, hasCount, hasForEach bool) tfdiags.Diagnostics { +func (n *NodeValidatableResource) validateProvisioner(ctx EvalContext, p *configs.Provisioner) tfdiags.Diagnostics { var diags tfdiags.Diagnostics provisioner, err := ctx.Provisioner(p.Type) @@ -91,7 +88,7 @@ func (n *NodeValidatableResource) validateProvisioner(ctx EvalContext, p *config } // Validate the provisioner's own config first - configVal, _, configDiags := n.evaluateBlock(ctx, p.Config, provisionerSchema, hasCount, hasForEach) + configVal, _, configDiags := n.evaluateBlock(ctx, p.Config, provisionerSchema) diags = diags.Append(configDiags) if configVal == cty.NilVal { @@ -115,42 +112,14 @@ func (n *NodeValidatableResource) validateProvisioner(ctx EvalContext, p *config // configuration keys that are not valid for *any* communicator, catching // typos early rather than waiting until we actually try to run one of // the resource's provisioners. - _, _, connDiags := n.evaluateBlock(ctx, p.Connection.Config, connectionBlockSupersetSchema, hasCount, hasForEach) + _, _, connDiags := n.evaluateBlock(ctx, p.Connection.Config, connectionBlockSupersetSchema) diags = diags.Append(connDiags) } return diags } -func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, schema *configschema.Block, hasCount, hasForEach bool) (cty.Value, hcl.Body, tfdiags.Diagnostics) { - keyData := EvalDataForNoInstanceKey - selfAddr := n.ResourceAddr().Resource.Instance(addrs.NoKey) - - if hasCount { - // For a resource that has count, we allow count.index but don't - // know at this stage what it will return. - keyData = InstanceKeyEvalData{ - CountIndex: cty.UnknownVal(cty.Number), - } - - // "self" can't point to an unknown key, but we'll force it to be - // key 0 here, which should return an unknown value of the - // expected type since none of these elements are known at this - // point anyway. - selfAddr = n.ResourceAddr().Resource.Instance(addrs.IntKey(0)) - } else if hasForEach { - // For a resource that has for_each, we allow each.value and each.key - // but don't know at this stage what it will return. - keyData = InstanceKeyEvalData{ - EachKey: cty.UnknownVal(cty.String), - EachValue: cty.DynamicVal, - } - - // "self" can't point to an unknown key, but we'll force it to be - // key "" here, which should return an unknown value of the - // expected type since none of these elements are known at - // this point anyway. - selfAddr = n.ResourceAddr().Resource.Instance(addrs.StringKey("")) - } +func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, schema *configschema.Block) (cty.Value, hcl.Body, tfdiags.Diagnostics) { + keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil) return ctx.EvaluateBlock(body, schema, selfAddr, keyData) } @@ -487,9 +456,7 @@ func (n *NodeValidatableResource) evaluateExpr(ctx EvalContext, expr hcl.Express return result, diags } -func (n *NodeValidatableResource) validateCheckRules(ctx EvalContext, config *configs.Resource) tfdiags.Diagnostics { - var diags tfdiags.Diagnostics - +func (n *NodeValidatableResource) stubRepetitionData(hasCount, hasForEach bool) (instances.RepetitionData, addrs.Referenceable) { keyData := EvalDataForNoInstanceKey selfAddr := n.ResourceAddr().Resource.Instance(addrs.NoKey) @@ -520,6 +487,14 @@ func (n *NodeValidatableResource) validateCheckRules(ctx EvalContext, config *co selfAddr = n.ResourceAddr().Resource.Instance(addrs.StringKey("")) } + return keyData, selfAddr +} + +func (n *NodeValidatableResource) validateCheckRules(ctx EvalContext, config *configs.Resource) tfdiags.Diagnostics { + var diags tfdiags.Diagnostics + + keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil) + for _, cr := range config.Preconditions { _, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, nil, keyData) diags = diags.Append(conditionDiags) diff --git a/internal/terraform/node_resource_validate_test.go b/internal/terraform/node_resource_validate_test.go index d0e08c730..b5b2af74c 100644 --- a/internal/terraform/node_resource_validate_test.go +++ b/internal/terraform/node_resource_validate_test.go @@ -51,7 +51,7 @@ func TestNodeValidatableResource_ValidateProvisioner_valid(t *testing.T) { }, } - diags := node.validateProvisioner(ctx, pc, false, false) + diags := node.validateProvisioner(ctx, pc) if diags.HasErrors() { t.Fatalf("node.Eval failed: %s", diags.Err()) } @@ -96,7 +96,7 @@ func TestNodeValidatableResource_ValidateProvisioner__warning(t *testing.T) { } } - diags := node.validateProvisioner(ctx, pc, false, false) + diags := node.validateProvisioner(ctx, pc) if len(diags) != 1 { t.Fatalf("wrong number of diagnostics in %s; want one warning", diags.ErrWithWarnings()) } @@ -141,7 +141,7 @@ func TestNodeValidatableResource_ValidateProvisioner__connectionInvalid(t *testi }, } - diags := node.validateProvisioner(ctx, pc, false, false) + diags := node.validateProvisioner(ctx, pc) if !diags.HasErrors() { t.Fatalf("node.Eval succeeded; want error") }