use an EvalOpFilter for module variables

Remove the Input flag threaded through the input graph creation process
to prevent interpolation failures on module variables.
Use an EvalOpFilter instead to inset the correct EvalNode during
walkInput. Remove the EvalTryInterpolate type, and use the same
ContinueOnErr flag as the output node for consistency and to try and
keep the number possible eval node types down.
This commit is contained in:
James Bardin 2017-09-26 19:00:57 -04:00
parent c4dd31e62b
commit 1ad97f6be8
5 changed files with 24 additions and 55 deletions

View File

@ -9,14 +9,19 @@ import (
// 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.
type EvalInterpolate struct { type EvalInterpolate struct {
Config *config.RawConfig Config *config.RawConfig
Resource *Resource Resource *Resource
Output **ResourceConfig Output **ResourceConfig
ContinueOnErr bool
} }
func (n *EvalInterpolate) Eval(ctx EvalContext) (interface{}, error) { func (n *EvalInterpolate) Eval(ctx EvalContext) (interface{}, error) {
rc, err := ctx.Interpolate(n.Config, n.Resource) rc, err := ctx.Interpolate(n.Config, n.Resource)
if err != nil { if err != nil {
if n.ContinueOnErr {
log.Printf("[WARN] Interpolation %q failed: %s", n.Config.Key, err)
return nil, EvalEarlyExitError{}
}
return nil, err return nil, err
} }
@ -26,28 +31,3 @@ 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
}

View File

@ -10,9 +10,6 @@ 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

View File

@ -40,9 +40,6 @@ 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.
@ -115,7 +112,6 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
// Add module variables // Add module variables
&ModuleVariableTransformer{ &ModuleVariableTransformer{
Module: b.Module, 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

View File

@ -15,9 +15,6 @@ 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 {
@ -96,23 +93,24 @@ func (n *NodeApplyableModuleVariable) EvalTree() EvalNode {
var config *ResourceConfig var config *ResourceConfig
variables := make(map[string]interface{}) 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{ return &EvalSequence{
Nodes: []EvalNode{ Nodes: []EvalNode{
interpolate, &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,
},
},
&EvalVariableBlock{ &EvalVariableBlock{
Config: &config, Config: &config,

View File

@ -17,7 +17,6 @@ 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 {
@ -100,7 +99,6 @@ 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 {