2017-02-14 20:17:18 +01:00
|
|
|
// 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"
|
|
|
|
|
2017-02-14 20:44:43 +01:00
|
|
|
"github.com/hashicorp/errwrap"
|
2017-02-14 20:17:18 +01:00
|
|
|
"github.com/hashicorp/terraform/helper/slowmessage"
|
|
|
|
"github.com/hashicorp/terraform/state"
|
|
|
|
"github.com/mitchellh/cli"
|
|
|
|
"github.com/mitchellh/colorstring"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2017-02-14 20:44:43 +01:00
|
|
|
LockThreshold = 400 * time.Millisecond
|
|
|
|
LockMessage = "Acquiring state lock. This may take a few moments..."
|
|
|
|
LockErrorMessage = `Error acquiring the state lock: {{err}}
|
2017-02-14 20:17:18 +01:00
|
|
|
|
2017-02-14 20:44:43 +01:00
|
|
|
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..."
|
2017-02-14 20:17:18 +01:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-02-14 20:44:43 +01:00
|
|
|
err := slowmessage.Do(LockThreshold, func() error {
|
2017-02-14 20:17:18 +01:00
|
|
|
return sl.Lock(info)
|
|
|
|
}, func() {
|
|
|
|
if ui != nil {
|
|
|
|
ui.Output(color.Color(LockMessage))
|
|
|
|
}
|
|
|
|
})
|
2017-02-14 20:44:43 +01:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
err = errwrap.Wrapf(strings.TrimSpace(LockErrorMessage), err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return err
|
2017-02-14 20:17:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|