coalesce the backened interrupt code

Moves the nested select statements for backend operations into a single
function. The only difference in this part was that apply called
PersistState, which should be harmless regardless of the type of
operation being run.
This commit is contained in:
James Bardin 2018-02-12 11:52:21 -05:00
parent ecd9ef0f77
commit ef8ed1e275
4 changed files with 51 additions and 77 deletions

View File

@ -5,6 +5,7 @@ import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"path/filepath"
"sort"
@ -273,6 +274,53 @@ func (b *Local) Operation(ctx context.Context, op *backend.Operation) (*backend.
return runningOp, nil
}
// opWait wats for the operation to complete, and a stop signal or a
// cancelation signal.
func (b *Local) opWait(
doneCh <-chan struct{},
stopCtx context.Context,
cancelCtx context.Context,
tfCtx *terraform.Context,
opState state.State) (canceled bool) {
// Wait for the operation to finish or for us to be interrupted so
// we can handle it properly.
select {
case <-stopCtx.Done():
if b.CLI != nil {
b.CLI.Output("stopping operation...")
}
// try to force a PersistState just in case the process is terminated
// before we can complete.
if err := opState.PersistState(); err != nil {
// We can't error out from here, but warn the user if there was an error.
// If this isn't transient, we will catch it again below, and
// attempt to save the state another way.
if b.CLI != nil {
b.CLI.Error(fmt.Sprintf(earlyStateWriteErrorFmt, err))
}
}
// Stop execution
go tfCtx.Stop()
select {
case <-cancelCtx.Done():
log.Println("[WARN] running operation canceled")
// if the operation was canceled, we need to return immediately
canceled = true
case <-doneCh:
}
case <-cancelCtx.Done():
// this should not be called without first attempting to stop the
// operation
log.Println("[ERROR] running operation canceled without Stop")
canceled = true
case <-doneCh:
}
return
}
// Colorize returns the Colorize structure that can be used for colorizing
// output. This is gauranteed to always return a non-nil value and so is useful
// as a helper to wrap any potentially colored strings.

View File

@ -154,42 +154,8 @@ func (b *Local) opApply(
applyState = tfCtx.State()
}()
// Wait for the apply to finish or for us to be interrupted so
// we can handle it properly.
err = nil
select {
case <-stopCtx.Done():
if b.CLI != nil {
b.CLI.Output("stopping apply operation...")
}
// try to force a PersistState just in case the process is terminated
// before we can complete.
if err := opState.PersistState(); err != nil {
// We can't error out from here, but warn the user if there was an error.
// If this isn't transient, we will catch it again below, and
// attempt to save the state another way.
if b.CLI != nil {
b.CLI.Error(fmt.Sprintf(earlyStateWriteErrorFmt, err))
}
}
// Stop execution
go tfCtx.Stop()
select {
case <-cancelCtx.Done():
log.Println("[WARN] running operation canceled")
// if the operation was canceled, we need to return immediately
return
case <-doneCh:
}
case <-cancelCtx.Done():
// this should not be called without first attempting to stop the
// operation
log.Println("[ERROR] running operation canceled without Stop")
if b.opWait(doneCh, stopCtx, cancelCtx, tfCtx, opState) {
return
case <-doneCh:
}
// Store the final state

View File

@ -112,28 +112,8 @@ func (b *Local) opPlan(
plan, planErr = tfCtx.Plan()
}()
select {
case <-stopCtx.Done():
if b.CLI != nil {
b.CLI.Output("stopping plan operation...")
}
// Stop execution
go tfCtx.Stop()
select {
case <-cancelCtx.Done():
log.Println("[WARN] running operation canceled")
// if the operation was canceled, we need to return immediately
return
case <-doneCh:
}
case <-cancelCtx.Done():
// this should not be called without first attempting to stop the
// operation
log.Println("[ERROR] running operation canceled without Stop")
if b.opWait(doneCh, stopCtx, cancelCtx, tfCtx, opState) {
return
case <-doneCh:
}
if planErr != nil {

View File

@ -91,28 +91,8 @@ func (b *Local) opRefresh(
log.Printf("[INFO] backend/local: refresh calling Refresh")
}()
select {
case <-stopCtx.Done():
if b.CLI != nil {
b.CLI.Output("stopping refresh operation...")
}
// Stop execution
go tfCtx.Stop()
select {
case <-cancelCtx.Done():
log.Println("[WARN] running operation canceled")
// if the operation was canceled, we need to return immediately
return
case <-doneCh:
}
case <-cancelCtx.Done():
// this should not be called without first attempting to stop the
// operation
log.Println("[ERROR] running operation canceled without Stop")
if b.opWait(doneCh, stopCtx, cancelCtx, tfCtx, opState) {
return
case <-doneCh:
}
// write the resulting state to the running op