command/state: helpers for UX with lock/unlock state

This commit is contained in:
Mitchell Hashimoto 2017-02-14 11:17:18 -08:00
parent 2124135287
commit 34f438b635
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
1 changed files with 83 additions and 0 deletions

83
command/state/state.go Normal file
View File

@ -0,0 +1,83 @@
// Package state exposes common helpers for working with state from the CLI.
//
// This is a separate package so that backends can use this for consistent
// messaging without creating a circular reference to the command package.
package message
import (
"fmt"
"strings"
"time"
"github.com/hashicorp/terraform/helper/slowmessage"
"github.com/hashicorp/terraform/state"
"github.com/mitchellh/cli"
"github.com/mitchellh/colorstring"
)
const (
LockThreshold = 250 * time.Millisecond
LockMessage = "Acquiring state lock. This may take a few moments..."
UnlockMessage = "Releasing state lock. This may take a few moments..."
UnlockErrorMessage = `
[reset][bold][red]Error releasing the state lock![reset][red]
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
error occurred while releasing this lock. This could mean that the lock
did or did not release properly. If the lock didn't release properly,
Terraform may not be able to run future commands since it'll appear as if
the lock is held.
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.
`
)
// Lock locks the given state and outputs to the user if locking
// is taking longer than the threshold.
func Lock(s state.State, info string, ui cli.Ui, color *colorstring.Colorize) error {
sl, ok := s.(state.Locker)
if !ok {
return nil
}
return slowmessage.Do(LockThreshold, func() error {
return sl.Lock(info)
}, func() {
if ui != nil {
ui.Output(color.Color(LockMessage))
}
})
}
// Unlock unlocks the given state and outputs to the user if the
// unlock fails what can be done.
func Unlock(s state.State, ui cli.Ui, color *colorstring.Colorize) error {
sl, ok := s.(state.Locker)
if !ok {
return nil
}
err := slowmessage.Do(LockThreshold, sl.Unlock, func() {
if ui != nil {
ui.Output(color.Color(UnlockMessage))
}
})
if err != nil {
ui.Output(color.Color(fmt.Sprintf(
"\n"+strings.TrimSpace(UnlockErrorMessage)+"\n", err)))
err = fmt.Errorf(
"Error releasing the state lock. Please see the longer error message above.")
}
return err
}