command: use new state lock/unlock helpers for better UX

This commit is contained in:
Mitchell Hashimoto 2017-02-14 11:33:55 -08:00
parent 65982bd412
commit 90f3d40c1f
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
5 changed files with 37 additions and 44 deletions

View File

@ -16,6 +16,7 @@ import (
"github.com/hashicorp/go-multierror" "github.com/hashicorp/go-multierror"
"github.com/hashicorp/hcl" "github.com/hashicorp/hcl"
"github.com/hashicorp/terraform/backend" "github.com/hashicorp/terraform/backend"
clistate "github.com/hashicorp/terraform/command/state"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
@ -531,11 +532,12 @@ func (m *Meta) backendFromPlan(opts *BackendOpts) (backend.Backend, error) {
return nil, fmt.Errorf("Error reading state: %s", err) return nil, fmt.Errorf("Error reading state: %s", err)
} }
unlock, err := lockState(realMgr, "backend from plan") // Lock the state if we can
err = clistate.Lock(realMgr, "backend from plan", m.Ui, m.Colorize())
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("Error locking state: %s", err)
} }
defer unlock() defer clistate.Unlock(realMgr, m.Ui, m.Colorize())
if err := realMgr.RefreshState(); err != nil { if err := realMgr.RefreshState(); err != nil {
return nil, fmt.Errorf("Error reading state: %s", err) return nil, fmt.Errorf("Error reading state: %s", err)
@ -983,11 +985,12 @@ func (m *Meta) backend_C_r_s(
} }
} }
unlock, err := lockState(sMgr, "backend_C_r_s") // Lock the state if we can
err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize())
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("Error locking state: %s", err)
} }
defer unlock() defer clistate.Unlock(sMgr, m.Ui, m.Colorize())
// Store the metadata in our saved state location // Store the metadata in our saved state location
s := sMgr.State() s := sMgr.State()
@ -1087,11 +1090,12 @@ func (m *Meta) backend_C_r_S_changed(
} }
} }
unlock, err := lockState(sMgr, "backend_C_r_S_changed") // Lock the state if we can
err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize())
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("Error locking state: %s", err)
} }
defer unlock() defer clistate.Unlock(sMgr, m.Ui, m.Colorize())
// Update the backend state // Update the backend state
s = sMgr.State() s = sMgr.State()
@ -1244,11 +1248,12 @@ func (m *Meta) backend_C_R_S_unchanged(
} }
} }
unlock, err := lockState(sMgr, "backend_C_R_S_unchanged") // Lock the state if we can
err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize())
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("Error locking state: %s", err)
} }
defer unlock() defer clistate.Unlock(sMgr, m.Ui, m.Colorize())
// Unset the remote state // Unset the remote state
s = sMgr.State() s = sMgr.State()
@ -1399,21 +1404,6 @@ func init() {
backendlegacy.Init(Backends) backendlegacy.Init(Backends)
} }
// simple wrapper to check for a state.Locker and always provide an unlock
// function to defer.
func lockState(s state.State, info string) (func() error, error) {
l, ok := s.(state.Locker)
if !ok {
return func() error { return nil }, nil
}
if err := l.Lock(info); err != nil {
return nil, err
}
return l.Unlock, nil
}
// errBackendInitRequired is the final error message shown when reinit // errBackendInitRequired is the final error message shown when reinit
// is required for some reason. The error message includes the reason. // is required for some reason. The error message includes the reason.
var errBackendInitRequired = errors.New( var errBackendInitRequired = errors.New(

View File

@ -7,6 +7,7 @@ import (
"path/filepath" "path/filepath"
"strings" "strings"
clistate "github.com/hashicorp/terraform/command/state"
"github.com/hashicorp/terraform/state" "github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -23,17 +24,17 @@ import (
// //
// This will attempt to lock both states for the migration. // This will attempt to lock both states for the migration.
func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error { func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
unlockOne, err := lockState(opts.One, "migrate from") err := clistate.Lock(opts.One, "migration source state", m.Ui, m.Colorize())
if err != nil { if err != nil {
return err return fmt.Errorf("Error locking source state: %s", err)
} }
defer unlockOne() defer clistate.Unlock(opts.One, m.Ui, m.Colorize())
unlockTwo, err := lockState(opts.Two, "migrate to") err = clistate.Lock(opts.Two, "migration destination state", m.Ui, m.Colorize())
if err != nil { if err != nil {
return err return fmt.Errorf("Error locking destination state: %s", err)
} }
defer unlockTwo() defer clistate.Unlock(opts.Two, m.Ui, m.Colorize())
one := opts.One.State() one := opts.One.State()
two := opts.Two.State() two := opts.Two.State()

View File

@ -5,7 +5,7 @@ import (
"log" "log"
"strings" "strings"
"github.com/hashicorp/terraform/state" clistate "github.com/hashicorp/terraform/command/state"
"github.com/hashicorp/terraform/terraform" "github.com/hashicorp/terraform/terraform"
) )
@ -72,13 +72,14 @@ func (c *TaintCommand) Run(args []string) int {
return 1 return 1
} }
if s, ok := st.(state.Locker); c.Meta.stateLock && ok { if c.Meta.stateLock {
if err := s.Lock("taint"); err != nil { err := clistate.Lock(st, "taint", c.Ui, c.Colorize())
c.Ui.Error(fmt.Sprintf("Failed to lock state: %s", err)) if err != nil {
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
return 1 return 1
} }
defer s.Unlock() defer clistate.Unlock(st, c.Ui, c.Colorize())
} }
// Get the actual state structure // Get the actual state structure

View File

@ -124,7 +124,7 @@ func (c *UnlockCommand) Synopsis() string {
} }
const outputUnlockSuccess = ` const outputUnlockSuccess = `
[reset][bold][red]Terraform state has been successfully unlocked![reset][red] [reset][bold][green]Terraform state has been successfully unlocked![reset][green]
The state has been unlocked, and Terraform commands should now be able to The state has been unlocked, and Terraform commands should now be able to
obtain a new lock on the remote state. obtain a new lock on the remote state.

View File

@ -5,7 +5,7 @@ import (
"log" "log"
"strings" "strings"
"github.com/hashicorp/terraform/state" clistate "github.com/hashicorp/terraform/command/state"
) )
// UntaintCommand is a cli.Command implementation that manually untaints // UntaintCommand is a cli.Command implementation that manually untaints
@ -60,13 +60,14 @@ func (c *UntaintCommand) Run(args []string) int {
return 1 return 1
} }
if s, ok := st.(state.Locker); c.Meta.stateLock && ok { if c.Meta.stateLock {
if err := s.Lock("untaint"); err != nil { err := clistate.Lock(st, "untaint", c.Ui, c.Colorize())
c.Ui.Error(fmt.Sprintf("Failed to lock state: %s", err)) if err != nil {
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
return 1 return 1
} }
defer s.Unlock() defer clistate.Unlock(st, c.Ui, c.Colorize())
} }
// Get the actual state structure // Get the actual state structure