mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
core: Handle count.index evaluation more explicitly
Previously we had the evaluate methods accept directly an addrs.InstanceKey and had our evaluator infer a suitable value for count.index for it, but that prevents us from setting the index to be unknown in the validation scenario where we may not be able to predict the number of instances yet but we still want to be able to check that the configuration block is type-safe for all possible count values. To achieve this, we separate the concern of deciding on a value for count.index from the concern of evaluating it, which then allows for other implementations of this in future. For the purpose of this commit there is no change in behavior, with the count.index value being populated whenever the instance key is a number. This commit does a little more groundwork for the future implementation of the for_each feature (which'll support each.key and each.value) but still doesn't yet implement it, leaving it just stubbed out for the moment.
This commit is contained in:
parent
eac8779870
commit
fd371d838d
@ -416,7 +416,7 @@ func (c *Context) Eval(path addrs.ModuleInstance) (*lang.Scope, tfdiags.Diagnost
|
|||||||
// caches its contexts, so we should get hold of the context that was
|
// caches its contexts, so we should get hold of the context that was
|
||||||
// previously used for evaluation here, unless we skipped walking.
|
// previously used for evaluation here, unless we skipped walking.
|
||||||
evalCtx := walker.EnterPath(path)
|
evalCtx := walker.EnterPath(path)
|
||||||
return evalCtx.EvaluationScope(nil, addrs.NoKey), diags
|
return evalCtx.EvaluationScope(nil, EvalDataForNoInstanceKey), diags
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interpolater is no longer used. Use Evaluator instead.
|
// Interpolater is no longer used. Use Evaluator instead.
|
||||||
|
@ -313,13 +313,15 @@ func (n *EvalApplyProvisioners) apply(ctx EvalContext, provs []*configs.Provisio
|
|||||||
provisioner := ctx.Provisioner(prov.Type)
|
provisioner := ctx.Provisioner(prov.Type)
|
||||||
schema := ctx.ProvisionerSchema(prov.Type)
|
schema := ctx.ProvisionerSchema(prov.Type)
|
||||||
|
|
||||||
|
keyData := EvalDataForInstanceKey(instanceAddr.Key)
|
||||||
|
|
||||||
// Evaluate the main provisioner configuration.
|
// Evaluate the main provisioner configuration.
|
||||||
config, _, configDiags := ctx.EvaluateBlock(prov.Config, schema, instanceAddr, instanceAddr.Key)
|
config, _, configDiags := ctx.EvaluateBlock(prov.Config, schema, instanceAddr, keyData)
|
||||||
diags = diags.Append(configDiags)
|
diags = diags.Append(configDiags)
|
||||||
|
|
||||||
// A provisioner may not have a connection block
|
// A provisioner may not have a connection block
|
||||||
if prov.Connection != nil {
|
if prov.Connection != nil {
|
||||||
connInfo, _, connInfoDiags := ctx.EvaluateBlock(prov.Connection.Config, connectionBlockSupersetSchema, instanceAddr, instanceAddr.Key)
|
connInfo, _, connInfoDiags := ctx.EvaluateBlock(prov.Connection.Config, connectionBlockSupersetSchema, instanceAddr, keyData)
|
||||||
diags = diags.Append(connInfoDiags)
|
diags = diags.Append(connInfoDiags)
|
||||||
|
|
||||||
if configDiags.HasErrors() || connInfoDiags.HasErrors() {
|
if configDiags.HasErrors() || connInfoDiags.HasErrors() {
|
||||||
|
@ -100,7 +100,7 @@ type EvalContext interface {
|
|||||||
// "dynamic" blocks replaced with zero or more static blocks. This can be
|
// "dynamic" blocks replaced with zero or more static blocks. This can be
|
||||||
// used to extract correct source location information about attributes of
|
// used to extract correct source location information about attributes of
|
||||||
// the returned object value.
|
// the returned object value.
|
||||||
EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, key addrs.InstanceKey) (cty.Value, hcl.Body, tfdiags.Diagnostics)
|
EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics)
|
||||||
|
|
||||||
// EvaluateExpr takes the given HCL expression and evaluates it to produce
|
// EvaluateExpr takes the given HCL expression and evaluates it to produce
|
||||||
// a value.
|
// a value.
|
||||||
@ -112,7 +112,7 @@ type EvalContext interface {
|
|||||||
|
|
||||||
// EvaluationScope returns a scope that can be used to evaluate reference
|
// EvaluationScope returns a scope that can be used to evaluate reference
|
||||||
// addresses in this context.
|
// addresses in this context.
|
||||||
EvaluationScope(self addrs.Referenceable, key addrs.InstanceKey) *lang.Scope
|
EvaluationScope(self addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope
|
||||||
|
|
||||||
// SetModuleCallArguments defines values for the variables of a particular
|
// SetModuleCallArguments defines values for the variables of a particular
|
||||||
// child module call.
|
// child module call.
|
||||||
|
@ -271,9 +271,9 @@ func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, key addrs.InstanceKey) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
|
func (ctx *BuiltinEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
scope := ctx.EvaluationScope(self, key)
|
scope := ctx.EvaluationScope(self, keyData)
|
||||||
body, evalDiags := scope.ExpandBlock(body, schema)
|
body, evalDiags := scope.ExpandBlock(body, schema)
|
||||||
diags = diags.Append(evalDiags)
|
diags = diags.Append(evalDiags)
|
||||||
val, evalDiags := scope.EvalBlock(body, schema)
|
val, evalDiags := scope.EvalBlock(body, schema)
|
||||||
@ -282,15 +282,15 @@ func (ctx *BuiltinEvalContext) EvaluateBlock(body hcl.Body, schema *configschema
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) {
|
func (ctx *BuiltinEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) {
|
||||||
scope := ctx.EvaluationScope(self, addrs.NoKey)
|
scope := ctx.EvaluationScope(self, EvalDataForNoInstanceKey)
|
||||||
return scope.EvalExpr(expr, wantType)
|
return scope.EvalExpr(expr, wantType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, key addrs.InstanceKey) *lang.Scope {
|
func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope {
|
||||||
data := &evaluationStateData{
|
data := &evaluationStateData{
|
||||||
Evaluator: ctx.Evaluator,
|
Evaluator: ctx.Evaluator,
|
||||||
ModulePath: ctx.PathValue,
|
ModulePath: ctx.PathValue,
|
||||||
InstanceKey: key,
|
InstanceKeyData: keyData,
|
||||||
}
|
}
|
||||||
return ctx.Evaluator.Scope(data, self)
|
return ctx.Evaluator.Scope(data, self)
|
||||||
}
|
}
|
||||||
|
@ -80,12 +80,12 @@ type MockEvalContext struct {
|
|||||||
EvaluateBlockBody hcl.Body
|
EvaluateBlockBody hcl.Body
|
||||||
EvaluateBlockSchema *configschema.Block
|
EvaluateBlockSchema *configschema.Block
|
||||||
EvaluateBlockSelf addrs.Referenceable
|
EvaluateBlockSelf addrs.Referenceable
|
||||||
EvaluateBlockKey addrs.InstanceKey
|
EvaluateBlockKeyData InstanceKeyEvalData
|
||||||
EvaluateBlockResultFunc func(
|
EvaluateBlockResultFunc func(
|
||||||
body hcl.Body,
|
body hcl.Body,
|
||||||
schema *configschema.Block,
|
schema *configschema.Block,
|
||||||
self addrs.Referenceable,
|
self addrs.Referenceable,
|
||||||
key addrs.InstanceKey,
|
keyData InstanceKeyEvalData,
|
||||||
) (cty.Value, hcl.Body, tfdiags.Diagnostics) // overrides the other values below, if set
|
) (cty.Value, hcl.Body, tfdiags.Diagnostics) // overrides the other values below, if set
|
||||||
EvaluateBlockResult cty.Value
|
EvaluateBlockResult cty.Value
|
||||||
EvaluateBlockExpandedBody hcl.Body
|
EvaluateBlockExpandedBody hcl.Body
|
||||||
@ -103,10 +103,10 @@ type MockEvalContext struct {
|
|||||||
EvaluateExprResult cty.Value
|
EvaluateExprResult cty.Value
|
||||||
EvaluateExprDiags tfdiags.Diagnostics
|
EvaluateExprDiags tfdiags.Diagnostics
|
||||||
|
|
||||||
EvaluationScopeCalled bool
|
EvaluationScopeCalled bool
|
||||||
EvaluationScopeSelf addrs.Referenceable
|
EvaluationScopeSelf addrs.Referenceable
|
||||||
EvaluationScopeKey addrs.InstanceKey
|
EvaluationScopeKeyData InstanceKeyEvalData
|
||||||
EvaluationScopeScope *lang.Scope
|
EvaluationScopeScope *lang.Scope
|
||||||
|
|
||||||
InterpolateCalled bool
|
InterpolateCalled bool
|
||||||
InterpolateConfig *config.RawConfig
|
InterpolateConfig *config.RawConfig
|
||||||
@ -228,14 +228,14 @@ func (c *MockEvalContext) CloseProvisioner(n string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, key addrs.InstanceKey) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
|
func (c *MockEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
|
||||||
c.EvaluateBlockCalled = true
|
c.EvaluateBlockCalled = true
|
||||||
c.EvaluateBlockBody = body
|
c.EvaluateBlockBody = body
|
||||||
c.EvaluateBlockSchema = schema
|
c.EvaluateBlockSchema = schema
|
||||||
c.EvaluateBlockSelf = self
|
c.EvaluateBlockSelf = self
|
||||||
c.EvaluateBlockKey = key
|
c.EvaluateBlockKeyData = keyData
|
||||||
if c.EvaluateBlockResultFunc != nil {
|
if c.EvaluateBlockResultFunc != nil {
|
||||||
return c.EvaluateBlockResultFunc(body, schema, self, key)
|
return c.EvaluateBlockResultFunc(body, schema, self, keyData)
|
||||||
}
|
}
|
||||||
return c.EvaluateBlockResult, c.EvaluateBlockExpandedBody, c.EvaluateBlockDiags
|
return c.EvaluateBlockResult, c.EvaluateBlockExpandedBody, c.EvaluateBlockDiags
|
||||||
}
|
}
|
||||||
@ -261,7 +261,7 @@ func (c *MockEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, s
|
|||||||
// This function overwrites any existing functions installed in fields
|
// This function overwrites any existing functions installed in fields
|
||||||
// EvaluateBlockResultFunc and EvaluateExprResultFunc.
|
// EvaluateBlockResultFunc and EvaluateExprResultFunc.
|
||||||
func (c *MockEvalContext) installSimpleEval() {
|
func (c *MockEvalContext) installSimpleEval() {
|
||||||
c.EvaluateBlockResultFunc = func(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, key addrs.InstanceKey) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
|
c.EvaluateBlockResultFunc = func(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) {
|
||||||
if scope := c.EvaluationScopeScope; scope != nil {
|
if scope := c.EvaluationScopeScope; scope != nil {
|
||||||
// Fully-functional codepath.
|
// Fully-functional codepath.
|
||||||
var diags tfdiags.Diagnostics
|
var diags tfdiags.Diagnostics
|
||||||
@ -304,10 +304,10 @@ func (c *MockEvalContext) installSimpleEval() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockEvalContext) EvaluationScope(self addrs.Referenceable, key addrs.InstanceKey) *lang.Scope {
|
func (c *MockEvalContext) EvaluationScope(self addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope {
|
||||||
c.EvaluationScopeCalled = true
|
c.EvaluationScopeCalled = true
|
||||||
c.EvaluationScopeSelf = self
|
c.EvaluationScopeSelf = self
|
||||||
c.EvaluationScopeKey = key
|
c.EvaluationScopeKeyData = keyData
|
||||||
return c.EvaluationScopeScope
|
return c.EvaluationScopeScope
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,8 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
// Should be caught during validation, so we don't bother with a pretty error here
|
// Should be caught during validation, so we don't bother with a pretty error here
|
||||||
return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
|
return nil, fmt.Errorf("provider does not support resource type %q", n.Addr.Resource.Type)
|
||||||
}
|
}
|
||||||
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, n.Addr.Key)
|
keyData := EvalDataForInstanceKey(n.Addr.Key)
|
||||||
|
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, nil, keyData)
|
||||||
diags = diags.Append(configDiags)
|
diags = diags.Append(configDiags)
|
||||||
if configDiags.HasErrors() {
|
if configDiags.HasErrors() {
|
||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
|
@ -26,7 +26,7 @@ type EvalConfigBlock struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *EvalConfigBlock) Eval(ctx EvalContext) (interface{}, error) {
|
func (n *EvalConfigBlock) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
val, body, diags := ctx.EvaluateBlock(*n.Config, n.Schema, n.SelfAddr, addrs.NoKey)
|
val, body, diags := ctx.EvaluateBlock(*n.Config, n.Schema, n.SelfAddr, EvalDataForNoInstanceKey)
|
||||||
if diags.HasErrors() && n.ContinueOnErr {
|
if diags.HasErrors() && n.ContinueOnErr {
|
||||||
log.Printf("[WARN] Block evaluation failed: %s", diags.Err())
|
log.Printf("[WARN] Block evaluation failed: %s", diags.Err())
|
||||||
return nil, EvalEarlyExitError{}
|
return nil, EvalEarlyExitError{}
|
||||||
|
@ -74,7 +74,7 @@ func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configSchema := schema.Provider
|
configSchema := schema.Provider
|
||||||
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, addrs.NoKey)
|
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
|
||||||
diags = diags.Append(evalDiags)
|
diags = diags.Append(evalDiags)
|
||||||
if evalDiags.HasErrors() {
|
if evalDiags.HasErrors() {
|
||||||
return nil, diags.NonFatalErr()
|
return nil, diags.NonFatalErr()
|
||||||
|
@ -63,8 +63,10 @@ func (n *EvalReadDataDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
return nil, fmt.Errorf("provider does not support data source %q", n.Addr.Resource.Type)
|
return nil, fmt.Errorf("provider does not support data source %q", n.Addr.Resource.Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyData := EvalDataForInstanceKey(n.Addr.Key)
|
||||||
|
|
||||||
var configDiags tfdiags.Diagnostics
|
var configDiags tfdiags.Diagnostics
|
||||||
configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, n.Addr.Key)
|
configVal, _, configDiags = ctx.EvaluateBlock(config.Config, schema, nil, keyData)
|
||||||
diags = diags.Append(configDiags)
|
diags = diags.Append(configDiags)
|
||||||
if configDiags.HasErrors() {
|
if configDiags.HasErrors() {
|
||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
|
@ -92,7 +92,7 @@ func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
configSchema = &configschema.Block{}
|
configSchema = &configschema.Block{}
|
||||||
}
|
}
|
||||||
|
|
||||||
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, addrs.NoKey)
|
configVal, configBody, evalDiags := ctx.EvaluateBlock(configBody, configSchema, nil, EvalDataForNoInstanceKey)
|
||||||
diags = diags.Append(evalDiags)
|
diags = diags.Append(evalDiags)
|
||||||
if evalDiags.HasErrors() {
|
if evalDiags.HasErrors() {
|
||||||
return nil, diags.NonFatalErr()
|
return nil, diags.NonFatalErr()
|
||||||
@ -142,7 +142,9 @@ func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
{
|
{
|
||||||
// Validate the provisioner's own config first
|
// Validate the provisioner's own config first
|
||||||
|
|
||||||
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, n.ResourceAddr, n.ResourceAddr.Key)
|
keyData := EvalDataForInstanceKey(n.ResourceAddr.Key)
|
||||||
|
|
||||||
|
configVal, _, configDiags := ctx.EvaluateBlock(config.Config, schema, n.ResourceAddr, keyData)
|
||||||
diags = diags.Append(configDiags)
|
diags = diags.Append(configDiags)
|
||||||
if configDiags.HasErrors() {
|
if configDiags.HasErrors() {
|
||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
@ -197,10 +199,12 @@ func (n *EvalValidateProvisioner) validateConnConfig(ctx EvalContext, config *co
|
|||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
keyData := EvalDataForInstanceKey(n.ResourceAddr.Key)
|
||||||
|
|
||||||
// We evaluate here just by evaluating the block and returning any
|
// We evaluate here just by evaluating the block and returning any
|
||||||
// diagnostics we get, since evaluation alone is enough to check for
|
// diagnostics we get, since evaluation alone is enough to check for
|
||||||
// extraneous arguments and incorrectly-typed arguments.
|
// extraneous arguments and incorrectly-typed arguments.
|
||||||
_, _, configDiags := ctx.EvaluateBlock(config.Config, connectionBlockSupersetSchema, self, n.ResourceAddr.Key)
|
_, _, configDiags := ctx.EvaluateBlock(config.Config, connectionBlockSupersetSchema, self, keyData)
|
||||||
diags = diags.Append(configDiags)
|
diags = diags.Append(configDiags)
|
||||||
|
|
||||||
return diags
|
return diags
|
||||||
@ -361,7 +365,9 @@ func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, n.Addr.Key)
|
keyData := EvalDataForInstanceKey(n.Addr.Key)
|
||||||
|
|
||||||
|
configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, keyData)
|
||||||
diags = diags.Append(valDiags)
|
diags = diags.Append(valDiags)
|
||||||
if valDiags.HasErrors() {
|
if valDiags.HasErrors() {
|
||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
@ -388,7 +394,9 @@ func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
|
|||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, n.Addr.Key)
|
keyData := EvalDataForInstanceKey(n.Addr.Key)
|
||||||
|
|
||||||
|
configVal, _, valDiags := ctx.EvaluateBlock(cfg.Config, schema, nil, keyData)
|
||||||
diags = diags.Append(valDiags)
|
diags = diags.Append(valDiags)
|
||||||
if valDiags.HasErrors() {
|
if valDiags.HasErrors() {
|
||||||
return nil, diags.Err()
|
return nil, diags.Err()
|
||||||
|
@ -83,11 +83,58 @@ type evaluationStateData struct {
|
|||||||
// that references will be resolved relative to.
|
// that references will be resolved relative to.
|
||||||
ModulePath addrs.ModuleInstance
|
ModulePath addrs.ModuleInstance
|
||||||
|
|
||||||
// InstanceKey is the instance key for the object being evaluated, if any.
|
// InstanceKeyData describes the values, if any, that are accessible due
|
||||||
// Set to addrs.NoKey if no object repetition is in progress.
|
// to repetition of a containing object using "count" or "for_each"
|
||||||
InstanceKey addrs.InstanceKey
|
// arguments. (It is _not_ used for the for_each inside "dynamic" blocks,
|
||||||
|
// since the user specifies in that case which variable name to locally
|
||||||
|
// shadow.)
|
||||||
|
InstanceKeyData InstanceKeyEvalData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InstanceKeyEvalData is used during evaluation to specify which values,
|
||||||
|
// if any, should be produced for count.index, each.key, and each.value.
|
||||||
|
type InstanceKeyEvalData struct {
|
||||||
|
// CountIndex is the value for count.index, or cty.NilVal if evaluating
|
||||||
|
// in a context where the "count" argument is not active.
|
||||||
|
//
|
||||||
|
// For correct operation, this should always be of type cty.Number if not
|
||||||
|
// nil.
|
||||||
|
CountIndex cty.Value
|
||||||
|
|
||||||
|
// EachKey and EachValue are the values for each.key and each.value
|
||||||
|
// respectively, or cty.NilVal if evaluating in a context where the
|
||||||
|
// "for_each" argument is not active. These must either both be set
|
||||||
|
// or neither set.
|
||||||
|
//
|
||||||
|
// For correct operation, EachKey must always be either of type cty.String
|
||||||
|
// or cty.Number if not nil.
|
||||||
|
EachKey, EachValue cty.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
// EvalDataForInstanceKey constructs a suitable InstanceKeyEvalData for
|
||||||
|
// evaluating in a context that has the given instance key.
|
||||||
|
func EvalDataForInstanceKey(key addrs.InstanceKey) InstanceKeyEvalData {
|
||||||
|
// At the moment we don't actually implement for_each, so we only
|
||||||
|
// ever populate CountIndex.
|
||||||
|
// (When we implement for_each later we may need to reorganize this some,
|
||||||
|
// so that we can resolve the ambiguity that an int key may either be
|
||||||
|
// a count.index or an each.key where for_each is over a list.)
|
||||||
|
|
||||||
|
var countIdx cty.Value
|
||||||
|
if intKey, ok := key.(addrs.IntKey); ok {
|
||||||
|
countIdx = cty.NumberIntVal(int64(intKey))
|
||||||
|
}
|
||||||
|
|
||||||
|
return InstanceKeyEvalData{
|
||||||
|
CountIndex: countIdx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// EvalDataForNoInstanceKey is a value of InstanceKeyData that sets no instance
|
||||||
|
// key values at all, suitable for use in contexts where no keyed instance
|
||||||
|
// is relevant.
|
||||||
|
var EvalDataForNoInstanceKey = InstanceKeyEvalData{}
|
||||||
|
|
||||||
// evaluationStateData must implement lang.Data
|
// evaluationStateData must implement lang.Data
|
||||||
var _ lang.Data = (*evaluationStateData)(nil)
|
var _ lang.Data = (*evaluationStateData)(nil)
|
||||||
|
|
||||||
@ -96,12 +143,8 @@ func (d *evaluationStateData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.Sou
|
|||||||
switch addr.Name {
|
switch addr.Name {
|
||||||
|
|
||||||
case "index":
|
case "index":
|
||||||
key := d.InstanceKey
|
idxVal := d.InstanceKeyData.CountIndex
|
||||||
// key might not be set at all (addrs.NoKey) or it might be a string
|
if idxVal == cty.NilVal {
|
||||||
// if we're actually in a for_each block, so we'll check first and
|
|
||||||
// produce a nice error if this is being used in the wrong context.
|
|
||||||
intKey, ok := key.(addrs.IntKey)
|
|
||||||
if !ok {
|
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
diags = diags.Append(&hcl.Diagnostic{
|
||||||
Severity: hcl.DiagError,
|
Severity: hcl.DiagError,
|
||||||
Summary: `Reference to "count" in non-counted context`,
|
Summary: `Reference to "count" in non-counted context`,
|
||||||
@ -110,7 +153,7 @@ func (d *evaluationStateData) GetCountAttr(addr addrs.CountAttr, rng tfdiags.Sou
|
|||||||
})
|
})
|
||||||
return cty.UnknownVal(cty.Number), diags
|
return cty.UnknownVal(cty.Number), diags
|
||||||
}
|
}
|
||||||
return cty.NumberIntVal(int64(intKey)), diags
|
return idxVal, diags
|
||||||
|
|
||||||
default:
|
default:
|
||||||
diags = diags.Append(&hcl.Diagnostic{
|
diags = diags.Append(&hcl.Diagnostic{
|
||||||
|
Loading…
Reference in New Issue
Block a user