provide contexts to clistate.Lock calls
Add fields required to create an appropriate context for all calls to clistate.Lock. Add missing checks for Meta.stateLock, where we would attempt to lock, even if locking should be skipped.
This commit is contained in:
parent
3f0dcd1308
commit
305ef43aa6
|
@ -7,6 +7,7 @@ package backend
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/terraform/config/module"
|
"github.com/hashicorp/terraform/config/module"
|
||||||
"github.com/hashicorp/terraform/state"
|
"github.com/hashicorp/terraform/state"
|
||||||
|
@ -132,6 +133,9 @@ type Operation struct {
|
||||||
// state.Lockers for its duration, and Unlock when complete.
|
// state.Lockers for its duration, and Unlock when complete.
|
||||||
LockState bool
|
LockState bool
|
||||||
|
|
||||||
|
// The duration to retry obtaining a State lock.
|
||||||
|
StateLockTimeout time.Duration
|
||||||
|
|
||||||
// Environment is the named state that should be loaded from the Backend.
|
// Environment is the named state that should be loaded from the Backend.
|
||||||
Environment string
|
Environment string
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,12 @@ func (b *Local) opApply(
|
||||||
}
|
}
|
||||||
|
|
||||||
if op.LockState {
|
if op.LockState {
|
||||||
|
lockCtx, cancel := context.WithTimeout(ctx, op.StateLockTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
lockInfo := state.NewLockInfo()
|
lockInfo := state.NewLockInfo()
|
||||||
lockInfo.Operation = op.Type.String()
|
lockInfo.Operation = op.Type.String()
|
||||||
lockID, err := clistate.Lock(opState, lockInfo, b.CLI, b.Colorize())
|
lockID, err := clistate.Lock(lockCtx, opState, lockInfo, b.CLI, b.Colorize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -61,9 +61,12 @@ func (b *Local) opPlan(
|
||||||
}
|
}
|
||||||
|
|
||||||
if op.LockState {
|
if op.LockState {
|
||||||
|
lockCtx, cancel := context.WithTimeout(ctx, op.StateLockTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
lockInfo := state.NewLockInfo()
|
lockInfo := state.NewLockInfo()
|
||||||
lockInfo.Operation = op.Type.String()
|
lockInfo.Operation = op.Type.String()
|
||||||
lockID, err := clistate.Lock(opState, lockInfo, b.CLI, b.Colorize())
|
lockID, err := clistate.Lock(lockCtx, opState, lockInfo, b.CLI, b.Colorize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -51,9 +51,12 @@ func (b *Local) opRefresh(
|
||||||
}
|
}
|
||||||
|
|
||||||
if op.LockState {
|
if op.LockState {
|
||||||
|
lockCtx, cancel := context.WithTimeout(ctx, op.StateLockTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
lockInfo := state.NewLockInfo()
|
lockInfo := state.NewLockInfo()
|
||||||
lockInfo.Operation = op.Type.String()
|
lockInfo.Operation = op.Type.String()
|
||||||
lockID, err := clistate.Lock(opState, lockInfo, b.CLI, b.Colorize())
|
lockID, err := clistate.Lock(lockCtx, opState, lockInfo, b.CLI, b.Colorize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
runningOp.Err = errwrap.Wrapf("Error locking state: {{err}}", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -92,15 +93,20 @@ func (c *EnvDeleteCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the state if we can
|
if c.stateLock {
|
||||||
lockInfo := state.NewLockInfo()
|
lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout)
|
||||||
lockInfo.Operation = "env delete"
|
defer cancel()
|
||||||
lockID, err := clistate.Lock(sMgr, lockInfo, c.Ui, c.Colorize())
|
|
||||||
if err != nil {
|
// Lock the state if we can
|
||||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
lockInfo := state.NewLockInfo()
|
||||||
return 1
|
lockInfo.Operation = "env delete"
|
||||||
|
lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize())
|
|
||||||
|
|
||||||
err = b.DeleteState(delEnv)
|
err = b.DeleteState(delEnv)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -87,15 +88,20 @@ func (c *EnvNewCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the state if we can
|
if c.stateLock {
|
||||||
lockInfo := state.NewLockInfo()
|
lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout)
|
||||||
lockInfo.Operation = "env new"
|
defer cancel()
|
||||||
lockID, err := clistate.Lock(sMgr, lockInfo, c.Ui, c.Colorize())
|
|
||||||
if err != nil {
|
// Lock the state if we can
|
||||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
lockInfo := state.NewLockInfo()
|
||||||
return 1
|
lockInfo.Operation = "env new"
|
||||||
|
lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, c.Ui, c.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(sMgr, lockID, c.Ui, c.Colorize())
|
|
||||||
|
|
||||||
// read the existing state file
|
// read the existing state file
|
||||||
stateFile, err := os.Open(statePath)
|
stateFile, err := os.Open(statePath)
|
||||||
|
|
|
@ -90,16 +90,20 @@ type Meta struct {
|
||||||
//
|
//
|
||||||
// stateLock is set to false to disable state locking
|
// stateLock is set to false to disable state locking
|
||||||
//
|
//
|
||||||
|
// stateLockTimeout is the optional duration to retry a state locks locks
|
||||||
|
// when it is already locked by another process.
|
||||||
|
//
|
||||||
// forceInitCopy suppresses confirmation for copying state data during
|
// forceInitCopy suppresses confirmation for copying state data during
|
||||||
// init.
|
// init.
|
||||||
statePath string
|
statePath string
|
||||||
stateOutPath string
|
stateOutPath string
|
||||||
backupPath string
|
backupPath string
|
||||||
parallelism int
|
parallelism int
|
||||||
shadow bool
|
shadow bool
|
||||||
provider string
|
provider string
|
||||||
stateLock bool
|
stateLock bool
|
||||||
forceInitCopy bool
|
stateLockTimeout time.Duration
|
||||||
|
forceInitCopy bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// initStatePaths is used to initialize the default values for
|
// initStatePaths is used to initialize the default values for
|
||||||
|
|
|
@ -4,6 +4,7 @@ package command
|
||||||
// exported and private.
|
// exported and private.
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
@ -166,10 +167,11 @@ func (m *Meta) IsLocalBackend(b backend.Backend) bool {
|
||||||
// be called.
|
// be called.
|
||||||
func (m *Meta) Operation() *backend.Operation {
|
func (m *Meta) Operation() *backend.Operation {
|
||||||
return &backend.Operation{
|
return &backend.Operation{
|
||||||
PlanOutBackend: m.backendState,
|
PlanOutBackend: m.backendState,
|
||||||
Targets: m.targets,
|
Targets: m.targets,
|
||||||
UIIn: m.UIInput(),
|
UIIn: m.UIInput(),
|
||||||
Environment: m.Env(),
|
Environment: m.Env(),
|
||||||
|
StateLockTimeout: m.stateLockTimeout,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -609,15 +611,20 @@ func (m *Meta) backendFromPlan(opts *BackendOpts) (backend.Backend, error) {
|
||||||
return nil, fmt.Errorf("Error reading state: %s", err)
|
return nil, fmt.Errorf("Error reading state: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the state if we can
|
if m.stateLock {
|
||||||
lockInfo := state.NewLockInfo()
|
lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout)
|
||||||
lockInfo.Operation = "backend from plan"
|
defer cancel()
|
||||||
|
|
||||||
lockID, err := clistate.Lock(realMgr, lockInfo, m.Ui, m.Colorize())
|
// Lock the state if we can
|
||||||
if err != nil {
|
lockInfo := state.NewLockInfo()
|
||||||
return nil, fmt.Errorf("Error locking state: %s", err)
|
lockInfo.Operation = "backend from plan"
|
||||||
|
|
||||||
|
lockID, err := clistate.Lock(lockCtx, realMgr, lockInfo, m.Ui, m.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error locking state: %s", err)
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(realMgr, lockID, m.Ui, m.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(realMgr, lockID, m.Ui, m.Colorize())
|
|
||||||
|
|
||||||
if err := realMgr.RefreshState(); err != nil {
|
if err := realMgr.RefreshState(); err != nil {
|
||||||
return nil, fmt.Errorf("Error reading state: %s", err)
|
return nil, fmt.Errorf("Error reading state: %s", err)
|
||||||
|
@ -1024,15 +1031,20 @@ func (m *Meta) backend_C_r_s(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the state if we can
|
if m.stateLock {
|
||||||
lockInfo := state.NewLockInfo()
|
lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout)
|
||||||
lockInfo.Operation = "backend from config"
|
defer cancel()
|
||||||
|
|
||||||
lockID, err := clistate.Lock(sMgr, lockInfo, m.Ui, m.Colorize())
|
// Lock the state if we can
|
||||||
if err != nil {
|
lockInfo := state.NewLockInfo()
|
||||||
return nil, fmt.Errorf("Error locking state: %s", err)
|
lockInfo.Operation = "backend from config"
|
||||||
|
|
||||||
|
lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error locking state: %s", err)
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
|
|
||||||
|
|
||||||
// Store the metadata in our saved state location
|
// Store the metadata in our saved state location
|
||||||
s := sMgr.State()
|
s := sMgr.State()
|
||||||
|
@ -1116,15 +1128,20 @@ func (m *Meta) backend_C_r_S_changed(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the state if we can
|
if m.stateLock {
|
||||||
lockInfo := state.NewLockInfo()
|
lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout)
|
||||||
lockInfo.Operation = "backend from config"
|
defer cancel()
|
||||||
|
|
||||||
lockID, err := clistate.Lock(sMgr, lockInfo, m.Ui, m.Colorize())
|
// Lock the state if we can
|
||||||
if err != nil {
|
lockInfo := state.NewLockInfo()
|
||||||
return nil, fmt.Errorf("Error locking state: %s", err)
|
lockInfo.Operation = "backend from config"
|
||||||
|
|
||||||
|
lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error locking state: %s", err)
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
|
|
||||||
|
|
||||||
// Update the backend state
|
// Update the backend state
|
||||||
s = sMgr.State()
|
s = sMgr.State()
|
||||||
|
@ -1272,15 +1289,20 @@ func (m *Meta) backend_C_R_S_unchanged(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock the state if we can
|
if m.stateLock {
|
||||||
lockInfo := state.NewLockInfo()
|
lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout)
|
||||||
lockInfo.Operation = "backend from config"
|
defer cancel()
|
||||||
|
|
||||||
lockID, err := clistate.Lock(sMgr, lockInfo, m.Ui, m.Colorize())
|
// Lock the state if we can
|
||||||
if err != nil {
|
lockInfo := state.NewLockInfo()
|
||||||
return nil, fmt.Errorf("Error locking state: %s", err)
|
lockInfo.Operation = "backend from config"
|
||||||
|
|
||||||
|
lockID, err := clistate.Lock(lockCtx, sMgr, lockInfo, m.Ui, m.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Error locking state: %s", err)
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
|
|
||||||
|
|
||||||
// Unset the remote state
|
// Unset the remote state
|
||||||
s = sMgr.State()
|
s = sMgr.State()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
|
@ -217,25 +218,30 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
||||||
errMigrateSingleLoadDefault), opts.TwoType, err)
|
errMigrateSingleLoadDefault), opts.TwoType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
lockInfoOne := state.NewLockInfo()
|
if m.stateLock {
|
||||||
lockInfoOne.Operation = "migration"
|
lockCtx, cancel := context.WithTimeout(context.Background(), m.stateLockTimeout)
|
||||||
lockInfoOne.Info = "source state"
|
defer cancel()
|
||||||
|
|
||||||
lockIDOne, err := clistate.Lock(stateOne, lockInfoOne, m.Ui, m.Colorize())
|
lockInfoOne := state.NewLockInfo()
|
||||||
if err != nil {
|
lockInfoOne.Operation = "migration"
|
||||||
return fmt.Errorf("Error locking source state: %s", err)
|
lockInfoOne.Info = "source state"
|
||||||
|
|
||||||
|
lockIDOne, err := clistate.Lock(lockCtx, stateOne, lockInfoOne, m.Ui, m.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error locking source state: %s", err)
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(stateOne, lockIDOne, m.Ui, m.Colorize())
|
||||||
|
|
||||||
|
lockInfoTwo := state.NewLockInfo()
|
||||||
|
lockInfoTwo.Operation = "migration"
|
||||||
|
lockInfoTwo.Info = "destination state"
|
||||||
|
|
||||||
|
lockIDTwo, err := clistate.Lock(lockCtx, stateTwo, lockInfoTwo, m.Ui, m.Colorize())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Error locking destination state: %s", err)
|
||||||
|
}
|
||||||
|
defer clistate.Unlock(stateTwo, lockIDTwo, m.Ui, m.Colorize())
|
||||||
}
|
}
|
||||||
defer clistate.Unlock(stateOne, lockIDOne, m.Ui, m.Colorize())
|
|
||||||
|
|
||||||
lockInfoTwo := state.NewLockInfo()
|
|
||||||
lockInfoTwo.Operation = "migration"
|
|
||||||
lockInfoTwo.Info = "destination state"
|
|
||||||
|
|
||||||
lockIDTwo, err := clistate.Lock(stateTwo, lockInfoTwo, m.Ui, m.Colorize())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("Error locking destination state: %s", err)
|
|
||||||
}
|
|
||||||
defer clistate.Unlock(stateTwo, lockIDTwo, m.Ui, m.Colorize())
|
|
||||||
|
|
||||||
one := stateOne.State()
|
one := stateOne.State()
|
||||||
two := stateTwo.State()
|
two := stateTwo.State()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -78,10 +79,13 @@ func (c *TaintCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Meta.stateLock {
|
if c.stateLock {
|
||||||
|
lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
lockInfo := state.NewLockInfo()
|
lockInfo := state.NewLockInfo()
|
||||||
lockInfo.Operation = "taint"
|
lockInfo.Operation = "taint"
|
||||||
lockID, err := clistate.Lock(st, lockInfo, c.Ui, c.Colorize())
|
lockID, err := clistate.Lock(lockCtx, st, lockInfo, c.Ui, c.Colorize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -66,10 +67,13 @@ func (c *UntaintCommand) Run(args []string) int {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.Meta.stateLock {
|
if c.stateLock {
|
||||||
|
lockCtx, cancel := context.WithTimeout(context.Background(), c.stateLockTimeout)
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
lockInfo := state.NewLockInfo()
|
lockInfo := state.NewLockInfo()
|
||||||
lockInfo.Operation = "untaint"
|
lockInfo.Operation = "untaint"
|
||||||
lockID, err := clistate.Lock(st, lockInfo, c.Ui, c.Colorize())
|
lockID, err := clistate.Lock(lockCtx, st, lockInfo, c.Ui, c.Colorize())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||||
return 1
|
return 1
|
||||||
|
|
Loading…
Reference in New Issue