make command tests pass with new state.Locker

This commit is contained in:
James Bardin 2017-02-14 18:51:32 -05:00
parent cd233fef6a
commit 4f0c465187
7 changed files with 63 additions and 34 deletions

View File

@ -533,11 +533,16 @@ func (m *Meta) backendFromPlan(opts *BackendOpts) (backend.Backend, error) {
}
// Lock the state if we can
err = clistate.Lock(realMgr, "backend from plan", m.Ui, m.Colorize())
lockInfo := &state.LockInfo{
Operation: "plan",
Info: "backend from plan",
}
lockID, err := clistate.Lock(realMgr, lockInfo, m.Ui, m.Colorize())
if err != nil {
return nil, fmt.Errorf("Error locking state: %s", err)
}
defer clistate.Unlock(realMgr, m.Ui, m.Colorize())
defer clistate.Unlock(realMgr, lockID, m.Ui, m.Colorize())
if err := realMgr.RefreshState(); err != nil {
return nil, fmt.Errorf("Error reading state: %s", err)
@ -986,11 +991,15 @@ func (m *Meta) backend_C_r_s(
}
// Lock the state if we can
err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize())
lockInfo := &state.LockInfo{
Info: "backend from config",
}
lockID, err := clistate.Lock(sMgr, lockInfo, m.Ui, m.Colorize())
if err != nil {
return nil, fmt.Errorf("Error locking state: %s", err)
}
defer clistate.Unlock(sMgr, m.Ui, m.Colorize())
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
// Store the metadata in our saved state location
s := sMgr.State()
@ -1091,11 +1100,14 @@ func (m *Meta) backend_C_r_S_changed(
}
// Lock the state if we can
err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize())
lockInfo := &state.LockInfo{
Info: "backend from config",
}
lockID, err := clistate.Lock(sMgr, lockInfo, m.Ui, m.Colorize())
if err != nil {
return nil, fmt.Errorf("Error locking state: %s", err)
}
defer clistate.Unlock(sMgr, m.Ui, m.Colorize())
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
// Update the backend state
s = sMgr.State()
@ -1249,11 +1261,15 @@ func (m *Meta) backend_C_R_S_unchanged(
}
// Lock the state if we can
err = clistate.Lock(sMgr, "backend from config", m.Ui, m.Colorize())
lockInfo := &state.LockInfo{
Info: "backend from config",
}
lockID, err := clistate.Lock(sMgr, lockInfo, m.Ui, m.Colorize())
if err != nil {
return nil, fmt.Errorf("Error locking state: %s", err)
}
defer clistate.Unlock(sMgr, m.Ui, m.Colorize())
defer clistate.Unlock(sMgr, lockID, m.Ui, m.Colorize())
// Unset the remote state
s = sMgr.State()

View File

@ -24,17 +24,25 @@ import (
//
// This will attempt to lock both states for the migration.
func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
err := clistate.Lock(opts.One, "migration source state", m.Ui, m.Colorize())
lockInfoOne := &state.LockInfo{
Info: "migration source state",
}
lockIDOne, err := clistate.Lock(opts.One, lockInfoOne, m.Ui, m.Colorize())
if err != nil {
return fmt.Errorf("Error locking source state: %s", err)
}
defer clistate.Unlock(opts.One, m.Ui, m.Colorize())
defer clistate.Unlock(opts.One, lockIDOne, m.Ui, m.Colorize())
err = clistate.Lock(opts.Two, "migration destination state", m.Ui, m.Colorize())
lockInfoTwo := &state.LockInfo{
Info: "migration source state",
}
lockIDTwo, err := clistate.Lock(opts.Two, lockInfoTwo, m.Ui, m.Colorize())
if err != nil {
return fmt.Errorf("Error locking destination state: %s", err)
}
defer clistate.Unlock(opts.Two, m.Ui, m.Colorize())
defer clistate.Unlock(opts.Two, lockIDTwo, m.Ui, m.Colorize())
one := opts.One.State()
two := opts.Two.State()

View File

@ -6,6 +6,7 @@ import (
"strings"
clistate "github.com/hashicorp/terraform/command/state"
"github.com/hashicorp/terraform/state"
"github.com/hashicorp/terraform/terraform"
)
@ -73,13 +74,16 @@ func (c *TaintCommand) Run(args []string) int {
}
if c.Meta.stateLock {
err := clistate.Lock(st, "taint", c.Ui, c.Colorize())
lockInfo := &state.LockInfo{
Operation: "taint",
}
lockID, err := clistate.Lock(st, lockInfo, c.Ui, c.Colorize())
if err != nil {
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
return 1
}
defer clistate.Unlock(st, c.Ui, c.Colorize())
defer clistate.Unlock(st, lockID, c.Ui, c.Colorize())
}
// Get the actual state structure

View File

@ -23,7 +23,7 @@ func main() {
Path: os.Args[1],
}
err := s.Lock("command test")
lockID, err := s.Lock(&state.LockInfo{Operation: "test", Info: "state locker"})
if err != nil {
io.WriteString(os.Stderr, err.Error())
return
@ -33,7 +33,7 @@ func main() {
io.WriteString(os.Stdout, "LOCKED")
defer func() {
if err := s.Unlock(); err != nil {
if err := s.Unlock(lockID); err != nil {
io.WriteString(os.Stderr, err.Error())
}
}()

View File

@ -92,7 +92,8 @@ func (c *UnlockCommand) Run(args []string) int {
}
}
if err := s.Unlock(); err != nil {
// FIXME: unlock should require the lock ID
if err := s.Unlock(""); err != nil {
c.Ui.Error(fmt.Sprintf("Failed to unlock state: %s", err))
return 1
}

View File

@ -6,6 +6,7 @@ import (
"strings"
clistate "github.com/hashicorp/terraform/command/state"
"github.com/hashicorp/terraform/state"
)
// UntaintCommand is a cli.Command implementation that manually untaints
@ -61,13 +62,16 @@ func (c *UntaintCommand) Run(args []string) int {
}
if c.Meta.stateLock {
err := clistate.Lock(st, "untaint", c.Ui, c.Colorize())
lockInfo := &state.LockInfo{
Operation: "untaint",
}
lockID, err := clistate.Lock(st, lockInfo, c.Ui, c.Colorize())
if err != nil {
c.Ui.Error(fmt.Sprintf("Error locking state: %s", err))
return 1
}
defer clistate.Unlock(st, c.Ui, c.Colorize())
defer clistate.Unlock(st, lockID, c.Ui, c.Colorize())
}
// Get the actual state structure

View File

@ -134,25 +134,25 @@ func (s *LocalState) RefreshState() error {
}
// Lock implements a local filesystem state.Locker.
func (s *LocalState) Lock(reason string) error {
func (s *LocalState) Lock(info *LockInfo) (string, error) {
if s.stateFileOut == nil {
if err := s.createStateFiles(); err != nil {
return err
return "", err
}
}
if err := s.lock(); err != nil {
if info, err := s.lockInfo(); err == nil {
return info.Err()
return "", info.Err()
}
return fmt.Errorf("state file %q locked: %s", s.Path, err)
return "", fmt.Errorf("state file %q locked: %s", s.Path, err)
}
return s.writeLockInfo(reason)
return "", s.writeLockInfo(info)
}
func (s *LocalState) Unlock() error {
func (s *LocalState) Unlock(id string) error {
// we can't be locked if we don't have a file
if s.stateFileOut == nil {
return nil
@ -232,18 +232,14 @@ func (s *LocalState) lockInfo() (*LockInfo, error) {
}
// write a new lock info file
func (s *LocalState) writeLockInfo(info string) error {
func (s *LocalState) writeLockInfo(info *LockInfo) error {
path := s.lockInfoPath()
info.Path = s.Path
info.Created = time.Now().UTC()
lockInfo := &LockInfo{
Path: s.Path,
Created: time.Now().UTC(),
Info: info,
}
infoData, err := json.Marshal(lockInfo)
infoData, err := json.Marshal(info)
if err != nil {
panic(fmt.Sprintf("could not marshal lock info: %#v", lockInfo))
panic(fmt.Sprintf("could not marshal lock info: %#v", info))
}
err = ioutil.WriteFile(path, infoData, 0600)