diff --git a/backend/local/backend.go b/backend/local/backend.go index b42aedb17..b0aae720e 100644 --- a/backend/local/backend.go +++ b/backend/local/backend.go @@ -13,6 +13,7 @@ import ( "sync" "github.com/hashicorp/terraform/backend" + "github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/state" "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()) runningOp.Cancel = cancel + if op.LockState { + op.StateLocker = clistate.NewLocker(stopCtx, op.StateLockTimeout, b.CLI, b.Colorize()) + } else { + op.StateLocker = clistate.NewNoopLocker() + } + // Do it go func() { defer done() defer stop() 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() f(stopCtx, cancelCtx, op, runningOp) }() diff --git a/backend/local/backend_apply.go b/backend/local/backend_apply.go index 8a97fc829..102d40c39 100644 --- a/backend/local/backend_apply.go +++ b/backend/local/backend_apply.go @@ -11,7 +11,6 @@ import ( "github.com/hashicorp/errwrap" "github.com/hashicorp/go-multierror" "github.com/hashicorp/terraform/backend" - "github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/state" @@ -55,20 +54,6 @@ func (b *Local) opApply( 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 runningOp.State = tfCtx.State() diff --git a/backend/local/backend_local.go b/backend/local/backend_local.go index aa056a1a1..d26fefa57 100644 --- a/backend/local/backend_local.go +++ b/backend/local/backend_local.go @@ -1,9 +1,11 @@ package local import ( + "context" "errors" "log" + "github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/format" "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. 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) } @@ -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) } + 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 { return nil, nil, errwrap.Wrapf("Error loading state: {{err}}", err) } diff --git a/backend/local/backend_plan.go b/backend/local/backend_plan.go index d2956e341..00c0a859d 100644 --- a/backend/local/backend_plan.go +++ b/backend/local/backend_plan.go @@ -10,7 +10,6 @@ import ( "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/backend" - "github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/command/format" "github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/terraform" @@ -60,20 +59,6 @@ func (b *Local) opPlan( 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 runningOp.State = tfCtx.State() diff --git a/backend/local/backend_refresh.go b/backend/local/backend_refresh.go index a19aa9e5e..b5ec9aa6d 100644 --- a/backend/local/backend_refresh.go +++ b/backend/local/backend_refresh.go @@ -9,7 +9,6 @@ import ( "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/backend" - "github.com/hashicorp/terraform/command/clistate" "github.com/hashicorp/terraform/config/module" "github.com/hashicorp/terraform/terraform" ) @@ -51,20 +50,6 @@ func (b *Local) opRefresh( 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 runningOp.State = opState.State() if runningOp.State.Empty() || !runningOp.State.HasResources() {