eval variables with unknown expansion data
While we don't have any expansion info during validation, we can try to evaluate variable expressions to catch some basic errors. Do this by creating module instance RepetitionData with unknown values. This unfortunately will still miss the incorrect usage of count/each values, but that would require the module call's each mode, which is not available at this time.
This commit is contained in:
parent
c59ecac870
commit
d060a3d0e8
|
@ -1435,7 +1435,7 @@ resource "aws_instance" "foo" {
|
|||
module "nested" {
|
||||
count = 2
|
||||
source = "./nested"
|
||||
input = 2
|
||||
input = count.index
|
||||
}
|
||||
`,
|
||||
"mod/nested/main.tf": `
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -113,7 +113,6 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, c *configs
|
|||
Config: v,
|
||||
Expr: expr,
|
||||
}
|
||||
|
||||
g.Add(node)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue