mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-02 04:07:22 -06:00
a2d2ce35dc
That name tag was left in only to reduce the diff when during implementation. Fix the naming now for these nodes so it is correct, and prevent any possible name collision between types.
223 lines
6.2 KiB
Go
223 lines
6.2 KiB
Go
package terraform
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/configs"
|
|
"github.com/hashicorp/terraform/dag"
|
|
"github.com/hashicorp/terraform/lang"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// nodeExpandModuleVariable is the placeholder for an variable that has not yet had
|
|
// its module path expanded.
|
|
type nodeExpandModuleVariable struct {
|
|
Addr addrs.InputVariable
|
|
Module addrs.Module
|
|
Config *configs.Variable
|
|
Expr hcl.Expression
|
|
}
|
|
|
|
var (
|
|
_ GraphNodeDynamicExpandable = (*nodeExpandModuleVariable)(nil)
|
|
_ GraphNodeReferenceOutside = (*nodeExpandModuleVariable)(nil)
|
|
_ GraphNodeReferenceable = (*nodeExpandModuleVariable)(nil)
|
|
_ GraphNodeReferencer = (*nodeExpandModuleVariable)(nil)
|
|
_ graphNodeTemporaryValue = (*nodeExpandModuleVariable)(nil)
|
|
_ RemovableIfNotTargeted = (*nodeExpandModuleVariable)(nil)
|
|
)
|
|
|
|
func (n *nodeExpandModuleVariable) temporaryValue() bool {
|
|
return true
|
|
}
|
|
|
|
func (n *nodeExpandModuleVariable) DynamicExpand(ctx EvalContext) (*Graph, error) {
|
|
var g Graph
|
|
expander := ctx.InstanceExpander()
|
|
for _, module := range expander.ExpandModule(n.Module) {
|
|
o := &nodeModuleVariable{
|
|
Addr: n.Addr.Absolute(module),
|
|
Config: n.Config,
|
|
Expr: n.Expr,
|
|
ModuleInstance: module,
|
|
}
|
|
g.Add(o)
|
|
}
|
|
return &g, nil
|
|
}
|
|
|
|
func (n *nodeExpandModuleVariable) Name() string {
|
|
return fmt.Sprintf("%s.%s (expand)", n.Module, n.Addr.String())
|
|
}
|
|
|
|
// GraphNodeModulePath
|
|
func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
|
|
return n.Module
|
|
}
|
|
|
|
// GraphNodeReferencer
|
|
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {
|
|
|
|
// If we have no value expression, we cannot depend on anything.
|
|
if n.Expr == nil {
|
|
return nil
|
|
}
|
|
|
|
// Variables in the root don't depend on anything, because their values
|
|
// are gathered prior to the graph walk and recorded in the context.
|
|
if len(n.Module) == 0 {
|
|
return nil
|
|
}
|
|
|
|
// Otherwise, we depend on anything referenced by our value expression.
|
|
// We ignore diagnostics here under the assumption that we'll re-eval
|
|
// all these things later and catch them then; for our purposes here,
|
|
// we only care about valid references.
|
|
//
|
|
// Due to our GraphNodeReferenceOutside implementation, the addresses
|
|
// returned by this function are interpreted in the _parent_ module from
|
|
// where our associated variable was declared, which is correct because
|
|
// our value expression is assigned within a "module" block in the parent
|
|
// module.
|
|
refs, _ := lang.ReferencesInExpr(n.Expr)
|
|
return refs
|
|
}
|
|
|
|
// GraphNodeReferenceOutside implementation
|
|
func (n *nodeExpandModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.Module) {
|
|
return n.Module, n.Module.Parent()
|
|
}
|
|
|
|
// GraphNodeReferenceable
|
|
func (n *nodeExpandModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
|
|
// FIXME: References for module variables probably need to be thought out a bit more
|
|
// Otherwise, we can reference the output via the address itself, or the
|
|
// module call
|
|
_, call := n.Module.Call()
|
|
return []addrs.Referenceable{n.Addr, call}
|
|
}
|
|
|
|
// RemovableIfNotTargeted
|
|
func (n *nodeExpandModuleVariable) RemoveIfNotTargeted() bool {
|
|
return true
|
|
}
|
|
|
|
// GraphNodeTargetDownstream
|
|
func (n *nodeExpandModuleVariable) TargetDownstream(targetedDeps, untargetedDeps dag.Set) bool {
|
|
return true
|
|
}
|
|
|
|
// nodeModuleVariable represents a module variable input during
|
|
// the apply step.
|
|
type nodeModuleVariable struct {
|
|
Addr addrs.AbsInputVariableInstance
|
|
Config *configs.Variable // Config is the var in the config
|
|
Expr hcl.Expression // Expr is the value expression given in the call
|
|
// ModuleInstance in order to create the appropriate context for evaluating
|
|
// ModuleCallArguments, ex. so count.index and each.key can resolve
|
|
ModuleInstance addrs.ModuleInstance
|
|
}
|
|
|
|
// Ensure that we are implementing all of the interfaces we think we are
|
|
// implementing.
|
|
var (
|
|
_ GraphNodeModuleInstance = (*nodeModuleVariable)(nil)
|
|
_ RemovableIfNotTargeted = (*nodeModuleVariable)(nil)
|
|
_ GraphNodeEvalable = (*nodeModuleVariable)(nil)
|
|
_ graphNodeTemporaryValue = (*nodeModuleVariable)(nil)
|
|
_ dag.GraphNodeDotter = (*nodeModuleVariable)(nil)
|
|
)
|
|
|
|
func (n *nodeModuleVariable) temporaryValue() bool {
|
|
return true
|
|
}
|
|
|
|
func (n *nodeModuleVariable) Name() string {
|
|
return n.Addr.String()
|
|
}
|
|
|
|
// GraphNodeModuleInstance
|
|
func (n *nodeModuleVariable) Path() addrs.ModuleInstance {
|
|
// We execute in the parent scope (above our own module) because
|
|
// expressions in our value are resolved in that context.
|
|
return n.Addr.Module.Parent()
|
|
}
|
|
|
|
// GraphNodeModulePath
|
|
func (n *nodeModuleVariable) ModulePath() addrs.Module {
|
|
return n.Addr.Module.Parent().Module()
|
|
}
|
|
|
|
// RemovableIfNotTargeted
|
|
func (n *nodeModuleVariable) RemoveIfNotTargeted() bool {
|
|
// We need to add this so that this node will be removed if
|
|
// it isn't targeted or a dependency of a target.
|
|
return true
|
|
}
|
|
|
|
// GraphNodeEvalable
|
|
func (n *nodeModuleVariable) EvalTree() EvalNode {
|
|
// If we have no value, do nothing
|
|
if n.Expr == nil {
|
|
return &EvalNoop{}
|
|
}
|
|
|
|
// Otherwise, interpolate the value of this variable and set it
|
|
// within the variables mapping.
|
|
vals := make(map[string]cty.Value)
|
|
|
|
_, call := n.Addr.Module.CallInstance()
|
|
|
|
return &EvalSequence{
|
|
Nodes: []EvalNode{
|
|
&EvalOpFilter{
|
|
Ops: []walkOperation{walkRefresh, walkPlan, walkApply,
|
|
walkDestroy},
|
|
Node: &EvalModuleCallArgument{
|
|
Addr: n.Addr.Variable,
|
|
Config: n.Config,
|
|
Expr: n.Expr,
|
|
ModuleInstance: n.ModuleInstance,
|
|
Values: vals,
|
|
},
|
|
},
|
|
|
|
&EvalOpFilter{
|
|
Ops: []walkOperation{walkValidate},
|
|
Node: &EvalModuleCallArgument{
|
|
Addr: n.Addr.Variable,
|
|
Config: n.Config,
|
|
Expr: n.Expr,
|
|
ModuleInstance: n.ModuleInstance,
|
|
Values: vals,
|
|
validateOnly: true,
|
|
},
|
|
},
|
|
|
|
&EvalSetModuleCallArguments{
|
|
Module: call,
|
|
Values: vals,
|
|
},
|
|
|
|
&evalVariableValidations{
|
|
Addr: n.Addr,
|
|
Config: n.Config,
|
|
Expr: n.Expr,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
// dag.GraphNodeDotter impl.
|
|
func (n *nodeModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
|
|
return &dag.DotNode{
|
|
Name: name,
|
|
Attrs: map[string]string{
|
|
"label": n.Name(),
|
|
"shape": "note",
|
|
},
|
|
}
|
|
}
|