command: Fix TestInit_inputFalse
This test was using old-style state files as its input, differing only by lineage. Since lineages are now managed within the state manager itself, the test can't use that to distinguish the two files and so we put a different output in each one instead. This also introduces some TRACE logging to the migration codepaths. There's some hard-to-follow control flow here and so this extra logging helps to understand the reason for a particular outcome, and since this codepath is visited only in "terraform init" anyway it doesn't hurt to be a bit more verbose here.
This commit is contained in:
parent
c0b7f58143
commit
f6d468ffd5
|
@ -11,15 +11,18 @@ import (
|
|||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
||||
"github.com/hashicorp/terraform/addrs"
|
||||
"github.com/hashicorp/terraform/backend/local"
|
||||
"github.com/hashicorp/terraform/configs"
|
||||
"github.com/hashicorp/terraform/helper/copy"
|
||||
"github.com/hashicorp/terraform/plugin/discovery"
|
||||
"github.com/hashicorp/terraform/state"
|
||||
"github.com/hashicorp/terraform/states"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/cli"
|
||||
)
|
||||
|
||||
func TestInit_empty(t *testing.T) {
|
||||
|
@ -553,13 +556,24 @@ func TestInit_inputFalse(t *testing.T) {
|
|||
}
|
||||
|
||||
// write different states for foo and bar
|
||||
s := terraform.NewState()
|
||||
s.Lineage = "foo"
|
||||
if err := (&state.LocalState{Path: "foo"}).WriteState(s); err != nil {
|
||||
fooState := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetOutputValue(
|
||||
addrs.OutputValue{Name: "foo"}.Absolute(addrs.RootModuleInstance),
|
||||
cty.StringVal("foo"),
|
||||
false, // not sensitive
|
||||
)
|
||||
})
|
||||
if err := statemgr.NewFilesystem("foo").WriteState(fooState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s.Lineage = "bar"
|
||||
if err := (&state.LocalState{Path: "bar"}).WriteState(s); err != nil {
|
||||
barState := states.BuildState(func(s *states.SyncState) {
|
||||
s.SetOutputValue(
|
||||
addrs.OutputValue{Name: "bar"}.Absolute(addrs.RootModuleInstance),
|
||||
cty.StringVal("bar"),
|
||||
false, // not sensitive
|
||||
)
|
||||
})
|
||||
if err := statemgr.NewFilesystem("bar").WriteState(barState); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
@ -41,6 +42,7 @@ type backendMigrateOpts struct {
|
|||
//
|
||||
// This will attempt to lock both states for the migration.
|
||||
func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
|
||||
log.Printf("[TRACE] backendMigrateState: need to migrate from %q to %q backend config", opts.OneType, opts.TwoType)
|
||||
// We need to check what the named state status is. If we're converting
|
||||
// from multi-state to single-state for example, we need to handle that.
|
||||
var oneSingle, twoSingle bool
|
||||
|
@ -126,6 +128,8 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error {
|
|||
|
||||
// Multi-state to multi-state.
|
||||
func (m *Meta) backendMigrateState_S_S(opts *backendMigrateOpts) error {
|
||||
log.Print("[TRACE] backendMigrateState: migrating all named workspaces")
|
||||
|
||||
// Ask the user if they want to migrate their existing remote state
|
||||
migrate, err := m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-multistate-to-multistate",
|
||||
|
@ -175,6 +179,8 @@ func (m *Meta) backendMigrateState_S_S(opts *backendMigrateOpts) error {
|
|||
|
||||
// Multi-state to single state.
|
||||
func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
|
||||
log.Printf("[TRACE] backendMigrateState: target backend type %q does not support named workspaces", opts.TwoType)
|
||||
|
||||
currentEnv := m.Workspace()
|
||||
|
||||
migrate := opts.force
|
||||
|
@ -212,6 +218,8 @@ func (m *Meta) backendMigrateState_S_s(opts *backendMigrateOpts) error {
|
|||
|
||||
// Single state to single state, assumed default state name.
|
||||
func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
||||
log.Printf("[TRACE] backendMigrateState: migrating %q workspace to %q workspace", opts.oneEnv, opts.twoEnv)
|
||||
|
||||
stateOne, err := opts.One.StateMgr(opts.oneEnv)
|
||||
if err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(
|
||||
|
@ -224,6 +232,7 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
|
||||
// Do not migrate workspaces without state.
|
||||
if stateOne.State().Empty() {
|
||||
log.Print("[TRACE] backendMigrateState: source workspace has empty state, so nothing to migrate")
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -232,6 +241,7 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
// If the backend doesn't support using the default state, we ask the user
|
||||
// for a new name and migrate the default state to the given named state.
|
||||
stateTwo, err = func() (statemgr.Full, error) {
|
||||
log.Print("[TRACE] backendMigrateState: target doesn't support a default workspace, so we must prompt for a new name")
|
||||
name, err := m.UIInput().Input(&terraform.InputOpts{
|
||||
Id: "new-state-name",
|
||||
Query: fmt.Sprintf(
|
||||
|
@ -284,9 +294,11 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
sm2, _ := stateTwo.(statemgr.PersistentMeta)
|
||||
if one != nil && two != nil {
|
||||
if sm1 == nil || sm2 == nil {
|
||||
log.Print("[TRACE] backendMigrateState: both source and destination workspaces have no state, so no migration is needed")
|
||||
return nil
|
||||
}
|
||||
if sm1.StateSnapshotMeta().Lineage == sm2.StateSnapshotMeta().Lineage {
|
||||
log.Printf("[TRACE] backendMigrateState: both source and destination workspaces have equal state with lineage %q, so no migration is needed", sm1.StateSnapshotMeta().Lineage)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -309,10 +321,12 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
|
||||
// We now own a lock, so double check that we have the version
|
||||
// corresponding to the lock.
|
||||
log.Print("[TRACE] backendMigrateState: refreshing source workspace state")
|
||||
if err := stateOne.RefreshState(); err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(
|
||||
errMigrateSingleLoadDefault), opts.OneType, err)
|
||||
}
|
||||
log.Print("[TRACE] backendMigrateState: refreshing target workspace state")
|
||||
if err := stateTwo.RefreshState(); err != nil {
|
||||
return fmt.Errorf(strings.TrimSpace(
|
||||
errMigrateSingleLoadDefault), opts.OneType, err)
|
||||
|
@ -326,20 +340,24 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
switch {
|
||||
// No migration necessary
|
||||
case one.Empty() && two.Empty():
|
||||
log.Print("[TRACE] backendMigrateState: both source and destination workspaces have empty state, so no migration is required")
|
||||
return nil
|
||||
|
||||
// No migration necessary if we're inheriting state.
|
||||
case one.Empty() && !two.Empty():
|
||||
log.Print("[TRACE] backendMigrateState: source workspace has empty state, so no migration is required")
|
||||
return nil
|
||||
|
||||
// We have existing state moving into no state. Ask the user if
|
||||
// they'd like to do this.
|
||||
case !one.Empty() && two.Empty():
|
||||
log.Print("[TRACE] backendMigrateState: target workspace has empty state, so might copy source workspace state")
|
||||
confirmFunc = m.backendMigrateEmptyConfirm
|
||||
|
||||
// Both states are non-empty, meaning we need to determine which
|
||||
// state should be used and update accordingly.
|
||||
case !one.Empty() && !two.Empty():
|
||||
log.Print("[TRACE] backendMigrateState: both source and destination workspaces have states, so might overwrite destination with source")
|
||||
confirmFunc = m.backendMigrateNonEmptyConfirm
|
||||
}
|
||||
|
||||
|
@ -350,6 +368,7 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
if !opts.force {
|
||||
// Abort if we can't ask for input.
|
||||
if !m.input {
|
||||
log.Print("[TRACE] backendMigrateState: can't prompt for input, so aborting migration")
|
||||
return errors.New("error asking for state migration action: input disabled")
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue