opentofu/terraform/node_module_variable.go
James Bardin 97bb7cb65c Don't allow interpolation failure to stop Input
Allow module variables to fail interpolation during input. This is OK
since they will be verified again during Plan.  Because Input happens
before Refresh, module variable interpolation can fail when referencing
values that aren't yet in the state, but are expected after Refresh.
2017-08-10 14:14:29 -04:00

141 lines
3.2 KiB
Go

package terraform
import (
"fmt"
"github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/module"
)
// 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
// Input is set if this graph was created for the Input operation.
Input bool
}
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)
}
return result
}
// 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
}
// RemovableIfNotTargeted
func (n *NodeApplyableModuleVariable) 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
}
// 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
}
// GraphNodeReferenceable
func (n *NodeApplyableModuleVariable) ReferenceableName() []string {
return []string{n.Name()}
}
// GraphNodeReferencer
func (n *NodeApplyableModuleVariable) References() []string {
// If we have no value set, we depend on nothing
if n.Value == nil {
return nil
}
// Can't depend on anything if we're in the root
if len(n.PathValue) < 2 {
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)
}
result := ReferencesFromConfig(n.Value)
return modulePrefixList(result, prefix)
}
// GraphNodeEvalable
func (n *NodeApplyableModuleVariable) EvalTree() EvalNode {
// If we have no value, do nothing
if n.Value == 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{})
var interpolate EvalNode
if n.Input {
interpolate = &EvalTryInterpolate{
Config: n.Value,
Output: &config,
}
} else {
interpolate = &EvalInterpolate{
Config: n.Value,
Output: &config,
}
}
return &EvalSequence{
Nodes: []EvalNode{
interpolate,
&EvalVariableBlock{
Config: &config,
VariableValues: variables,
},
&EvalCoerceMapVariable{
Variables: variables,
ModulePath: n.PathValue,
ModuleTree: n.Module,
},
&EvalTypeCheckVariable{
Variables: variables,
ModulePath: n.PathValue,
ModuleTree: n.Module,
},
&EvalSetVariables{
Module: &n.PathValue[len(n.PathValue)-1],
Variables: variables,
},
},
}
}