package terraform
import (
- "fmt"
-
- "github.com/hashicorp/terraform/config"
- "github.com/hashicorp/terraform/config/module"
+ "github.com/hashicorp/hcl2/hcl"
+ "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"
)
// NodeApplyableModuleVariable represents a module variable input during
// the apply step.
type NodeApplyableModuleVariable struct {
- PathValue []string
- Config *config.Variable // Config is the var in the config
- Value *config.RawConfig // Value is the value that is set
-
- Module *module.Tree // Antiquated, want to remove
+ 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
}
-func (n *NodeApplyableModuleVariable) Name() string {
- result := fmt.Sprintf("var.%s", n.Config.Name)
- if len(n.PathValue) > 1 {
- result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result)
- }
+// Ensure that we are implementing all of the interfaces we think we are
+// implementing.
+var (
+ _ GraphNodeSubPath = (*NodeApplyableModuleVariable)(nil)
+ _ RemovableIfNotTargeted = (*NodeApplyableModuleVariable)(nil)
+ _ GraphNodeReferenceOutside = (*NodeApplyableModuleVariable)(nil)
+ _ GraphNodeReferenceable = (*NodeApplyableModuleVariable)(nil)
+ _ GraphNodeReferencer = (*NodeApplyableModuleVariable)(nil)
+ _ GraphNodeEvalable = (*NodeApplyableModuleVariable)(nil)
+ _ dag.GraphNodeDotter = (*NodeApplyableModuleVariable)(nil)
+)
- return result
+func (n *NodeApplyableModuleVariable) Name() string {
+ return n.Addr.String()
}
// GraphNodeSubPath
-func (n *NodeApplyableModuleVariable) Path() []string {
- // We execute in the parent scope (above our own module) so that
- // we can access the proper interpolations.
- if len(n.PathValue) > 2 {
- return n.PathValue[:len(n.PathValue)-1]
- }
-
- return rootModulePath
+func (n *NodeApplyableModuleVariable) 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()
}
// RemovableIfNotTargeted
return true
}
-// GraphNodeReferenceGlobal
-func (n *NodeApplyableModuleVariable) ReferenceGlobal() bool {
- // We have to create fully qualified references because we cross
- // boundaries here: our ReferenceableName is in one path and our
- // References are from another path.
- return true
+// GraphNodeReferenceOutside implementation
+func (n *NodeApplyableModuleVariable) ReferenceOutside() (selfPath, referencePath addrs.ModuleInstance) {
+
+ // Module input variables have their value expressions defined in the
+ // context of their calling (parent) module, and so references from
+ // a node of this type should be resolved in the parent module instance.
+ referencePath = n.Addr.Module.Parent()
+
+ // Input variables are _referenced_ from their own module, though.
+ selfPath = n.Addr.Module
+
+ return // uses named return values
}
// GraphNodeReferenceable
-func (n *NodeApplyableModuleVariable) ReferenceableName() []string {
- return []string{n.Name()}
+func (n *NodeApplyableModuleVariable) ReferenceableAddrs() []addrs.Referenceable {
+ return []addrs.Referenceable{n.Addr.Variable}
}
// GraphNodeReferencer
-func (n *NodeApplyableModuleVariable) References() []string {
- // If we have no value set, we depend on nothing
- if n.Value == nil {
- return nil
- }
+func (n *NodeApplyableModuleVariable) References() []*addrs.Reference {
- // Can't depend on anything if we're in the root
- if len(n.PathValue) < 2 {
+ // If we have no value expression, we cannot depend on anything.
+ if n.Expr == nil {
return nil
}
- // Otherwise, we depend on anything that is in our value, but
- // specifically in the namespace of the parent path.
- // Create the prefix based on the path
- var prefix string
- if p := n.Path(); len(p) > 0 {
- prefix = modulePrefixStr(p)
+ // 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.Addr.Module) == 0 {
+ return nil
}
- result := ReferencesFromConfig(n.Value)
- return modulePrefixList(result, prefix)
+ // 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
}
// GraphNodeEvalable
func (n *NodeApplyableModuleVariable) EvalTree() EvalNode {
// If we have no value, do nothing
- if n.Value == nil {
+ if n.Expr == nil {
return &EvalNoop{}
}
// Otherwise, interpolate the value of this variable and set it
// within the variables mapping.
- var config *ResourceConfig
- variables := make(map[string]interface{})
+ vals := make(map[string]cty.Value)
+
+ _, call := n.Addr.Module.CallInstance()
return &EvalSequence{
Nodes: []EvalNode{
- &EvalOpFilter{
- Ops: []walkOperation{walkInput},
- Node: &EvalInterpolate{
- Config: n.Value,
- Output: &config,
- ContinueOnErr: true,
- },
- },
&EvalOpFilter{
Ops: []walkOperation{walkRefresh, walkPlan, walkApply,
walkDestroy, walkValidate},
- Node: &EvalInterpolate{
- Config: n.Value,
- Output: &config,
- },
- },
+ Node: &EvalModuleCallArgument{
+ Addr: n.Addr.Variable,
+ Config: n.Config,
+ Expr: n.Expr,
+ Values: vals,
- &EvalVariableBlock{
- Config: &config,
- VariableValues: variables,
- },
-
- &EvalCoerceMapVariable{
- Variables: variables,
- ModulePath: n.PathValue,
- ModuleTree: n.Module,
+ IgnoreDiagnostics: false,
+ },
},
- &EvalTypeCheckVariable{
- Variables: variables,
- ModulePath: n.PathValue,
- ModuleTree: n.Module,
+ &EvalSetModuleCallArguments{
+ Module: call,
+ Values: vals,
},
+ },
+ }
+}
- &EvalSetVariables{
- Module: &n.PathValue[len(n.PathValue)-1],
- Variables: variables,
- },
+// dag.GraphNodeDotter impl.
+func (n *NodeApplyableModuleVariable) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
+ return &dag.DotNode{
+ Name: name,
+ Attrs: map[string]string{
+ "label": n.Name(),
+ "shape": "note",
},
}
}