command: test multi-state to single state

This commit is contained in:
Mitchell Hashimoto 2017-03-01 11:34:45 -08:00
parent 3ef82e6b5f
commit e75b666591
No known key found for this signature in database
GPG Key ID: 744E147AA52F5B0A
7 changed files with 164 additions and 3 deletions

View File

@ -47,9 +47,13 @@ type Local struct {
//
// StateBackupPath is the local path where a backup file will be written.
// Set this to "-" to disable state backup.
//
// StateEnvPath is the path to the folder containing environments. This
// defaults to DefaultEnvDir if not set.
StatePath string
StateOutPath string
StateBackupPath string
StateEnvDir string
// We only want to create a single instance of a local state, so store them
// here as they're loaded.
@ -266,6 +270,13 @@ func (b *Local) init() {
"path": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
},
"environment_dir": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Default: "",
},
},
@ -288,6 +299,13 @@ func (b *Local) schemaConfigure(ctx context.Context) error {
b.StateOutPath = path
}
if raw, ok := d.GetOk("environment_dir"); ok {
path := raw.(string)
if path != "" {
b.StateEnvDir = path
}
}
return nil
}
@ -302,12 +320,17 @@ func (b *Local) StatePaths(name string) (string, string, string) {
name = backend.DefaultStateName
}
envDir := DefaultEnvDir
if b.StateEnvDir != "" {
envDir = b.StateEnvDir
}
if name == backend.DefaultStateName {
if statePath == "" {
statePath = DefaultStateFilename
}
} else {
statePath = filepath.Join(DefaultEnvDir, name, DefaultStateFilename)
statePath = filepath.Join(envDir, name, DefaultStateFilename)
}
if stateOutPath == "" {
@ -330,7 +353,12 @@ func (b *Local) createState(name string) error {
return nil
}
stateDir := filepath.Join(DefaultEnvDir, name)
envDir := DefaultEnvDir
if b.StateEnvDir != "" {
envDir = b.StateEnvDir
}
stateDir := filepath.Join(envDir, name)
s, err := os.Stat(stateDir)
if err == nil && s.IsDir() {
// no need to check for os.IsNotExist, since that is covered by os.MkdirAll

View File

@ -70,7 +70,7 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
return m.backendMigrateState_s_s(opts)
}
panic("unhandled")
return m.backendMigrateState_S_s(opts)
// Multi-state to multi-state. We merge the states together (migrating
// each from the source to the destination one by one).
@ -103,6 +103,29 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
//
//-------------------------------------------------------------------
// Multi-state to single state.
func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
// Ask the user if they want to migrate their existing remote state
migrate, err := m.confirm(&terraform.InputOpts{
Id: "backend-migrate-multistate-to-single",
Query: fmt.Sprintf(
"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),
})
if err != nil {
return fmt.Errorf(
"Error asking for state migration action: %s", err)
}
if !migrate {
return fmt.Errorf("Migration aborted by user.")
}
// Copy the default state
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)
@ -336,3 +359,12 @@ Two (%[2]q): %[4]s
Do you want to copy the state from %[1]q to %[2]q? Enter "yes" to copy
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.
If you continue, Terraform will offer to copy your current environment
%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

@ -1064,6 +1064,68 @@ func TestMetaBackend_configuredChangeCopy_multiToSingleDefault(t *testing.T) {
}
}
// Changing a configured backend that supports multi-state to a
// backend that only supports single states.
func TestMetaBackend_configuredChangeCopy_multiToSingle(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)
// 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" {
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

View File

@ -0,0 +1,22 @@
{
"version": 3,
"serial": 0,
"lineage": "666f9301-7e65-4b19-ae23-71184bb19b03",
"backend": {
"type": "local",
"config": {
"path": "local-state.tfstate"
},
"hash": 9073424445967744180
},
"modules": [
{
"path": [
"root"
],
"outputs": {},
"resources": {},
"depends_on": []
}
]
}

View File

@ -0,0 +1,6 @@
{
"version": 3,
"terraform_version": "0.8.2",
"serial": 7,
"lineage": "backend-change"
}

View File

@ -0,0 +1,5 @@
terraform {
backend "local-single" {
path = "local-state-2.tfstate"
}
}

View File

@ -0,0 +1,6 @@
{
"version": 3,
"terraform_version": "0.8.2",
"serial": 7,
"lineage": "backend-change-env2"
}