don't delete local state on a local backend

Don't erase local state during backend migration if the new and old
paths are the same. Skipping the confirmation and copy are handled in
another patch, but the local state was always erased by default, even
when it was our new state.
This commit is contained in:
James Bardin 2017-03-31 15:21:32 -04:00
parent 835792018a
commit 8050eda52d
2 changed files with 67 additions and 6 deletions

View File

@ -1002,7 +1002,8 @@ func (m *Meta) backend_C_r_s(
} }
// If the local state is not empty, we need to potentially do a // If the local state is not empty, we need to potentially do a
// state migration to the new backend (with user permission). // state migration to the new backend (with user permission), unless the
// destination is also "local"
if localS := localState.State(); !localS.Empty() { if localS := localState.State(); !localS.Empty() {
// Perform the migration // Perform the migration
err = m.backendMigrateState(&backendMigrateOpts{ err = m.backendMigrateState(&backendMigrateOpts{
@ -1015,12 +1016,27 @@ func (m *Meta) backend_C_r_s(
return nil, err return nil, err
} }
// We always delete the local state // we usually remove the local state after migration to prevent
if err := localState.WriteState(nil); err != nil { // confusion, but adding a default local backend block to the config
return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) // can get us here too. Don't delete our state if the old and new paths
// are the same.
erase := true
if newLocalB, ok := b.(*backendlocal.Local); ok {
if localB, ok := localB.(*backendlocal.Local); ok {
if newLocalB.StatePath == localB.StatePath {
erase = false
}
}
} }
if err := localState.PersistState(); err != nil {
return nil, fmt.Errorf(errBackendMigrateLocalDelete, err) if erase {
// We always delete the local state, unless that was our new state too.
if err := localState.WriteState(nil); err != nil {
return nil, fmt.Errorf(errBackendMigrateLocalDelete, err)
}
if err := localState.PersistState(); err != nil {
return nil, fmt.Errorf(errBackendMigrateLocalDelete, err)
}
} }
} }

View File

@ -3275,6 +3275,51 @@ func TestMetaBackend_configureWithExtra(t *testing.T) {
} }
} }
// when confniguring a default local state, don't delete local state
func TestMetaBackend_localDoesNotDeleteLocal(t *testing.T) {
// Create a temporary working directory that is empty
td := tempDir(t)
copy.CopyDir(testFixturePath("init-backend-empty"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
// create our local state
orig := &terraform.State{
Modules: []*terraform.ModuleState{
{
Path: []string{"root"},
Outputs: map[string]*terraform.OutputState{
"foo": {
Value: "bar",
Type: "string",
},
},
},
},
}
err := (&state.LocalState{Path: DefaultStateFilename}).WriteState(orig)
if err != nil {
t.Fatal(err)
}
m := testMetaBackend(t, nil)
m.forceInitCopy = true
// init the backend
_, err = m.Backend(&BackendOpts{
Init: true,
})
if err != nil {
t.Fatalf("bad: %s", err)
}
// check that we can read the state
s := testStateRead(t, DefaultStateFilename)
if s.Empty() {
t.Fatal("our state was deleted")
}
}
// move options from config to -backend-config // move options from config to -backend-config
func TestMetaBackend_configToExtra(t *testing.T) { func TestMetaBackend_configToExtra(t *testing.T) {
// Create a temporary working directory that is empty // Create a temporary working directory that is empty