backend: StateMgrWithoutCheckVersion

Allow users of backends to initialize a state manager instance without
checking the Terraform version of any state files which are retrieved
during this process. Many backends call RefreshState as part of
initialization, and this new method instead calls the new
RefreshStateWithoutCheckVersion method to prevent version checking.
pull/26692/head
Alisdair McDiarmid 6 years ago
parent 06af227e14
commit c8d7515808

@ -179,6 +179,10 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return &remote.State{Client: b.stateClient}, nil
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}
// Colorize returns the Colorize structure that can be used for colorizing
// output. This is gauranteed to always return a non-nil value and so is useful
// as a helper to wrap any potentially colored strings.

@ -103,6 +103,18 @@ type Backend interface {
// PersistState is called, depending on the state manager implementation.
StateMgr(workspace string) (statemgr.Full, error)
// StateMgrWithoutCheckVersion returns the state manager for the given
// workspace name, while ensuring that Terraform version checks are not
// performed if the backend needs to read a state file in order to
// initialize the state manager.
//
// For backends which do not need to read a state file at this point, this
// is identical to StateMgr.
//
// This is used to facilitate reading compatible state files from newer
// versions of Terraform.
StateMgrWithoutCheckVersion(workspace string) (statemgr.Full, error)
// DeleteWorkspace removes the workspace with the given name if it exists.
//
// DeleteWorkspace cannot prevent deleting a state that is in use. It is

@ -279,6 +279,10 @@ func (b *Local) StateMgr(name string) (statemgr.Full, error) {
return s, nil
}
func (b *Local) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}
// Operation implements backend.Enhanced
//
// This will initialize an in-memory terraform.Context to perform the

@ -31,6 +31,10 @@ func (Nil) StateMgr(string) (statemgr.Full, error) {
return statemgr.NewFullFake(statemgr.NewTransientInMemory(nil), nil), nil
}
func (Nil) StateMgrWithoutCheckVersion(string) (statemgr.Full, error) {
return statemgr.NewFullFake(statemgr.NewTransientInMemory(nil), nil), nil
}
func (Nil) DeleteWorkspace(string) error {
return nil
}

@ -100,3 +100,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
Client: b.client,
}, nil
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}

@ -79,6 +79,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
ctx := context.TODO()
blobClient, err := b.armClient.getBlobClient(ctx)
if err != nil {
@ -115,9 +123,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -64,6 +64,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
// Determine the path of the data
path := b.path(name)
@ -109,9 +117,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -75,6 +75,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
// StateMgr manage the state, if the named state not exists, a new file will created
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
log.Printf("[DEBUG] state manager, current workspace: %v", name)
c, err := b.client(name)
@ -108,9 +116,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -94,3 +94,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
},
}, nil
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}

@ -42,6 +42,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
var stateMgr statemgr.Full = &remote.State{
Client: &RemoteClient{
Client: b.client,
@ -68,9 +76,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return parent
}
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
if v := stateMgr.State(); v == nil {

@ -87,6 +87,14 @@ func (b *Backend) client(name string) (*remoteClient, error) {
// StateMgr reads and returns the named state from GCS. If the named state does
// not yet exist, a new state file is created.
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
c, err := b.client(name)
if err != nil {
return nil, err
@ -95,8 +103,14 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
st := &remote.State{Client: c}
// Grab the value
if err := st.RefreshState(); err != nil {
return nil, err
if checkVersion {
if err := st.RefreshState(); err != nil {
return nil, err
}
} else {
if err := st.RefreshStateWithoutCheckVersion(); err != nil {
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -188,6 +188,10 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return &remote.State{Client: b.client}, nil
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}
func (b *Backend) Workspaces() ([]string, error) {
return nil, backend.ErrWorkspacesNotSupported
}

@ -150,6 +150,10 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return s, nil
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}
type stateMap struct {
sync.Mutex
m map[string]*remote.State

@ -72,6 +72,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
c, err := b.remoteClient(name)
if err != nil {
return nil, err
@ -80,8 +88,14 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
stateMgr := &remote.State{Client: c}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -65,6 +65,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
if name == "" {
return nil, errors.New("missing state name")
}
@ -97,9 +105,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -107,6 +107,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
client, err := b.remoteClient(name)
if err != nil {
return nil, err
@ -147,9 +155,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -111,3 +111,7 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return stateMgr, nil
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}

@ -125,6 +125,14 @@ func (b *Backend) remoteClient(name string) (*RemoteClient, error) {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
client, err := b.remoteClient(name)
if err != nil {
return nil, err
@ -173,9 +181,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
// Grab the value
// This is to ensure that no one beat us to writing a state between
// the `exists` check and taking the lock.
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -92,6 +92,14 @@ func (b *Backend) DeleteWorkspace(name string) error {
}
func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
return b.stateMgr(name, true)
}
func (b *Backend) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.stateMgr(name, false)
}
func (b *Backend) stateMgr(name string, checkVersion bool) (statemgr.Full, error) {
if name == "" {
return nil, fmt.Errorf("missing state name")
}
@ -161,9 +169,16 @@ func (b *Backend) StateMgr(name string) (statemgr.Full, error) {
}
// Grab the value
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
if checkVersion {
if err := stateMgr.RefreshState(); err != nil {
err = lockUnlock(err)
return nil, err
}
} else {
if err := stateMgr.RefreshStateWithoutCheckVersion(); err != nil {
err = lockUnlock(err)
return nil, err
}
}
// If we have no state, we have to create an empty state

@ -641,6 +641,10 @@ func (b *Remote) StateMgr(name string) (statemgr.Full, error) {
return &remote.State{Client: client}, nil
}
func (b *Remote) StateMgrWithoutCheckVersion(name string) (statemgr.Full, error) {
return b.StateMgr(name)
}
// Operation implements backend.Enhanced.
func (b *Remote) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) {
// Get the remote workspace name.

@ -362,6 +362,10 @@ func (b backendFailsConfigure) StateMgr(workspace string) (statemgr.Full, error)
return nil, fmt.Errorf("StateMgr not implemented")
}
func (b backendFailsConfigure) StateMgrWithoutCheckVersion(workspace string) (statemgr.Full, error) {
return nil, fmt.Errorf("StateMgrWithoutCheckVersion not implemented")
}
func (b backendFailsConfigure) DeleteWorkspace(name string) error {
return fmt.Errorf("DeleteWorkspace not implemented")
}

Loading…
Cancel
Save