diff --git a/terraform/context_validate_test.go b/terraform/context_validate_test.go index 8b380ba03f..178f291746 100644 --- a/terraform/context_validate_test.go +++ b/terraform/context_validate_test.go @@ -1435,7 +1435,7 @@ resource "aws_instance" "foo" { module "nested" { count = 2 source = "./nested" - input = 2 + input = count.index } `, "mod/nested/main.tf": ` diff --git a/terraform/eval_variable.go b/terraform/eval_variable.go index e5ff7cdf74..5fc90245b5 100644 --- a/terraform/eval_variable.go +++ b/terraform/eval_variable.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/hcl/v2" "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/configs" + "github.com/hashicorp/terraform/instances" "github.com/hashicorp/terraform/tfdiags" "github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty/convert" @@ -42,12 +43,12 @@ type EvalModuleCallArgument struct { Expr hcl.Expression ModuleInstance addrs.ModuleInstance - // If this flag is set, any diagnostics are discarded and this operation - // will always succeed, though may produce an unknown value in the - // event of an error. - IgnoreDiagnostics bool - Values map[string]cty.Value + + // validateOnly indicates that this evaluation is only for config + // validation, and we will not have any expansion module instance + // repetition data. + validateOnly bool } func (n *EvalModuleCallArgument) Eval(ctx EvalContext) (interface{}, error) { @@ -69,9 +70,24 @@ func (n *EvalModuleCallArgument) Eval(ctx EvalContext) (interface{}, error) { return nil, nil } - // Get the repetition data for this module instance, - // so we can create the appropriate scope for evaluating our expression - moduleInstanceRepetitionData := ctx.InstanceExpander().GetModuleInstanceRepetitionData(n.ModuleInstance) + var moduleInstanceRepetitionData instances.RepetitionData + + switch { + case n.validateOnly: + // the instance expander does not track unknown expansion values, so we + // have to assume all RepetitionData is unknown. + moduleInstanceRepetitionData = instances.RepetitionData{ + CountIndex: cty.UnknownVal(cty.Number), + EachKey: cty.UnknownVal(cty.String), + EachValue: cty.DynamicVal, + } + + default: + // Get the repetition data for this module instance, + // so we can create the appropriate scope for evaluating our expression + moduleInstanceRepetitionData = ctx.InstanceExpander().GetModuleInstanceRepetitionData(n.ModuleInstance) + } + scope := ctx.EvaluationScope(nil, moduleInstanceRepetitionData) val, diags := scope.EvalExpr(expr, cty.DynamicPseudoType) @@ -96,9 +112,6 @@ func (n *EvalModuleCallArgument) Eval(ctx EvalContext) (interface{}, error) { } n.Values[name] = val - if n.IgnoreDiagnostics { - return nil, nil - } return nil, diags.ErrWithWarnings() } @@ -116,15 +129,10 @@ type evalVariableValidations struct { // This will be nil for root module variables, because their values come // from outside the configuration. Expr hcl.Expression - - // If this flag is set, this node becomes a no-op. - // This is here for consistency with EvalModuleCallArgument so that it - // can be populated with the same value, where needed. - IgnoreDiagnostics bool } func (n *evalVariableValidations) Eval(ctx EvalContext) (interface{}, error) { - if n.Config == nil || n.IgnoreDiagnostics || len(n.Config.Validations) == 0 { + if n.Config == nil || len(n.Config.Validations) == 0 { log.Printf("[TRACE] evalVariableValidations: not active for %s, so skipping", n.Addr) return nil, nil } diff --git a/terraform/node_module_variable.go b/terraform/node_module_variable.go index 53543b47fc..62ebb19132 100644 --- a/terraform/node_module_variable.go +++ b/terraform/node_module_variable.go @@ -11,8 +11,6 @@ import ( "github.com/zclconf/go-cty/cty" ) -type ConcreteVariableNodeFunc func(n *nodeExpandModuleVariable) dag.Vertex - // nodeExpandModuleVariable is the placeholder for an variable that has not yet had // its module path expanded. type nodeExpandModuleVariable struct { @@ -176,15 +174,25 @@ func (n *nodeModuleVariable) EvalTree() EvalNode { Nodes: []EvalNode{ &EvalOpFilter{ Ops: []walkOperation{walkRefresh, walkPlan, walkApply, - walkDestroy, walkValidate}, + walkDestroy}, Node: &EvalModuleCallArgument{ Addr: n.Addr.Variable, Config: n.Config, Expr: n.Expr, ModuleInstance: n.ModuleInstance, Values: vals, + }, + }, - IgnoreDiagnostics: false, + &EvalOpFilter{ + Ops: []walkOperation{walkValidate}, + Node: &EvalModuleCallArgument{ + Addr: n.Addr.Variable, + Config: n.Config, + Expr: n.Expr, + ModuleInstance: n.ModuleInstance, + Values: vals, + validateOnly: true, }, }, @@ -197,8 +205,6 @@ func (n *nodeModuleVariable) EvalTree() EvalNode { Addr: n.Addr, Config: n.Config, Expr: n.Expr, - - IgnoreDiagnostics: false, }, }, } diff --git a/terraform/node_root_variable.go b/terraform/node_root_variable.go index 9740bf4ebf..f9814f375a 100644 --- a/terraform/node_root_variable.go +++ b/terraform/node_root_variable.go @@ -50,8 +50,6 @@ func (n *NodeRootVariable) EvalTree() EvalNode { Addr: addrs.RootModuleInstance.InputVariable(n.Addr.Name), Config: n.Config, Expr: nil, // not set for root module variables - - IgnoreDiagnostics: false, } } diff --git a/terraform/transform_module_variable.go b/terraform/transform_module_variable.go index 1d74ba3327..99a86c01d9 100644 --- a/terraform/transform_module_variable.go +++ b/terraform/transform_module_variable.go @@ -113,7 +113,6 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs Config: v, Expr: expr, } - g.Add(node) }