backend/gcs: fix locking issue when used with terraform_remote_state

Previously there was a problem with double-locking when using the GCS backend with the terraform_remote_state data source.

Here we adjust the locking methodology to avoid that problem.
This commit is contained in:
Kaveh Mousavi Zamani 2017-12-06 18:36:16 +01:00 committed by Martin Atkins
parent 12b7dac124
commit 7507e3cd21
1 changed files with 33 additions and 30 deletions

View File

@ -91,50 +91,53 @@ func (b *gcsBackend) State(name string) (state.State, error) {
} }
st := &remote.State{Client: c} st := &remote.State{Client: c}
lockInfo := state.NewLockInfo()
lockInfo.Operation = "init"
lockID, err := st.Lock(lockInfo)
if err != nil {
return nil, err
}
// Local helper function so we can call it multiple places
unlock := func(baseErr error) error {
if err := st.Unlock(lockID); err != nil {
const unlockErrMsg = `%v
Additionally, unlocking the state file on Google Cloud Storage failed:
Error message: %q
Lock ID (gen): %v
Lock file URL: %v
You may have to force-unlock this state in order to use it again.
The GCloud backend acquires a lock during initialization to ensure
the initial state file is created.`
return fmt.Errorf(unlockErrMsg, baseErr, err.Error(), lockID, c.lockFileURL())
}
return baseErr
}
// Grab the value // Grab the value
if err := st.RefreshState(); err != nil { if err := st.RefreshState(); err != nil {
return nil, unlock(err) return nil, err
} }
// If we have no state, we have to create an empty state // If we have no state, we have to create an empty state
if v := st.State(); v == nil { if v := st.State(); v == nil {
lockInfo := state.NewLockInfo()
lockInfo.Operation = "init"
lockID, err := st.Lock(lockInfo)
if err != nil {
return nil, err
}
// Local helper function so we can call it multiple places
unlock := func(baseErr error) error {
if err := st.Unlock(lockID); err != nil {
const unlockErrMsg = `%v
Additionally, unlocking the state file on Google Cloud Storage failed:
Error message: %q
Lock ID (gen): %v
Lock file URL: %v
You may have to force-unlock this state in order to use it again.
The GCloud backend acquires a lock during initialization to ensure
the initial state file is created.`
return fmt.Errorf(unlockErrMsg, baseErr, err.Error(), lockID, c.lockFileURL())
}
return baseErr
}
if err := st.WriteState(terraform.NewState()); err != nil { if err := st.WriteState(terraform.NewState()); err != nil {
return nil, unlock(err) return nil, unlock(err)
} }
if err := st.PersistState(); err != nil { if err := st.PersistState(); err != nil {
return nil, unlock(err) return nil, unlock(err)
} }
}
// Unlock, the state should now be initialized // Unlock, the state should now be initialized
if err := unlock(nil); err != nil { if err := unlock(nil); err != nil {
return nil, err return nil, err
}
} }
return st, nil return st, nil