use the new clistate.Locker in the local backend

Use the new StateLocker field to provide a wrapper for locking the state
during terraform.Context creation. We can then remove all the state
locking code from individual operations, and unlock them in one place
inside the main Operation method.
This commit is contained in:
James Bardin 2018-02-23 11:28:13 -05:00
parent d3f7edeb27
commit 0b804a9686
5 changed files with 22 additions and 45 deletions

View File

@ -13,6 +13,7 @@ import (
"sync" "sync"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
@ -260,12 +261,21 @@ func (b *Local) Operation(ctx context.Context, op *backend.Operation) (*backend.
cancelCtx, cancel := context.WithCancel(context.Background()) cancelCtx, cancel := context.WithCancel(context.Background())
runningOp.Cancel = cancel runningOp.Cancel = cancel
if op.LockState {
op.StateLocker = clistate.NewLocker(stopCtx, op.StateLockTimeout, b.CLI, b.Colorize())
} else {
op.StateLocker = clistate.NewNoopLocker()
}
// Do it // Do it
go func() { go func() {
defer done() defer done()
defer stop() defer stop()
defer cancel() defer cancel()
// the state was locked during context creation, unlock the state when
// the operation completes
defer op.StateLocker.Unlock(runningOp.Err)
defer b.opLock.Unlock() defer b.opLock.Unlock()
f(stopCtx, cancelCtx, op, runningOp) f(stopCtx, cancelCtx, op, runningOp)
}() }()

View File

@ -11,7 +11,6 @@ import (
"github.com/hashicorp/errwrap" "github.com/hashicorp/errwrap"
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/command/format"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
@ -55,20 +54,6 @@ func (b *Local) opApply(
return return
} }
if op.LockState {
lockCtx, cancel := context.WithTimeout(stopCtx, op.StateLockTimeout)
defer cancel()
unlock, err := clistate.Lock(lockCtx, opState, op.Type.String(), "", b.CLI, b.Colorize())
if err != nil {
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
return
}
defer func() {
runningOp.Err = unlock(runningOp.Err)
}()
}
// Setup the state // Setup the state
runningOp.State = tfCtx.State() runningOp.State = tfCtx.State()

View File

@ -1,9 +1,11 @@
package local package local
import ( import (
"context"
"errors" "errors"
"log" "log"
"github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/command/format"
"github.com/hashicorp/terraform/tfdiags" "github.com/hashicorp/terraform/tfdiags"
@ -20,6 +22,12 @@ func (b *Local) Context(op *backend.Operation) (*terraform.Context, state.State,
// to ask for input/validate. // to ask for input/validate.
op.Type = backend.OperationTypeInvalid op.Type = backend.OperationTypeInvalid
if op.LockState {
op.StateLocker = clistate.NewLocker(context.Background(), op.StateLockTimeout, b.CLI, b.Colorize())
} else {
op.StateLocker = clistate.NewNoopLocker()
}
return b.context(op) return b.context(op)
} }
@ -30,6 +38,10 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, state.State,
return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err)
} }
if err := op.StateLocker.Lock(s, op.Type.String()); err != nil {
return nil, nil, errwrap.Wrapf("Error locking state: {{err}}", err)
}
if err := s.RefreshState(); err != nil { if err := s.RefreshState(); err != nil {
return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err)
} }

View File

@ -10,7 +10,6 @@ import (
"github.com/hashicorp/errwrap" "github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/command/format"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
@ -60,20 +59,6 @@ func (b *Local) opPlan(
return return
} }
if op.LockState {
lockCtx, cancel := context.WithTimeout(stopCtx, op.StateLockTimeout)
defer cancel()
unlock, err := clistate.Lock(lockCtx, opState, op.Type.String(), "", b.CLI, b.Colorize())
if err != nil {
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
return
}
defer func() {
runningOp.Err = unlock(runningOp.Err)
}()
}
// Setup the state // Setup the state
runningOp.State = tfCtx.State() runningOp.State = tfCtx.State()

View File

@ -9,7 +9,6 @@ import (
"github.com/hashicorp/errwrap" "github.com/hashicorp/errwrap"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
"github.com/hashicorp/terraform/command/clistate"
"github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/config/module"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -51,20 +50,6 @@ func (b *Local) opRefresh(
return return
} }
if op.LockState {
lockCtx, cancel := context.WithTimeout(stopCtx, op.StateLockTimeout)
defer cancel()
unlock, err := clistate.Lock(lockCtx, opState, op.Type.String(), "", b.CLI, b.Colorize())
if err != nil {
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
return
}
defer func() {
runningOp.Err = unlock(runningOp.Err)
}()
}
// Set our state // Set our state
runningOp.State = opState.State() runningOp.State = opState.State()
if runningOp.State.Empty() || !runningOp.State.HasResources() { if runningOp.State.Empty() || !runningOp.State.HasResources() {