Merge pull request #27787 from hashicorp/alisdair/command-views-state-locker
clistate: Update clistate.Locker for command views
This commit is contained in:
commit
6375c6ce6b
|
@ -10,7 +10,6 @@ import (
|
|||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
|
@ -216,17 +215,13 @@ type Operation struct {
|
|||
// ShowDiagnostics prints diagnostic messages to the UI.
|
||||
ShowDiagnostics func(vals ...interface{})
|
||||
|
||||
// If LockState is true, the Operation must Lock any
|
||||
// statemgr.Lockers for its duration, and Unlock when complete.
|
||||
LockState bool
|
||||
|
||||
// StateLocker is used to lock the state while providing UI feedback to the
|
||||
// user. This will be supplied by the Backend itself.
|
||||
// user. This will be replaced by the Backend to update the context.
|
||||
//
|
||||
// If state locking is not necessary, this should be set to a no-op
|
||||
// implementation of clistate.Locker.
|
||||
StateLocker clistate.Locker
|
||||
|
||||
// The duration to retry obtaining a State lock.
|
||||
StateLockTimeout time.Duration
|
||||
|
||||
// Workspace is the name of the workspace that this operation should run
|
||||
// in, which controls which named state is used.
|
||||
Workspace string
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
"sync"
|
||||
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
|
@ -326,11 +325,7 @@ 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()
|
||||
}
|
||||
op.StateLocker = op.StateLocker.WithContext(stopCtx)
|
||||
|
||||
// Do it
|
||||
go func() {
|
||||
|
|
|
@ -52,9 +52,9 @@ func (b *Local) opApply(
|
|||
// the state was locked during succesfull context creation; unlock the state
|
||||
// when the operation completes
|
||||
defer func() {
|
||||
err := op.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
op.ShowDiagnostics(err)
|
||||
diags := op.StateLocker.Unlock()
|
||||
if diags.HasErrors() {
|
||||
op.ShowDiagnostics(diags)
|
||||
runningOp.Result = backend.OperationFailure
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/providers"
|
||||
|
@ -293,6 +294,7 @@ func testOperationApply(t *testing.T, configDir string) (*backend.Operation, fun
|
|||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
ShowDiagnostics: testLogDiagnostics(t),
|
||||
StateLocker: clistate.NewNoopLocker(),
|
||||
}, configCleanup
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/configs/configload"
|
||||
"github.com/hashicorp/terraform/plans/planfile"
|
||||
|
@ -24,11 +23,7 @@ func (b *Local) Context(op *backend.Operation) (*terraform.Context, statemgr.Ful
|
|||
// 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()
|
||||
}
|
||||
op.StateLocker = op.StateLocker.WithContext(context.Background())
|
||||
|
||||
ctx, _, stateMgr, diags := b.context(op)
|
||||
return ctx, stateMgr, diags
|
||||
|
@ -45,8 +40,7 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, *configload.
|
|||
return nil, nil, nil, diags
|
||||
}
|
||||
log.Printf("[TRACE] backend/local: requesting state lock for workspace %q", op.Workspace)
|
||||
if err := op.StateLocker.Lock(s, op.Type.String()); err != nil {
|
||||
diags = diags.Append(errwrap.Wrapf("Error locking state: {{err}}", err))
|
||||
if diags := op.StateLocker.Lock(s, op.Type.String()); diags.HasErrors() {
|
||||
return nil, nil, nil, diags
|
||||
}
|
||||
|
||||
|
@ -54,10 +48,7 @@ func (b *Local) context(op *backend.Operation) (*terraform.Context, *configload.
|
|||
// If we're returning with errors, and thus not producing a valid
|
||||
// context, we'll want to avoid leaving the workspace locked.
|
||||
if diags.HasErrors() {
|
||||
err := op.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
diags = diags.Append(errwrap.Wrapf("Error unlocking state: {{err}}", err))
|
||||
}
|
||||
diags = diags.Append(op.StateLocker.Unlock())
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -4,7 +4,11 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
)
|
||||
|
||||
func TestLocalContext(t *testing.T) {
|
||||
|
@ -15,11 +19,15 @@ func TestLocalContext(t *testing.T) {
|
|||
_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
|
||||
defer configCleanup()
|
||||
|
||||
streams, _ := terminal.StreamsForTesting(t)
|
||||
view := views.NewView(streams)
|
||||
stateLocker := clistate.NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
|
||||
|
||||
op := &backend.Operation{
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
Workspace: backend.DefaultStateName,
|
||||
LockState: true,
|
||||
StateLocker: stateLocker,
|
||||
}
|
||||
|
||||
_, _, diags := b.Context(op)
|
||||
|
@ -39,11 +47,15 @@ func TestLocalContext_error(t *testing.T) {
|
|||
_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
|
||||
defer configCleanup()
|
||||
|
||||
streams, _ := terminal.StreamsForTesting(t)
|
||||
view := views.NewView(streams)
|
||||
stateLocker := clistate.NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
|
||||
|
||||
op := &backend.Operation{
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
Workspace: backend.DefaultStateName,
|
||||
LockState: true,
|
||||
StateLocker: stateLocker,
|
||||
}
|
||||
|
||||
_, _, diags := b.Context(op)
|
||||
|
@ -53,5 +65,4 @@ func TestLocalContext_error(t *testing.T) {
|
|||
|
||||
// Context() unlocks the state on failure
|
||||
assertBackendStateUnlocked(t, b)
|
||||
|
||||
}
|
||||
|
|
|
@ -73,9 +73,9 @@ func (b *Local) opPlan(
|
|||
// the state was locked during succesfull context creation; unlock the state
|
||||
// when the operation completes
|
||||
defer func() {
|
||||
err := op.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
op.ShowDiagnostics(err)
|
||||
diags := op.StateLocker.Unlock()
|
||||
if diags.HasErrors() {
|
||||
op.ShowDiagnostics(diags)
|
||||
runningOp.Result = backend.OperationFailure
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
|
@ -740,6 +741,7 @@ func testOperationPlan(t *testing.T, configDir string) (*backend.Operation, func
|
|||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
ShowDiagnostics: testLogDiagnostics(t),
|
||||
StateLocker: clistate.NewNoopLocker(),
|
||||
}, configCleanup
|
||||
}
|
||||
|
||||
|
|
|
@ -55,9 +55,9 @@ func (b *Local) opRefresh(
|
|||
// the state was locked during succesfull context creation; unlock the state
|
||||
// when the operation completes
|
||||
defer func() {
|
||||
err := op.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
op.ShowDiagnostics(err)
|
||||
diags := op.StateLocker.Unlock()
|
||||
if diags.HasErrors() {
|
||||
op.ShowDiagnostics(diags)
|
||||
runningOp.Result = backend.OperationFailure
|
||||
}
|
||||
}()
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/providers"
|
||||
|
@ -260,8 +261,8 @@ func testOperationRefresh(t *testing.T, configDir string) (*backend.Operation, f
|
|||
Type: backend.OperationTypeRefresh,
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
LockState: true,
|
||||
ShowDiagnostics: testLogDiagnostics(t),
|
||||
StateLocker: clistate.NewNoopLocker(),
|
||||
}, configCleanup
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,11 @@ import (
|
|||
version "github.com/hashicorp/go-version"
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/plans/planfile"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -26,14 +30,24 @@ import (
|
|||
func testOperationApply(t *testing.T, configDir string) (*backend.Operation, func()) {
|
||||
t.Helper()
|
||||
|
||||
return testOperationApplyWithTimeout(t, configDir, 0)
|
||||
}
|
||||
|
||||
func testOperationApplyWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func()) {
|
||||
t.Helper()
|
||||
|
||||
_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
|
||||
|
||||
streams, _ := terminal.StreamsForTesting(t)
|
||||
view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
|
||||
|
||||
return &backend.Operation{
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
Parallelism: defaultParallelism,
|
||||
PlanRefresh: true,
|
||||
ShowDiagnostics: testLogDiagnostics(t),
|
||||
StateLocker: clistate.NewLocker(timeout, view),
|
||||
Type: backend.OperationTypeApply,
|
||||
}, configCleanup
|
||||
}
|
||||
|
@ -878,7 +892,7 @@ func TestRemote_applyLockTimeout(t *testing.T) {
|
|||
t.Fatalf("error creating pending run: %v", err)
|
||||
}
|
||||
|
||||
op, configCleanup := testOperationApply(t, "./testdata/apply")
|
||||
op, configCleanup := testOperationApplyWithTimeout(t, "./testdata/apply", 50*time.Millisecond)
|
||||
defer configCleanup()
|
||||
|
||||
input := testInput(t, map[string]string{
|
||||
|
@ -886,7 +900,6 @@ func TestRemote_applyLockTimeout(t *testing.T) {
|
|||
"approve": "yes",
|
||||
})
|
||||
|
||||
op.StateLockTimeout = 50 * time.Millisecond
|
||||
op.UIIn = input
|
||||
op.UIOut = b.CLI
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/hashicorp/hcl/v2"
|
||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -23,11 +22,7 @@ import (
|
|||
func (b *Remote) Context(op *backend.Operation) (*terraform.Context, statemgr.Full, tfdiags.Diagnostics) {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
if op.LockState {
|
||||
op.StateLocker = clistate.NewLocker(context.Background(), op.StateLockTimeout, b.CLI, b.cliColorize())
|
||||
} else {
|
||||
op.StateLocker = clistate.NewNoopLocker()
|
||||
}
|
||||
op.StateLocker = op.StateLocker.WithContext(context.Background())
|
||||
|
||||
// Get the remote workspace name.
|
||||
remoteWorkspaceName := b.getRemoteWorkspaceName(op.Workspace)
|
||||
|
@ -41,8 +36,7 @@ func (b *Remote) Context(op *backend.Operation) (*terraform.Context, statemgr.Fu
|
|||
}
|
||||
|
||||
log.Printf("[TRACE] backend/remote: requesting state lock for workspace %q", remoteWorkspaceName)
|
||||
if err := op.StateLocker.Lock(stateMgr, op.Type.String()); err != nil {
|
||||
diags = diags.Append(errwrap.Wrapf("Error locking state: {{err}}", err))
|
||||
if diags := op.StateLocker.Lock(stateMgr, op.Type.String()); diags.HasErrors() {
|
||||
return nil, nil, diags
|
||||
}
|
||||
|
||||
|
@ -50,10 +44,7 @@ func (b *Remote) Context(op *backend.Operation) (*terraform.Context, statemgr.Fu
|
|||
// If we're returning with errors, and thus not producing a valid
|
||||
// context, we'll want to avoid leaving the remote workspace locked.
|
||||
if diags.HasErrors() {
|
||||
err := op.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
diags = diags.Append(errwrap.Wrapf("Error unlocking state: {{err}}", err))
|
||||
}
|
||||
diags = diags.Append(op.StateLocker.Unlock())
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -6,8 +6,12 @@ import (
|
|||
|
||||
tfe "github.com/hashicorp/go-tfe"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
@ -183,11 +187,14 @@ func TestRemoteContextWithVars(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
streams, _ := terminal.StreamsForTesting(t)
|
||||
view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
|
||||
|
||||
op := &backend.Operation{
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
StateLocker: clistate.NewLocker(0, view),
|
||||
Workspace: backend.DefaultStateName,
|
||||
LockState: true,
|
||||
}
|
||||
|
||||
v := test.Opts
|
||||
|
|
|
@ -260,15 +260,16 @@ in order to capture the filesystem context the remote workspace expects:
|
|||
return r, generalError("Failed to create run", err)
|
||||
}
|
||||
|
||||
// When the lock timeout is set,
|
||||
if op.StateLockTimeout > 0 {
|
||||
// When the lock timeout is set, if the run is still pending and
|
||||
// cancellable after that period, we attempt to cancel it.
|
||||
if lockTimeout := op.StateLocker.Timeout(); lockTimeout > 0 {
|
||||
go func() {
|
||||
select {
|
||||
case <-stopCtx.Done():
|
||||
return
|
||||
case <-cancelCtx.Done():
|
||||
return
|
||||
case <-time.After(op.StateLockTimeout):
|
||||
case <-time.After(lockTimeout):
|
||||
// Retrieve the run to get its current status.
|
||||
r, err := b.client.Runs.Read(cancelCtx, r.ID)
|
||||
if err != nil {
|
||||
|
|
|
@ -13,7 +13,11 @@ import (
|
|||
tfe "github.com/hashicorp/go-tfe"
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/internal/initwd"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/plans/planfile"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -24,14 +28,24 @@ import (
|
|||
func testOperationPlan(t *testing.T, configDir string) (*backend.Operation, func()) {
|
||||
t.Helper()
|
||||
|
||||
return testOperationPlanWithTimeout(t, configDir, 0)
|
||||
}
|
||||
|
||||
func testOperationPlanWithTimeout(t *testing.T, configDir string, timeout time.Duration) (*backend.Operation, func()) {
|
||||
t.Helper()
|
||||
|
||||
_, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir)
|
||||
|
||||
streams, _ := terminal.StreamsForTesting(t)
|
||||
view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams))
|
||||
|
||||
return &backend.Operation{
|
||||
ConfigDir: configDir,
|
||||
ConfigLoader: configLoader,
|
||||
Parallelism: defaultParallelism,
|
||||
PlanRefresh: true,
|
||||
ShowDiagnostics: testLogDiagnostics(t),
|
||||
StateLocker: clistate.NewLocker(timeout, view),
|
||||
Type: backend.OperationTypePlan,
|
||||
}, configCleanup
|
||||
}
|
||||
|
@ -625,7 +639,7 @@ func TestRemote_planLockTimeout(t *testing.T) {
|
|||
t.Fatalf("error creating pending run: %v", err)
|
||||
}
|
||||
|
||||
op, configCleanup := testOperationPlan(t, "./testdata/plan")
|
||||
op, configCleanup := testOperationPlanWithTimeout(t, "./testdata/plan", 50)
|
||||
defer configCleanup()
|
||||
|
||||
input := testInput(t, map[string]string{
|
||||
|
@ -633,7 +647,6 @@ func TestRemote_planLockTimeout(t *testing.T) {
|
|||
"approve": "yes",
|
||||
})
|
||||
|
||||
op.StateLockTimeout = 50 * time.Millisecond
|
||||
op.UIIn = input
|
||||
op.UIOut = b.CLI
|
||||
op.Workspace = backend.DefaultStateName
|
||||
|
|
|
@ -940,6 +940,7 @@ func TestApply_planNoModuleFiles(t *testing.T) {
|
|||
|
||||
p := applyFixtureProvider()
|
||||
planPath := applyFixturePlanFile(t)
|
||||
view, _ := testView(t)
|
||||
|
||||
view, _ := testView(t)
|
||||
apply := &ApplyCommand{
|
||||
|
|
|
@ -7,33 +7,25 @@ package clistate
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/internal/helper/slowmessage"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/colorstring"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
||||
const (
|
||||
LockThreshold = 400 * time.Millisecond
|
||||
LockMessage = "Acquiring state lock. This may take a few moments..."
|
||||
LockErrorMessage = `Error acquiring the state lock: {{err}}
|
||||
LockErrorMessage = `Error message: %s
|
||||
|
||||
Terraform acquires a state lock to protect the state from being written
|
||||
by multiple users at the same time. Please resolve the issue above and try
|
||||
again. For most commands, you can disable locking with the "-lock=false"
|
||||
flag, but this is not recommended.`
|
||||
|
||||
UnlockMessage = "Releasing state lock. This may take a few moments..."
|
||||
UnlockErrorMessage = `
|
||||
[reset][bold][red]Error releasing the state lock![reset][red]
|
||||
|
||||
Error message: %s
|
||||
UnlockErrorMessage = `Error message: %s
|
||||
|
||||
Terraform acquires a lock when accessing your state to prevent others
|
||||
running Terraform to potentially modify the state at the same time. An
|
||||
|
@ -46,8 +38,7 @@ In this scenario, please call the "force-unlock" command to unlock the
|
|||
state manually. This is a very dangerous operation since if it is done
|
||||
erroneously it could result in two people modifying state at the same time.
|
||||
Only call this command if you're certain that the unlock above failed and
|
||||
that no one else is holding a lock.
|
||||
`
|
||||
that no one else is holding a lock.`
|
||||
)
|
||||
|
||||
// Locker allows for more convenient usage of the lower-level statemgr.Locker
|
||||
|
@ -60,12 +51,17 @@ that no one else is holding a lock.
|
|||
// Unlock, which is at a minimum the LockID string returned by the
|
||||
// statemgr.Locker.
|
||||
type Locker interface {
|
||||
// Returns a shallow copy of the locker with its context changed to ctx.
|
||||
WithContext(ctx context.Context) Locker
|
||||
|
||||
// Lock the provided state manager, storing the reason string in the LockInfo.
|
||||
Lock(s statemgr.Locker, reason string) error
|
||||
Lock(s statemgr.Locker, reason string) tfdiags.Diagnostics
|
||||
|
||||
// Unlock the previously locked state.
|
||||
// An optional error can be passed in, and will be combined with any error
|
||||
// from the Unlock operation.
|
||||
Unlock(error) error
|
||||
Unlock() tfdiags.Diagnostics
|
||||
|
||||
// Timeout returns the configured timeout duration
|
||||
Timeout() time.Duration
|
||||
}
|
||||
|
||||
type locker struct {
|
||||
|
@ -73,34 +69,43 @@ type locker struct {
|
|||
ctx context.Context
|
||||
timeout time.Duration
|
||||
state statemgr.Locker
|
||||
ui cli.Ui
|
||||
color *colorstring.Colorize
|
||||
view views.StateLocker
|
||||
lockID string
|
||||
}
|
||||
|
||||
var _ Locker = (*locker)(nil)
|
||||
|
||||
// Create a new Locker.
|
||||
// This Locker uses state.LockWithContext to retry the lock until the provided
|
||||
// timeout is reached, or the context is canceled. Lock progress will be be
|
||||
// reported to the user through the provided UI.
|
||||
func NewLocker(
|
||||
ctx context.Context,
|
||||
timeout time.Duration,
|
||||
ui cli.Ui,
|
||||
color *colorstring.Colorize) Locker {
|
||||
|
||||
l := &locker{
|
||||
ctx: ctx,
|
||||
func NewLocker(timeout time.Duration, view views.StateLocker) Locker {
|
||||
return &locker{
|
||||
ctx: context.Background(),
|
||||
timeout: timeout,
|
||||
ui: ui,
|
||||
color: color,
|
||||
view: view,
|
||||
}
|
||||
}
|
||||
|
||||
// WithContext returns a new Locker with the specified context, copying the
|
||||
// timeout and view parameters from the original Locker.
|
||||
func (l *locker) WithContext(ctx context.Context) Locker {
|
||||
if ctx == nil {
|
||||
panic("nil context")
|
||||
}
|
||||
return &locker{
|
||||
ctx: ctx,
|
||||
timeout: l.timeout,
|
||||
view: l.view,
|
||||
}
|
||||
return l
|
||||
}
|
||||
|
||||
// Locker locks the given state and outputs to the user if locking is taking
|
||||
// longer than the threshold. The lock is retried until the context is
|
||||
// cancelled.
|
||||
func (l *locker) Lock(s statemgr.Locker, reason string) error {
|
||||
func (l *locker) Lock(s statemgr.Locker, reason string) tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
|
@ -116,46 +121,49 @@ func (l *locker) Lock(s statemgr.Locker, reason string) error {
|
|||
id, err := statemgr.LockWithContext(ctx, s, lockInfo)
|
||||
l.lockID = id
|
||||
return err
|
||||
}, func() {
|
||||
if l.ui != nil {
|
||||
l.ui.Output(l.color.Color(LockMessage))
|
||||
}
|
||||
})
|
||||
}, l.view.Locking)
|
||||
|
||||
if err != nil {
|
||||
return errwrap.Wrapf(strings.TrimSpace(LockErrorMessage), err)
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Error acquiring the state lock",
|
||||
fmt.Sprintf(LockErrorMessage, err),
|
||||
))
|
||||
}
|
||||
|
||||
return nil
|
||||
return diags
|
||||
}
|
||||
|
||||
func (l *locker) Unlock(parentErr error) error {
|
||||
func (l *locker) Unlock() tfdiags.Diagnostics {
|
||||
var diags tfdiags.Diagnostics
|
||||
|
||||
l.mu.Lock()
|
||||
defer l.mu.Unlock()
|
||||
|
||||
if l.lockID == "" {
|
||||
return parentErr
|
||||
return diags
|
||||
}
|
||||
|
||||
err := slowmessage.Do(LockThreshold, func() error {
|
||||
return l.state.Unlock(l.lockID)
|
||||
}, func() {
|
||||
if l.ui != nil {
|
||||
l.ui.Output(l.color.Color(UnlockMessage))
|
||||
}
|
||||
})
|
||||
}, l.view.Unlocking)
|
||||
|
||||
if err != nil {
|
||||
l.ui.Output(l.color.Color(fmt.Sprintf(
|
||||
"\n"+strings.TrimSpace(UnlockErrorMessage)+"\n", err)))
|
||||
|
||||
parentErr = multierror.Append(parentErr, err)
|
||||
diags = diags.Append(tfdiags.Sourceless(
|
||||
tfdiags.Error,
|
||||
"Error releasing the state lock",
|
||||
fmt.Sprintf(UnlockErrorMessage, err),
|
||||
))
|
||||
}
|
||||
|
||||
return parentErr
|
||||
return diags
|
||||
|
||||
}
|
||||
|
||||
func (l *locker) Timeout() time.Duration {
|
||||
return l.timeout
|
||||
}
|
||||
|
||||
type noopLocker struct{}
|
||||
|
||||
// NewNoopLocker returns a valid Locker that does nothing.
|
||||
|
@ -163,10 +171,20 @@ func NewNoopLocker() Locker {
|
|||
return noopLocker{}
|
||||
}
|
||||
|
||||
func (l noopLocker) Lock(statemgr.Locker, string) error {
|
||||
var _ Locker = noopLocker{}
|
||||
|
||||
func (l noopLocker) WithContext(ctx context.Context) Locker {
|
||||
return l
|
||||
}
|
||||
|
||||
func (l noopLocker) Lock(statemgr.Locker, string) tfdiags.Diagnostics {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l noopLocker) Unlock(err error) error {
|
||||
return err
|
||||
func (l noopLocker) Unlock() tfdiags.Diagnostics {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l noopLocker) Timeout() time.Duration {
|
||||
return 0
|
||||
}
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
package clistate
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/colorstring"
|
||||
)
|
||||
|
||||
func TestUnlock(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
streams, _ := terminal.StreamsForTesting(t)
|
||||
view := views.NewView(streams)
|
||||
|
||||
l := NewLocker(context.Background(), 0, ui, &colorstring.Colorize{Disable: true})
|
||||
l := NewLocker(0, views.NewStateLocker(arguments.ViewHuman, view))
|
||||
l.Lock(statemgr.NewUnlockErrorFull(nil, nil), "test-lock")
|
||||
|
||||
err := l.Unlock(nil)
|
||||
if err != nil {
|
||||
t.Log(err.Error())
|
||||
diags := l.Unlock()
|
||||
if diags.HasErrors() {
|
||||
t.Log(diags.Err().Error())
|
||||
} else {
|
||||
t.Error("expected error")
|
||||
}
|
||||
|
|
|
@ -104,9 +104,9 @@ func (c *ConsoleCommand) Run(args []string) int {
|
|||
|
||||
// Successfully creating the context can result in a lock, so ensure we release it
|
||||
defer func() {
|
||||
err := opReq.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
diags := opReq.StateLocker.Unlock()
|
||||
if diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -27,10 +27,12 @@ func TestConsole_basic(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &ConsoleCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -76,10 +78,12 @@ func TestConsole_tfvars(t *testing.T) {
|
|||
},
|
||||
}
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &ConsoleCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -127,10 +131,12 @@ func TestConsole_unsetRequiredVars(t *testing.T) {
|
|||
},
|
||||
}
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &ConsoleCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -159,10 +165,12 @@ func TestConsole_variables(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &ConsoleCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -200,11 +208,13 @@ func TestConsole_modules(t *testing.T) {
|
|||
|
||||
p := applyFixtureProvider()
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
|
||||
c := &ConsoleCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -218,9 +218,9 @@ func (c *ImportCommand) Run(args []string) int {
|
|||
|
||||
// Successfully creating the context can result in a lock, so ensure we release it
|
||||
defer func() {
|
||||
err := opReq.StateLocker.Unlock(nil)
|
||||
if err != nil {
|
||||
c.Ui.Error(err.Error())
|
||||
diags := opReq.StateLocker.Unlock()
|
||||
if diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -35,10 +35,12 @@ func TestInit_empty(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -56,10 +58,12 @@ func TestInit_multipleArgs(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -80,10 +84,12 @@ func TestInit_fromModule_cwdDest(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -130,10 +136,12 @@ func TestInit_fromModule_dstInSrc(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -157,10 +165,12 @@ func TestInit_get(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -184,10 +194,12 @@ func TestInit_getUpgradeModules(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -214,10 +226,12 @@ func TestInit_backend(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -242,10 +256,12 @@ func TestInit_backendUnset(t *testing.T) {
|
|||
log.Printf("[TRACE] TestInit_backendUnset: beginning first init")
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -272,10 +288,12 @@ func TestInit_backendUnset(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -303,10 +321,12 @@ func TestInit_backendConfigFile(t *testing.T) {
|
|||
|
||||
t.Run("good-config-file", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{"-backend-config", "input.config"}
|
||||
|
@ -324,10 +344,12 @@ func TestInit_backendConfigFile(t *testing.T) {
|
|||
// the backend config file must not be a full terraform block
|
||||
t.Run("full-backend-config-file", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{"-backend-config", "backend.config"}
|
||||
|
@ -342,10 +364,12 @@ func TestInit_backendConfigFile(t *testing.T) {
|
|||
// the backend config file must match the schema for the backend
|
||||
t.Run("invalid-config-file", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{"-backend-config", "invalid.config"}
|
||||
|
@ -360,10 +384,12 @@ func TestInit_backendConfigFile(t *testing.T) {
|
|||
// missing file is an error
|
||||
t.Run("missing-config-file", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{"-backend-config", "missing.config"}
|
||||
|
@ -378,10 +404,12 @@ func TestInit_backendConfigFile(t *testing.T) {
|
|||
// blank filename clears the backend config
|
||||
t.Run("blank-config-file", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
args := []string{"-backend-config="}
|
||||
|
@ -429,10 +457,12 @@ func TestInit_backendConfigFilePowershellConfusion(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -468,10 +498,12 @@ func TestInit_backendConfigFileChange(t *testing.T) {
|
|||
})()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -495,10 +527,12 @@ func TestInit_backendConfigKV(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -522,10 +556,12 @@ func TestInit_backendConfigKVReInit(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -539,6 +575,7 @@ func TestInit_backendConfigKVReInit(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -583,10 +620,12 @@ func TestInit_backendConfigKVReInitWithConfigDiff(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -600,6 +639,7 @@ func TestInit_backendConfigKVReInitWithConfigDiff(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -629,10 +669,12 @@ func TestInit_backendCli_no_config_block(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -667,10 +709,12 @@ func TestInit_backendReinitWithExtra(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -710,10 +754,12 @@ func TestInit_backendReinitConfigToExtra(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -741,6 +787,7 @@ func TestInit_backendReinitConfigToExtra(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -766,10 +813,12 @@ func TestInit_inputFalse(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -805,6 +854,7 @@ func TestInit_inputFalse(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -823,6 +873,7 @@ func TestInit_inputFalse(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -842,6 +893,7 @@ func TestInit_getProvider(t *testing.T) {
|
|||
|
||||
overrides := metaOverridesForProvider(testProvider())
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
providerSource, close := newMockProviderSource(t, map[string][]string{
|
||||
// looking for an exact version
|
||||
"exact": {"1.2.3"},
|
||||
|
@ -854,6 +906,7 @@ func TestInit_getProvider(t *testing.T) {
|
|||
m := Meta{
|
||||
testingOverrides: overrides,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -919,7 +972,9 @@ func TestInit_getProvider(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m.Ui = ui
|
||||
m.View = view
|
||||
c := &InitCommand{
|
||||
Meta: m,
|
||||
}
|
||||
|
@ -944,6 +999,7 @@ func TestInit_getProviderSource(t *testing.T) {
|
|||
|
||||
overrides := metaOverridesForProvider(testProvider())
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
providerSource, close := newMockProviderSource(t, map[string][]string{
|
||||
// looking for an exact version
|
||||
"acme/alpha": {"1.2.3"},
|
||||
|
@ -955,6 +1011,7 @@ func TestInit_getProviderSource(t *testing.T) {
|
|||
m := Meta{
|
||||
testingOverrides: overrides,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -993,6 +1050,7 @@ func TestInit_getProviderLegacyFromState(t *testing.T) {
|
|||
|
||||
overrides := metaOverridesForProvider(testProvider())
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
providerSource, close := newMockProviderSource(t, map[string][]string{
|
||||
"acme/alpha": {"1.2.3"},
|
||||
})
|
||||
|
@ -1000,6 +1058,7 @@ func TestInit_getProviderLegacyFromState(t *testing.T) {
|
|||
m := Meta{
|
||||
testingOverrides: overrides,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1033,6 +1092,7 @@ func TestInit_getProviderInvalidPackage(t *testing.T) {
|
|||
|
||||
overrides := metaOverridesForProvider(testProvider())
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
|
||||
// create a provider source which allows installing an invalid package
|
||||
addr := addrs.MustParseProviderSourceString("invalid/package")
|
||||
|
@ -1053,6 +1113,7 @@ func TestInit_getProviderInvalidPackage(t *testing.T) {
|
|||
m := Meta{
|
||||
testingOverrides: overrides,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1109,8 +1170,10 @@ func TestInit_getProviderDetectedLegacy(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: multiSource,
|
||||
}
|
||||
|
||||
|
@ -1166,9 +1229,11 @@ func TestInit_providerSource(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1277,9 +1342,11 @@ func TestInit_cancel(t *testing.T) {
|
|||
close(shutdownCh)
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
ShutdownCh: shutdownCh,
|
||||
}
|
||||
|
@ -1320,9 +1387,11 @@ func TestInit_getUpgradePlugins(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1444,9 +1513,11 @@ func TestInit_getProviderMissing(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1472,10 +1543,12 @@ func TestInit_checkRequiredVersion(t *testing.T) {
|
|||
defer testChdir(t, td)()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -1505,9 +1578,11 @@ func TestInit_providerLockFile(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1555,10 +1630,12 @@ func TestInit_pluginDirReset(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
},
|
||||
}
|
||||
|
@ -1591,6 +1668,7 @@ func TestInit_pluginDirReset(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource, // still empty
|
||||
},
|
||||
}
|
||||
|
@ -1623,9 +1701,11 @@ func TestInit_pluginDirProviders(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1723,9 +1803,11 @@ func TestInit_pluginDirProvidersDoesNotGet(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1795,9 +1877,11 @@ func TestInit_pluginDirWithBuiltIn(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
@ -1832,9 +1916,11 @@ func TestInit_invalidBuiltInProviders(t *testing.T) {
|
|||
defer close()
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,9 @@ import (
|
|||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
remoteBackend "github.com/hashicorp/terraform/backend/remote"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/plans"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
|
@ -341,15 +343,20 @@ func (m *Meta) Operation(b backend.Backend) *backend.Operation {
|
|||
panic(fmt.Sprintf("failed to encode backend configuration for plan: %s", err))
|
||||
}
|
||||
|
||||
stateLocker := clistate.NewNoopLocker()
|
||||
if m.stateLock {
|
||||
view := views.NewStateLocker(arguments.ViewHuman, m.View)
|
||||
stateLocker = clistate.NewLocker(m.stateLockTimeout, view)
|
||||
}
|
||||
|
||||
return &backend.Operation{
|
||||
PlanOutBackend: planOutBackend,
|
||||
Parallelism: m.parallelism,
|
||||
Targets: m.targets,
|
||||
UIIn: m.UIInput(),
|
||||
UIOut: m.Ui,
|
||||
Workspace: workspace,
|
||||
LockState: m.stateLock,
|
||||
StateLockTimeout: m.stateLockTimeout,
|
||||
PlanOutBackend: planOutBackend,
|
||||
Parallelism: m.parallelism,
|
||||
Targets: m.targets,
|
||||
UIIn: m.UIInput(),
|
||||
UIOut: m.Ui,
|
||||
Workspace: workspace,
|
||||
StateLocker: stateLocker,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -802,12 +809,13 @@ func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *clistate.Local
|
|||
}
|
||||
|
||||
if m.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), m.stateLockTimeout, m.Ui, m.Colorize())
|
||||
view := views.NewStateLocker(arguments.ViewHuman, m.View)
|
||||
stateLocker := clistate.NewLocker(m.stateLockTimeout, view)
|
||||
if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
|
||||
diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
|
||||
return nil, diags
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer stateLocker.Unlock()
|
||||
}
|
||||
|
||||
configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
|
||||
|
@ -886,12 +894,13 @@ func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *clista
|
|||
}
|
||||
|
||||
if m.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), m.stateLockTimeout, m.Ui, m.Colorize())
|
||||
view := views.NewStateLocker(arguments.ViewHuman, m.View)
|
||||
stateLocker := clistate.NewLocker(m.stateLockTimeout, view)
|
||||
if err := stateLocker.Lock(sMgr, "backend from plan"); err != nil {
|
||||
diags = diags.Append(fmt.Errorf("Error locking state: %s", err))
|
||||
return nil, diags
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer stateLocker.Unlock()
|
||||
}
|
||||
|
||||
configJSON, err := ctyjson.Marshal(configVal, b.ConfigSchema().ImpliedType())
|
||||
|
|
|
@ -12,7 +12,9 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -325,17 +327,20 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
if m.stateLock {
|
||||
lockCtx := context.Background()
|
||||
|
||||
lockerOne := clistate.NewLocker(lockCtx, m.stateLockTimeout, m.Ui, m.Colorize())
|
||||
if err := lockerOne.Lock(stateOne, "migration source state"); err != nil {
|
||||
return fmt.Errorf("Error locking source state: %s", err)
|
||||
}
|
||||
defer lockerOne.Unlock(nil)
|
||||
view := views.NewStateLocker(arguments.ViewHuman, m.View)
|
||||
locker := clistate.NewLocker(m.stateLockTimeout, view)
|
||||
|
||||
lockerTwo := clistate.NewLocker(lockCtx, m.stateLockTimeout, m.Ui, m.Colorize())
|
||||
if err := lockerTwo.Lock(stateTwo, "migration destination state"); err != nil {
|
||||
return fmt.Errorf("Error locking destination state: %s", err)
|
||||
lockerOne := locker.WithContext(lockCtx)
|
||||
if diags := lockerOne.Lock(stateOne, "migration source state"); diags.HasErrors() {
|
||||
return diags.Err()
|
||||
}
|
||||
defer lockerTwo.Unlock(nil)
|
||||
defer lockerOne.Unlock()
|
||||
|
||||
lockerTwo := locker.WithContext(lockCtx)
|
||||
if diags := lockerTwo.Lock(stateTwo, "migration destination state"); diags.HasErrors() {
|
||||
return diags.Err()
|
||||
}
|
||||
defer lockerTwo.Unlock()
|
||||
|
||||
// We now own a lock, so double check that we have the version
|
||||
// corresponding to the lock.
|
||||
|
|
|
@ -1876,6 +1876,8 @@ func TestBackendFromState(t *testing.T) {
|
|||
func testMetaBackend(t *testing.T, args []string) *Meta {
|
||||
var m Meta
|
||||
m.Ui = new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m.View = view
|
||||
m.process(args)
|
||||
f := m.extendedFlagSet("test")
|
||||
if err := f.Parse(args); err != nil {
|
||||
|
|
|
@ -22,10 +22,12 @@ import (
|
|||
|
||||
func TestShow(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -46,10 +48,12 @@ func TestShow_noArgs(t *testing.T) {
|
|||
defer testChdir(t, stateDir)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -93,10 +97,12 @@ func TestShow_aliasedProvider(t *testing.T) {
|
|||
defer testChdir(t, stateDir)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -121,10 +127,12 @@ func TestShow_noArgsNoState(t *testing.T) {
|
|||
defer testChdir(t, stateDir)()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -139,10 +147,12 @@ func TestShow_plan(t *testing.T) {
|
|||
planPath := testPlanFileNoop(t)
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -164,10 +174,12 @@ func TestShow_planWithChanges(t *testing.T) {
|
|||
planPathWithChanges := showFixturePlanFile(t, plans.DeleteThenCreate)
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(showFixtureProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -190,10 +202,12 @@ func TestShow_plan_json(t *testing.T) {
|
|||
planPath := showFixturePlanFile(t, plans.Create)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(showFixtureProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -212,10 +226,12 @@ func TestShow_state(t *testing.T) {
|
|||
defer os.RemoveAll(filepath.Dir(statePath))
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &ShowCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -354,9 +370,11 @@ func TestShow_json_output_state(t *testing.T) {
|
|||
|
||||
p := showFixtureProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
m := Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
ProviderSource: providerSource,
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/mitchellh/cli"
|
||||
|
@ -49,12 +50,16 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateFromMgr, "state-mv"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking source state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateFromMgr, "state-mv"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := stateFromMgr.RefreshState(); err != nil {
|
||||
|
@ -83,12 +88,16 @@ func (c *StateMvCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateToMgr, "state-mv"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking destination state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateToMgr, "state-mv"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := stateToMgr.RefreshState(); err != nil {
|
||||
|
|
|
@ -58,11 +58,13 @@ func TestStateMv(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -204,11 +206,13 @@ func TestStateMv_resourceToInstance(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -277,12 +281,14 @@ func TestStateMv_resourceToInstanceErr(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -344,11 +350,13 @@ func TestStateMv_resourceToInstanceErrInAutomation(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
RunningInAutomation: true,
|
||||
},
|
||||
},
|
||||
|
@ -416,11 +424,13 @@ func TestStateMv_instanceToResource(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -489,11 +499,13 @@ func TestStateMv_instanceToNewResource(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -560,11 +572,13 @@ func TestStateMv_differentResourceTypes(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -636,10 +650,12 @@ func TestStateMv_explicitWithBackend(t *testing.T) {
|
|||
|
||||
// init our backend
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
ic := &InitCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -656,6 +672,7 @@ func TestStateMv_explicitWithBackend(t *testing.T) {
|
|||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -713,11 +730,13 @@ func TestStateMv_backupExplicit(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -762,11 +781,13 @@ func TestStateMv_stateOutNew(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -834,11 +855,13 @@ func TestStateMv_stateOutExisting(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -877,11 +900,13 @@ func TestStateMv_noState(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -945,11 +970,13 @@ func TestStateMv_stateOutNew_count(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1019,11 +1046,13 @@ func TestStateMv_stateOutNew_largeCount(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1089,11 +1118,13 @@ func TestStateMv_stateOutNew_nestedModule(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1145,11 +1176,13 @@ func TestStateMv_toNewModule(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1244,11 +1277,13 @@ func TestStateMv_withinBackend(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1314,11 +1349,13 @@ func TestStateMv_fromBackendToLocal(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -1365,11 +1402,13 @@ func TestStateMv_onlyResourceInModule(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateMvCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states/statefile"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/mitchellh/cli"
|
||||
|
@ -93,12 +94,16 @@ func (c *StatePushCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "state-push"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "state-push"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := stateMgr.RefreshState(); err != nil {
|
||||
|
|
|
@ -23,10 +23,12 @@ func TestStatePush_empty(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -50,10 +52,12 @@ func TestStatePush_lockedState(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -83,10 +87,12 @@ func TestStatePush_replaceMatch(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -119,10 +125,12 @@ func TestStatePush_replaceMatchStdin(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -148,10 +156,12 @@ func TestStatePush_lineageMismatch(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -177,10 +187,12 @@ func TestStatePush_serialNewer(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -206,10 +218,12 @@ func TestStatePush_serialOlder(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -236,8 +250,9 @@ func TestStatePush_forceRemoteState(t *testing.T) {
|
|||
|
||||
// init the backend
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
initCmd := &InitCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
if code := initCmd.Run([]string{}); code != 0 {
|
||||
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
||||
|
@ -246,7 +261,7 @@ func TestStatePush_forceRemoteState(t *testing.T) {
|
|||
// create a new workspace
|
||||
ui = new(cli.MockUi)
|
||||
newCmd := &WorkspaceNewCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
if code := newCmd.Run([]string{"test"}); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -268,7 +283,7 @@ func TestStatePush_forceRemoteState(t *testing.T) {
|
|||
// push our local state to that new workspace
|
||||
ui = new(cli.MockUi)
|
||||
c := &StatePushCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
|
||||
args := []string{"-force", statePath}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/mitchellh/cli"
|
||||
|
@ -74,12 +75,16 @@ func (c *StateReplaceProviderCommand) Run(args []string) int {
|
|||
|
||||
// Acquire lock if requested
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "state-replace-provider"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking source state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "state-replace-provider"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Refresh and load state
|
||||
|
|
|
@ -65,10 +65,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -99,10 +101,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -133,10 +137,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -166,10 +172,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -193,10 +201,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
|
||||
t.Run("invalid flags", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -217,10 +227,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
|
||||
t.Run("wrong number of arguments", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -237,10 +249,12 @@ func TestStateReplaceProvider(t *testing.T) {
|
|||
|
||||
t.Run("invalid provider strings", func(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateReplaceProviderCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
@ -44,12 +45,16 @@ func (c *StateRmCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "state-rm"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "state-rm"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := stateMgr.RefreshState(); err != nil {
|
||||
|
|
|
@ -49,11 +49,13 @@ func TestStateRm(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -117,11 +119,13 @@ func TestStateRmNotChildModule(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -203,11 +207,13 @@ func TestStateRmNoArgs(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -262,11 +268,13 @@ func TestStateRmNonExist(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -318,11 +326,13 @@ func TestStateRm_backupExplicit(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -349,11 +359,13 @@ func TestStateRm_noState(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -372,11 +384,13 @@ func TestStateRm_needsInit(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -446,11 +460,13 @@ func TestStateRm_backendState(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &StateRmCommand{
|
||||
StateMeta{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
|
@ -116,12 +117,16 @@ func (c *TaintCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "taint"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "taint"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := stateMgr.RefreshState(); err != nil {
|
||||
|
|
|
@ -33,9 +33,11 @@ func TestTaint(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -76,9 +78,11 @@ func TestTaint_lockedState(t *testing.T) {
|
|||
}
|
||||
defer unlock()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -122,9 +126,11 @@ func TestTaint_backup(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -165,9 +171,11 @@ func TestTaint_backupDisable(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -188,9 +196,11 @@ func TestTaint_backupDisable(t *testing.T) {
|
|||
|
||||
func TestTaint_badState(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -229,9 +239,11 @@ func TestTaint_defaultState(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -271,7 +283,8 @@ func TestTaint_defaultWorkspaceState(t *testing.T) {
|
|||
path := testStateFileWorkspaceDefault(t, testWorkspace, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
meta := Meta{Ui: ui}
|
||||
view, _ := testView(t)
|
||||
meta := Meta{Ui: ui, View: view}
|
||||
meta.SetWorkspace(testWorkspace)
|
||||
c := &TaintCommand{
|
||||
Meta: meta,
|
||||
|
@ -308,9 +321,11 @@ func TestTaint_missing(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -344,9 +359,11 @@ func TestTaint_missingAllow(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -399,9 +416,11 @@ func TestTaint_stateOut(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -453,9 +472,11 @@ func TestTaint_module(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -498,10 +519,12 @@ func TestTaint_checkRequiredVersion(t *testing.T) {
|
|||
path := testStateFile(t, state)
|
||||
|
||||
ui := cli.NewMockUi()
|
||||
view, _ := testView(t)
|
||||
c := &TaintCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(testProvider()),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -34,10 +34,12 @@ func TestUnlock(t *testing.T) {
|
|||
|
||||
p := testProvider()
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UnlockCommand{
|
||||
Meta: Meta{
|
||||
testingOverrides: metaOverridesForProvider(p),
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -72,9 +74,11 @@ func TestUnlock_inmemBackend(t *testing.T) {
|
|||
|
||||
// init backend
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
ci := &InitCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
if code := ci.Run(nil); code != 0 {
|
||||
|
@ -84,7 +88,8 @@ func TestUnlock_inmemBackend(t *testing.T) {
|
|||
ui = new(cli.MockUi)
|
||||
c := &UnlockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -101,7 +106,8 @@ func TestUnlock_inmemBackend(t *testing.T) {
|
|||
ui = new(cli.MockUi)
|
||||
c = &UnlockCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
)
|
||||
|
@ -81,12 +82,16 @@ func (c *UntaintCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if c.stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), c.stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "untaint"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "untaint"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
if err := stateMgr.RefreshState(); err != nil {
|
||||
|
|
|
@ -32,9 +32,11 @@ func TestUntaint(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -80,9 +82,11 @@ func TestUntaint_lockedState(t *testing.T) {
|
|||
defer unlock()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -126,9 +130,11 @@ func TestUntaint_backup(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -180,9 +186,11 @@ func TestUntaint_backupDisable(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -207,9 +215,11 @@ test_instance.foo:
|
|||
|
||||
func TestUntaint_badState(t *testing.T) {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -248,9 +258,11 @@ func TestUntaint_defaultState(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -295,7 +307,8 @@ func TestUntaint_defaultWorkspaceState(t *testing.T) {
|
|||
path := testStateFileWorkspaceDefault(t, testWorkspace, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
meta := Meta{Ui: ui}
|
||||
view, _ := testView(t)
|
||||
meta := Meta{Ui: ui, View: view}
|
||||
meta.SetWorkspace(testWorkspace)
|
||||
c := &UntaintCommand{
|
||||
Meta: meta,
|
||||
|
@ -336,9 +349,11 @@ func TestUntaint_missing(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -372,9 +387,11 @@ func TestUntaint_missingAllow(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -427,9 +444,11 @@ func TestUntaint_stateOut(t *testing.T) {
|
|||
testStateFileDefault(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -489,9 +508,11 @@ func TestUntaint_module(t *testing.T) {
|
|||
statePath := testStateFile(t, state)
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
c := &UntaintCommand{
|
||||
Meta: Meta{
|
||||
Ui: ui,
|
||||
Ui: ui,
|
||||
View: view,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package views
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
)
|
||||
|
||||
// The StateLocker view is used to display locking/unlocking status messages
|
||||
// if the state lock process takes longer than expected.
|
||||
type StateLocker interface {
|
||||
Locking()
|
||||
Unlocking()
|
||||
}
|
||||
|
||||
// NewStateLocker returns an initialized StateLocker implementation for the given ViewType.
|
||||
func NewStateLocker(vt arguments.ViewType, view *View) StateLocker {
|
||||
switch vt {
|
||||
case arguments.ViewHuman:
|
||||
return &StateLockerHuman{View: *view}
|
||||
default:
|
||||
panic(fmt.Sprintf("unknown view type %v", vt))
|
||||
}
|
||||
}
|
||||
|
||||
// StateLockerHuman is an implementation of StateLocker which prints status to
|
||||
// a terminal.
|
||||
type StateLockerHuman struct {
|
||||
View
|
||||
}
|
||||
|
||||
var _ StateLocker = (*StateLockerHuman)(nil)
|
||||
|
||||
func (v *StateLockerHuman) Locking() {
|
||||
v.streams.Println("Acquiring state lock. This may take a few moments...")
|
||||
}
|
||||
|
||||
func (v *StateLockerHuman) Unlocking() {
|
||||
v.streams.Println("Releasing state lock. This may take a few moments...")
|
||||
}
|
|
@ -34,7 +34,8 @@ func TestWorkspace_createAndChange(t *testing.T) {
|
|||
|
||||
args := []string{"test"}
|
||||
ui := new(cli.MockUi)
|
||||
newCmd.Meta = Meta{Ui: ui}
|
||||
view, _ := testView(t)
|
||||
newCmd.Meta = Meta{Ui: ui, View: view}
|
||||
if code := newCmd.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
}
|
||||
|
@ -47,7 +48,7 @@ func TestWorkspace_createAndChange(t *testing.T) {
|
|||
selCmd := &WorkspaceSelectCommand{}
|
||||
args = []string{backend.DefaultStateName}
|
||||
ui = new(cli.MockUi)
|
||||
selCmd.Meta = Meta{Ui: ui}
|
||||
selCmd.Meta = Meta{Ui: ui, View: view}
|
||||
if code := selCmd.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
}
|
||||
|
@ -83,8 +84,9 @@ func TestWorkspace_createAndList(t *testing.T) {
|
|||
// create multiple workspaces
|
||||
for _, env := range envs {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
newCmd := &WorkspaceNewCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
if code := newCmd.Run([]string{env}); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -93,7 +95,8 @@ func TestWorkspace_createAndList(t *testing.T) {
|
|||
|
||||
listCmd := &WorkspaceListCommand{}
|
||||
ui := new(cli.MockUi)
|
||||
listCmd.Meta = Meta{Ui: ui}
|
||||
view, _ := testView(t)
|
||||
listCmd.Meta = Meta{Ui: ui, View: view}
|
||||
|
||||
if code := listCmd.Run(nil); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -128,7 +131,8 @@ func TestWorkspace_createAndShow(t *testing.T) {
|
|||
// make sure current workspace show outputs "default"
|
||||
showCmd := &WorkspaceShowCommand{}
|
||||
ui := new(cli.MockUi)
|
||||
showCmd.Meta = Meta{Ui: ui}
|
||||
view, _ := testView(t)
|
||||
showCmd.Meta = Meta{Ui: ui, View: view}
|
||||
|
||||
if code := showCmd.Run(nil); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -147,21 +151,21 @@ func TestWorkspace_createAndShow(t *testing.T) {
|
|||
|
||||
// create test_a workspace
|
||||
ui = new(cli.MockUi)
|
||||
newCmd.Meta = Meta{Ui: ui}
|
||||
newCmd.Meta = Meta{Ui: ui, View: view}
|
||||
if code := newCmd.Run(env); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
}
|
||||
|
||||
selCmd := &WorkspaceSelectCommand{}
|
||||
ui = new(cli.MockUi)
|
||||
selCmd.Meta = Meta{Ui: ui}
|
||||
selCmd.Meta = Meta{Ui: ui, View: view}
|
||||
if code := selCmd.Run(env); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
}
|
||||
|
||||
showCmd = &WorkspaceShowCommand{}
|
||||
ui = new(cli.MockUi)
|
||||
showCmd.Meta = Meta{Ui: ui}
|
||||
showCmd.Meta = Meta{Ui: ui, View: view}
|
||||
|
||||
if code := showCmd.Run(nil); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -188,8 +192,9 @@ func TestWorkspace_createInvalid(t *testing.T) {
|
|||
// create multiple workspaces
|
||||
for _, env := range envs {
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
newCmd := &WorkspaceNewCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
if code := newCmd.Run([]string{env}); code == 0 {
|
||||
t.Fatalf("expected failure: \n%s", ui.OutputWriter)
|
||||
|
@ -199,7 +204,8 @@ func TestWorkspace_createInvalid(t *testing.T) {
|
|||
// list workspaces to make sure none were created
|
||||
listCmd := &WorkspaceListCommand{}
|
||||
ui := new(cli.MockUi)
|
||||
listCmd.Meta = Meta{Ui: ui}
|
||||
view, _ := testView(t)
|
||||
listCmd.Meta = Meta{Ui: ui, View: view}
|
||||
|
||||
if code := listCmd.Run(nil); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -222,8 +228,9 @@ func TestWorkspace_createWithState(t *testing.T) {
|
|||
|
||||
// init the backend
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
initCmd := &InitCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
if code := initCmd.Run([]string{}); code != 0 {
|
||||
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
||||
|
@ -257,7 +264,7 @@ func TestWorkspace_createWithState(t *testing.T) {
|
|||
args := []string{"-state", "test.tfstate", workspace}
|
||||
ui = new(cli.MockUi)
|
||||
newCmd := &WorkspaceNewCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
if code := newCmd.Run(args); code != 0 {
|
||||
t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter)
|
||||
|
@ -303,8 +310,9 @@ func TestWorkspace_delete(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
delCmd := &WorkspaceDeleteCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
|
||||
current, _ := delCmd.Workspace()
|
||||
|
@ -352,8 +360,9 @@ func TestWorkspace_deleteInvalid(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
delCmd := &WorkspaceDeleteCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
|
||||
// delete the workspace
|
||||
|
@ -406,8 +415,9 @@ func TestWorkspace_deleteWithState(t *testing.T) {
|
|||
}
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
view, _ := testView(t)
|
||||
delCmd := &WorkspaceDeleteCommand{
|
||||
Meta: Meta{Ui: ui},
|
||||
Meta: Meta{Ui: ui, View: view},
|
||||
}
|
||||
args := []string{"test"}
|
||||
if code := delCmd.Run(args); code == 0 {
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/posener/complete"
|
||||
|
@ -107,9 +108,9 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
|
|||
|
||||
var stateLocker clistate.Locker
|
||||
if stateLock {
|
||||
stateLocker = clistate.NewLocker(context.Background(), stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "workspace_delete"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||
stateLocker = clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "state-replace-provider"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
} else {
|
||||
|
@ -118,7 +119,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
|
|||
|
||||
if err := stateMgr.RefreshState(); err != nil {
|
||||
// We need to release the lock before exit
|
||||
stateLocker.Unlock(nil)
|
||||
stateLocker.Unlock()
|
||||
c.Ui.Error(err.Error())
|
||||
return 1
|
||||
}
|
||||
|
@ -127,7 +128,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
|
|||
|
||||
if hasResources && !force {
|
||||
// We need to release the lock before exit
|
||||
stateLocker.Unlock(nil)
|
||||
stateLocker.Unlock()
|
||||
c.Ui.Error(fmt.Sprintf(strings.TrimSpace(envNotEmpty), workspace))
|
||||
return 1
|
||||
}
|
||||
|
@ -141,7 +142,7 @@ func (c *WorkspaceDeleteCommand) Run(args []string) int {
|
|||
// state deletion, i.e. in a CI environment. Adding Delete() as a
|
||||
// required method of States would allow the removal of the resource to
|
||||
// be delegated from the Backend to the State itself.
|
||||
stateLocker.Unlock(nil)
|
||||
stateLocker.Unlock()
|
||||
|
||||
err = b.DeleteWorkspace(workspace)
|
||||
if err != nil {
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/command/arguments"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/command/views"
|
||||
"github.com/hashicorp/terraform/states/statefile"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
"github.com/mitchellh/cli"
|
||||
|
@ -124,12 +125,16 @@ func (c *WorkspaceNewCommand) Run(args []string) int {
|
|||
}
|
||||
|
||||
if stateLock {
|
||||
stateLocker := clistate.NewLocker(context.Background(), stateLockTimeout, c.Ui, c.Colorize())
|
||||
if err := stateLocker.Lock(stateMgr, "workspace_new"); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
|
||||
stateLocker := clistate.NewLocker(c.stateLockTimeout, views.NewStateLocker(arguments.ViewHuman, c.View))
|
||||
if diags := stateLocker.Lock(stateMgr, "workspace-new"); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
return 1
|
||||
}
|
||||
defer stateLocker.Unlock(nil)
|
||||
defer func() {
|
||||
if diags := stateLocker.Unlock(); diags.HasErrors() {
|
||||
c.showDiagnostics(diags)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// read the existing state file
|
||||
|
|
Loading…
Reference in New Issue