command: multi-state (non-default env) to single state

This commit is contained in:
Mitchell Hashimoto 2017-03-01 11:40:28 -08:00
parent e75b666591
commit c82d7dd56c
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
2 changed files with 87 additions and 6 deletions

View File

@ -48,6 +48,10 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
errMigrateLoadStates), opts.TwoType, err)
}
// Setup defaults
opts.oneEnv = backend.DefaultStateName
opts.twoEnv = backend.DefaultStateName
// Determine migration behavior based on whether the source/destionation
// supports multi-state.
switch {
@ -105,6 +109,8 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
// Multi-state to single state.
func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
currentEnv := m.Env()
// Ask the user if they want to migrate their existing remote state
migrate, err := m.confirm(&terraform.InputOpts{
Id: "backend-migrate-multistate-to-single",
@ -112,7 +118,9 @@ func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
"Destination state %q doesn't support environments (named states).\n"+
"Do you want to copy only your current environment?",
opts.TwoType),
Description: strings.TrimSpace(inputBackendMigrateMultiToSingle),
Description: fmt.Sprintf(
strings.TrimSpace(inputBackendMigrateMultiToSingle),
opts.OneType, opts.TwoType, currentEnv),
})
if err != nil {
return fmt.Errorf(
@ -123,12 +131,13 @@ func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
}
// Copy the default state
opts.oneEnv = currentEnv
return m.backendMigrateState_s_s(opts)
}
// Single state to single state, assumed default state name.
func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
stateOne, err := opts.One.State(backend.DefaultStateName)
stateOne, err := opts.One.State(opts.oneEnv)
if err != nil {
return fmt.Errorf(strings.TrimSpace(
errMigrateSingleLoadDefault), opts.OneType, err)
@ -138,7 +147,7 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
errMigrateSingleLoadDefault), opts.OneType, err)
}
stateTwo, err := opts.Two.State(backend.DefaultStateName)
stateTwo, err := opts.Two.State(opts.twoEnv)
if err != nil {
return fmt.Errorf(strings.TrimSpace(
errMigrateSingleLoadDefault), opts.TwoType, err)
@ -314,6 +323,11 @@ func (m *Meta) backendMigrateNonEmptyConfirm(
type backendMigrateOpts struct {
OneType, TwoType string
One, Two backend.Backend
// Fields below are set internally when migrate is called
oneEnv string // source env
twoEnv string // dest env
}
const errMigrateLoadStates = `
@ -361,10 +375,10 @@ and "no" to start with the existing state in %[2]q.
`
const inputBackendMigrateMultiToSingle = `
The existing backend %q supports environments and you currently are
using more than one. The target backend %q doesn't support environments.
The existing backend %[1]q supports environments and you currently are
using more than one. The target backend %[2]q doesn't support environments.
If you continue, Terraform will offer to copy your current environment
%q to the default environment in the target. Your existing environments
%[3]q to the default environment in the target. Your existing environments
in the source backend won't be modified. If you want to switch environments,
back them up, or cancel altogether, answer "no" and Terraform will abort.
`

View File

@ -1126,6 +1126,73 @@ func TestMetaBackend_configuredChangeCopy_multiToSingle(t *testing.T) {
}
}
// Changing a configured backend that supports multi-state to a
// backend that only supports single states.
func TestMetaBackend_configuredChangeCopy_multiToSingleCurrentEnv(t *testing.T) {
// Create a temporary working directory that is empty
td := tempDir(t)
copy.CopyDir(testFixturePath("backend-change-multi-to-single"), td)
defer os.RemoveAll(td)
defer testChdir(t, td)()
// Register the single-state backend
backendinit.Set("local-single", backendlocal.TestNewLocalSingle)
defer backendinit.Set("local-single", nil)
// Ask input
defer testInputMap(t, map[string]string{
"backend-migrate-to-new": "yes",
"backend-migrate-multistate-to-single": "yes",
"backend-migrate-copy-to-empty": "yes",
})()
// Setup the meta
m := testMetaBackend(t, nil)
// Change env
if err := m.SetEnv("env2"); err != nil {
t.Fatalf("bad: %s", err)
}
// Get the backend
b, err := m.Backend(&BackendOpts{Init: true})
if err != nil {
t.Fatalf("bad: %s", err)
}
// Check the state
s, err := b.State(backend.DefaultStateName)
if err != nil {
t.Fatalf("bad: %s", err)
}
if err := s.RefreshState(); err != nil {
t.Fatalf("bad: %s", err)
}
state := s.State()
if state == nil {
t.Fatal("state should not be nil")
}
if state.Lineage != "backend-change-env2" {
t.Fatalf("bad: %#v", state)
}
// Verify no local state
if _, err := os.Stat(DefaultStateFilename); err == nil {
t.Fatal("file should not exist")
}
// Verify no local backup
if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
t.Fatal("file should not exist")
}
// Verify existing environments exist
envPath := filepath.Join(backendlocal.DefaultEnvDir, "env2", backendlocal.DefaultStateFilename)
if _, err := os.Stat(envPath); err != nil {
t.Fatal("env should exist")
}
}
// Unsetting a saved backend
func TestMetaBackend_configuredUnset(t *testing.T) {
// Create a temporary working directory that is empty