core: Refactor stub repetition data generation

This commit is contained in:
Alisdair McDiarmid 2022-03-10 13:52:03 -05:00
parent ad995322e1
commit ef0d859af7
2 changed files with 18 additions and 43 deletions

View File

@ -46,9 +46,6 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (di
diags = diags.Append(n.validateCheckRules(ctx, n.Config)) diags = diags.Append(n.validateCheckRules(ctx, n.Config))
if managed := n.Config.Managed; managed != nil { if managed := n.Config.Managed; managed != nil {
hasCount := n.Config.Count != nil
hasForEach := n.Config.ForEach != nil
// Validate all the provisioners // Validate all the provisioners
for _, p := range managed.Provisioners { for _, p := range managed.Provisioners {
if p.Connection == nil { if p.Connection == nil {
@ -58,7 +55,7 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (di
} }
// Validate Provisioner Config // Validate Provisioner Config
diags = diags.Append(n.validateProvisioner(ctx, p, hasCount, hasForEach)) diags = diags.Append(n.validateProvisioner(ctx, p))
if diags.HasErrors() { if diags.HasErrors() {
return diags return diags
} }
@ -70,7 +67,7 @@ func (n *NodeValidatableResource) Execute(ctx EvalContext, op walkOperation) (di
// validateProvisioner validates the configuration of a provisioner belonging to // validateProvisioner validates the configuration of a provisioner belonging to
// a resource. The provisioner config is expected to contain the merged // a resource. The provisioner config is expected to contain the merged
// connection configurations. // 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 var diags tfdiags.Diagnostics
provisioner, err := ctx.Provisioner(p.Type) 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 // 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) diags = diags.Append(configDiags)
if configVal == cty.NilVal { 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 // configuration keys that are not valid for *any* communicator, catching
// typos early rather than waiting until we actually try to run one of // typos early rather than waiting until we actually try to run one of
// the resource's provisioners. // 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) diags = diags.Append(connDiags)
} }
return diags return diags
} }
func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, schema *configschema.Block, hasCount, hasForEach bool) (cty.Value, hcl.Body, tfdiags.Diagnostics) { func (n *NodeValidatableResource) evaluateBlock(ctx EvalContext, body hcl.Body, schema *configschema.Block) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
keyData := EvalDataForNoInstanceKey keyData, selfAddr := n.stubRepetitionData(n.Config.Count != nil, n.Config.ForEach != nil)
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(""))
}
return ctx.EvaluateBlock(body, schema, selfAddr, keyData) return ctx.EvaluateBlock(body, schema, selfAddr, keyData)
} }
@ -487,9 +456,7 @@ func (n *NodeValidatableResource) evaluateExpr(ctx EvalContext, expr hcl.Express
return result, diags return result, diags
} }
func (n *NodeValidatableResource) validateCheckRules(ctx EvalContext, config *configs.Resource) tfdiags.Diagnostics { func (n *NodeValidatableResource) stubRepetitionData(hasCount, hasForEach bool) (instances.RepetitionData, addrs.Referenceable) {
var diags tfdiags.Diagnostics
keyData := EvalDataForNoInstanceKey keyData := EvalDataForNoInstanceKey
selfAddr := n.ResourceAddr().Resource.Instance(addrs.NoKey) 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("")) 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 { for _, cr := range config.Preconditions {
_, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, nil, keyData) _, conditionDiags := n.evaluateExpr(ctx, cr.Condition, cty.Bool, nil, keyData)
diags = diags.Append(conditionDiags) diags = diags.Append(conditionDiags)

View File

@ -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() { if diags.HasErrors() {
t.Fatalf("node.Eval failed: %s", diags.Err()) 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 { if len(diags) != 1 {
t.Fatalf("wrong number of diagnostics in %s; want one warning", diags.ErrWithWarnings()) 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() { if !diags.HasErrors() {
t.Fatalf("node.Eval succeeded; want error") t.Fatalf("node.Eval succeeded; want error")
} }