continue on output errors during Input

Module outputs may not have complete information during Input, because
it happens before refresh. Continue process on output interpolation
errors during the Input walk.
This commit is contained in:
James Bardin 2017-09-27 11:41:14 -04:00
parent 1ad97f6be8
commit a048bcffa0
2 changed files with 33 additions and 7 deletions

View File

@ -41,15 +41,16 @@ type EvalWriteOutput struct {
Name string
Sensitive bool
Value *config.RawConfig
// ContinueOnErr allows interpolation to fail during Input
ContinueOnErr bool
}
// TODO: test
func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
// This has to run before we have a state lock, since interpolation also
// reads the state
cfg, err := ctx.Interpolate(n.Value, nil)
if err != nil {
// Log error but continue anyway
log.Printf("[WARN] Output interpolation %q failed: %s", n.Name, err)
}
// handle the error after we have the module from the state
state, lock := ctx.State()
if state == nil {
@ -59,13 +60,28 @@ func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
// Get a write lock so we can access this instance
lock.Lock()
defer lock.Unlock()
// Look for the module state. If we don't have one, create it.
mod := state.ModuleByPath(ctx.Path())
if mod == nil {
mod = state.AddModule(ctx.Path())
}
// handling the interpolation error
if err != nil {
if n.ContinueOnErr {
log.Printf("[ERROR] Output interpolation %q failed: %s", n.Name, err)
// if we're continueing, make sure the output is included, and
// marked as unknown
mod.Outputs[n.Name] = &OutputState{
Type: "string",
Value: config.UnknownVariableValue,
}
return nil, EvalEarlyExitError{}
}
return nil, err
}
// Get the value from the config
var valueRaw interface{} = config.UnknownVariableValue
if cfg != nil {

View File

@ -72,8 +72,18 @@ func (n *NodeApplyableOutput) EvalTree() EvalNode {
return &EvalSequence{
Nodes: []EvalNode{
&EvalOpFilter{
Ops: []walkOperation{walkRefresh, walkPlan, walkApply,
walkInput, walkValidate},
// Don't let interpolation errors stop Input, since it happens
// before Refresh.
Ops: []walkOperation{walkInput},
Node: &EvalWriteOutput{
Name: n.Config.Name,
Sensitive: n.Config.Sensitive,
Value: n.Config.RawConfig,
ContinueOnErr: true,
},
},
&EvalOpFilter{
Ops: []walkOperation{walkRefresh, walkPlan, walkApply, walkValidate},
Node: &EvalWriteOutput{
Name: n.Config.Name,
Sensitive: n.Config.Sensitive,