command: test multi-state to single state
This commit is contained in:
parent
3ef82e6b5f
commit
e75b666591
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
`
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"version": 3,
|
||||
"terraform_version": "0.8.2",
|
||||
"serial": 7,
|
||||
"lineage": "backend-change"
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
terraform {
|
||||
backend "local-single" {
|
||||
path = "local-state-2.tfstate"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"version": 3,
|
||||
"terraform_version": "0.8.2",
|
||||
"serial": 7,
|
||||
"lineage": "backend-change-env2"
|
||||
}
|
Loading…
Reference in New Issue