1package terraform 2 3import ( 4 "github.com/hashicorp/hcl2/hcl" 5 "github.com/hashicorp/terraform-plugin-sdk/internal/addrs" 6 "github.com/hashicorp/terraform-plugin-sdk/internal/configs" 7 "github.com/hashicorp/terraform-plugin-sdk/internal/dag" 8 "github.com/hashicorp/terraform-plugin-sdk/internal/lang" 9 "github.com/zclconf/go-cty/cty" 10) 11 12// NodeApplyableModuleVariable represents a module variable input during 13// the apply step. 14type NodeApplyableModuleVariable struct { 15 Addr addrs.AbsInputVariableInstance 16 Config *configs.Variable // Config is the var in the config 17 Expr hcl.Expression // Expr is the value expression given in the call 18} 19 20// Ensure that we are implementing all of the interfaces we think we are 21// implementing. 22var ( 23 _ GraphNodeSubPath = (*NodeApplyableModuleVariable)(nil) 24 _ RemovableIfNotTargeted = (*NodeApplyableModuleVariable)(nil) 25 _ GraphNodeReferenceOutside = (*NodeApplyableModuleVariable)(nil) 26 _ GraphNodeReferenceable = (*NodeApplyableModuleVariable)(nil) 27 _ GraphNodeReferencer = (*NodeApplyableModuleVariable)(nil) 28 _ GraphNodeEvalable = (*NodeApplyableModuleVariable)(nil) 29 _ dag.GraphNodeDotter = (*NodeApplyableModuleVariable)(nil) 30) 31 32func (n *NodeApplyableModuleVariable) Name() string { 33 return n.Addr.String() 34} 35 36// GraphNodeSubPath 37func (n *NodeApplyableModuleVariable) Path() addrs.ModuleInstance { 38 // We execute in the parent scope (above our own module) because 39 // expressions in our value are resolved in that context. 40 return n.Addr.Module.Parent() 41} 42 43// RemovableIfNotTargeted 44func (n *NodeApplyableModuleVariable) RemoveIfNotTargeted() bool { 45 // We need to add this so that this node will be removed if 46 // it isn't targeted or a dependency of a target. 47 return true 48} 49 50// GraphNodeReferenceOutside implementation 51func (n *NodeApplyableModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.ModuleInstance) { 52 53 // Module input variables have their value expressions defined in the 54 // context of their calling (parent) module, and so references from 55 // a node of this type should be resolved in the parent module instance. 56 referencePath = n.Addr.Module.Parent() 57 58 // Input variables are _referenced_ from their own module, though. 59 selfPath = n.Addr.Module 60 61 return // uses named return values 62} 63 64// GraphNodeReferenceable 65func (n *NodeApplyableModuleVariable) ReferenceableAddrs() []addrs.Referenceable { 66 return []addrs.Referenceable{n.Addr.Variable} 67} 68 69// GraphNodeReferencer 70func (n *NodeApplyableModuleVariable) References() []*addrs.Reference { 71 72 // If we have no value expression, we cannot depend on anything. 73 if n.Expr == nil { 74 return nil 75 } 76 77 // Variables in the root don't depend on anything, because their values 78 // are gathered prior to the graph walk and recorded in the context. 79 if len(n.Addr.Module) == 0 { 80 return nil 81 } 82 83 // Otherwise, we depend on anything referenced by our value expression. 84 // We ignore diagnostics here under the assumption that we'll re-eval 85 // all these things later and catch them then; for our purposes here, 86 // we only care about valid references. 87 // 88 // Due to our GraphNodeReferenceOutside implementation, the addresses 89 // returned by this function are interpreted in the _parent_ module from 90 // where our associated variable was declared, which is correct because 91 // our value expression is assigned within a "module" block in the parent 92 // module. 93 refs, _ := lang.ReferencesInExpr(n.Expr) 94 return refs 95} 96 97// GraphNodeEvalable 98func (n *NodeApplyableModuleVariable) EvalTree() EvalNode { 99 // If we have no value, do nothing 100 if n.Expr == nil { 101 return &EvalNoop{} 102 } 103 104 // Otherwise, interpolate the value of this variable and set it 105 // within the variables mapping. 106 vals := make(map[string]cty.Value) 107 108 _, call := n.Addr.Module.CallInstance() 109 110 return &EvalSequence{ 111 Nodes: []EvalNode{ 112 &EvalOpFilter{ 113 Ops: []walkOperation{walkRefresh, walkPlan, walkApply, 114 walkDestroy, walkValidate}, 115 Node: &EvalModuleCallArgument{ 116 Addr: n.Addr.Variable, 117 Config: n.Config, 118 Expr: n.Expr, 119 Values: vals, 120 121 IgnoreDiagnostics: false, 122 }, 123 }, 124 125 &EvalSetModuleCallArguments{ 126 Module: call, 127 Values: vals, 128 }, 129 }, 130 } 131} 132 133// dag.GraphNodeDotter impl. 134func (n *NodeApplyableModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { 135 return &dag.DotNode{ 136 Name: name, 137 Attrs: map[string]string{ 138 "label": n.Name(), 139 "shape": "note", 140 }, 141 } 142} 143