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.
This commit is contained in:
parent
5bcc1bae59
commit
97bb7cb65c
|
@ -1,6 +1,10 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import "github.com/hashicorp/terraform/config"
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/hashicorp/terraform/config"
|
||||||
|
)
|
||||||
|
|
||||||
// EvalInterpolate is an EvalNode implementation that takes a raw
|
// EvalInterpolate is an EvalNode implementation that takes a raw
|
||||||
// configuration and interpolates it.
|
// configuration and interpolates it.
|
||||||
|
@ -22,3 +26,28 @@ func (n *EvalInterpolate) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EvalTryInterpolate is an EvalNode implementation that takes a raw
|
||||||
|
// configuration and interpolates it, but only logs a warning on an
|
||||||
|
// interpolation error, and stops further Eval steps.
|
||||||
|
// This is used during Input where a value may not be known before Refresh, but
|
||||||
|
// we don't want to block Input.
|
||||||
|
type EvalTryInterpolate struct {
|
||||||
|
Config *config.RawConfig
|
||||||
|
Resource *Resource
|
||||||
|
Output **ResourceConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *EvalTryInterpolate) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
rc, err := ctx.Interpolate(n.Config, n.Resource)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[WARN] Interpolation %q failed: %s", n.Config.Key, err)
|
||||||
|
return nil, EvalEarlyExitError{}
|
||||||
|
}
|
||||||
|
|
||||||
|
if n.Output != nil {
|
||||||
|
*n.Output = rc
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// EvalReadState is an EvalNode implementation that reads the
|
// EvalReadState is an EvalNode implementation that reads the
|
||||||
// primary InstanceState for a specific resource out of the state.
|
// primary InstanceState for a specific resource out of the state.
|
||||||
|
|
|
@ -10,6 +10,9 @@ import (
|
||||||
// and is based on the PlanGraphBuilder. The PlanGraphBuilder passed in will be
|
// and is based on the PlanGraphBuilder. The PlanGraphBuilder passed in will be
|
||||||
// modified and should not be used for any other operations.
|
// modified and should not be used for any other operations.
|
||||||
func InputGraphBuilder(p *PlanGraphBuilder) GraphBuilder {
|
func InputGraphBuilder(p *PlanGraphBuilder) GraphBuilder {
|
||||||
|
// convert this to an InputPlan
|
||||||
|
p.Input = true
|
||||||
|
|
||||||
// We're going to customize the concrete functions
|
// We're going to customize the concrete functions
|
||||||
p.CustomConcrete = true
|
p.CustomConcrete = true
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,9 @@ type PlanGraphBuilder struct {
|
||||||
// Validate will do structural validation of the graph.
|
// Validate will do structural validation of the graph.
|
||||||
Validate bool
|
Validate bool
|
||||||
|
|
||||||
|
// Input represents that this builder is for an Input operation.
|
||||||
|
Input bool
|
||||||
|
|
||||||
// CustomConcrete can be set to customize the node types created
|
// CustomConcrete can be set to customize the node types created
|
||||||
// for various parts of the plan. This is useful in order to customize
|
// for various parts of the plan. This is useful in order to customize
|
||||||
// the plan behavior.
|
// the plan behavior.
|
||||||
|
@ -107,7 +110,10 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
|
||||||
),
|
),
|
||||||
|
|
||||||
// Add module variables
|
// Add module variables
|
||||||
&ModuleVariableTransformer{Module: b.Module},
|
&ModuleVariableTransformer{
|
||||||
|
Module: b.Module,
|
||||||
|
Input: b.Input,
|
||||||
|
},
|
||||||
|
|
||||||
// Connect so that the references are ready for targeting. We'll
|
// Connect so that the references are ready for targeting. We'll
|
||||||
// have to connect again later for providers and so on.
|
// have to connect again later for providers and so on.
|
||||||
|
|
|
@ -15,6 +15,9 @@ type NodeApplyableModuleVariable struct {
|
||||||
Value *config.RawConfig // Value is the value that is set
|
Value *config.RawConfig // Value is the value that is set
|
||||||
|
|
||||||
Module *module.Tree // Antiquated, want to remove
|
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 {
|
func (n *NodeApplyableModuleVariable) Name() string {
|
||||||
|
@ -92,12 +95,24 @@ func (n *NodeApplyableModuleVariable) EvalTree() EvalNode {
|
||||||
// within the variables mapping.
|
// within the variables mapping.
|
||||||
var config *ResourceConfig
|
var config *ResourceConfig
|
||||||
variables := make(map[string]interface{})
|
variables := make(map[string]interface{})
|
||||||
return &EvalSequence{
|
|
||||||
Nodes: []EvalNode{
|
var interpolate EvalNode
|
||||||
&EvalInterpolate{
|
|
||||||
|
if n.Input {
|
||||||
|
interpolate = &EvalTryInterpolate{
|
||||||
Config: n.Value,
|
Config: n.Value,
|
||||||
Output: &config,
|
Output: &config,
|
||||||
},
|
}
|
||||||
|
} else {
|
||||||
|
interpolate = &EvalInterpolate{
|
||||||
|
Config: n.Value,
|
||||||
|
Output: &config,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &EvalSequence{
|
||||||
|
Nodes: []EvalNode{
|
||||||
|
interpolate,
|
||||||
|
|
||||||
&EvalVariableBlock{
|
&EvalVariableBlock{
|
||||||
Config: &config,
|
Config: &config,
|
||||||
|
|
|
@ -17,6 +17,7 @@ type ModuleVariableTransformer struct {
|
||||||
Module *module.Tree
|
Module *module.Tree
|
||||||
|
|
||||||
DisablePrune bool // True if pruning unreferenced should be disabled
|
DisablePrune bool // True if pruning unreferenced should be disabled
|
||||||
|
Input bool // True if this is from an Input operation.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *ModuleVariableTransformer) Transform(g *Graph) error {
|
func (t *ModuleVariableTransformer) Transform(g *Graph) error {
|
||||||
|
@ -99,6 +100,7 @@ func (t *ModuleVariableTransformer) transformSingle(g *Graph, parent, m *module.
|
||||||
Config: v,
|
Config: v,
|
||||||
Value: value,
|
Value: value,
|
||||||
Module: t.Module,
|
Module: t.Module,
|
||||||
|
Input: t.Input,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !t.DisablePrune {
|
if !t.DisablePrune {
|
||||||
|
|
Loading…
Reference in New Issue