Merge pull request #12939 from hashicorp/jbardin/GH-12921
add `-force-copy` option to init command
This commit is contained in:
commit
ddb9c51481
|
@ -21,11 +21,14 @@ type InitCommand struct {
|
|||
func (c *InitCommand) Run(args []string) int {
|
||||
var flagBackend, flagGet bool
|
||||
var flagConfigExtra map[string]interface{}
|
||||
|
||||
args = c.Meta.process(args, false)
|
||||
cmdFlags := c.flagSet("init")
|
||||
cmdFlags.BoolVar(&flagBackend, "backend", true, "")
|
||||
cmdFlags.Var((*variables.FlagAny)(&flagConfigExtra), "backend-config", "")
|
||||
cmdFlags.BoolVar(&flagGet, "get", true, "")
|
||||
cmdFlags.BoolVar(&c.forceInitCopy, "force-copy", false, "suppress prompts about copying state data")
|
||||
|
||||
cmdFlags.Usage = func() { c.Ui.Error(c.Help()) }
|
||||
if err := cmdFlags.Parse(args); err != nil {
|
||||
return 1
|
||||
|
@ -225,6 +228,10 @@ Options:
|
|||
|
||||
-no-color If specified, output won't contain any color.
|
||||
|
||||
-force-copy Suppress prompts about copying state data. This is
|
||||
equivalent to providing a "yes" to all confirmation
|
||||
prompts.
|
||||
|
||||
`
|
||||
return strings.TrimSpace(helpText)
|
||||
}
|
||||
|
|
|
@ -270,9 +270,6 @@ func TestInit_backendUnset(t *testing.T) {
|
|||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
// Run it again
|
||||
defer testInteractiveInput(t, []string{"yes", "yes"})()
|
||||
|
||||
ui := new(cli.MockUi)
|
||||
c := &InitCommand{
|
||||
Meta: Meta{
|
||||
|
@ -281,7 +278,7 @@ func TestInit_backendUnset(t *testing.T) {
|
|||
},
|
||||
}
|
||||
|
||||
args := []string{}
|
||||
args := []string{"-force-copy"}
|
||||
if code := c.Run(args); code != 0 {
|
||||
t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
|
||||
}
|
||||
|
|
|
@ -87,14 +87,18 @@ type Meta struct {
|
|||
//
|
||||
// provider is to specify specific resource providers
|
||||
//
|
||||
// lockState is set to false to disable state locking
|
||||
statePath string
|
||||
stateOutPath string
|
||||
backupPath string
|
||||
parallelism int
|
||||
shadow bool
|
||||
provider string
|
||||
stateLock bool
|
||||
// stateLock is set to false to disable state locking
|
||||
//
|
||||
// forceInitCopy suppresses confirmation for copying state data during
|
||||
// init.
|
||||
statePath string
|
||||
stateOutPath string
|
||||
backupPath string
|
||||
parallelism int
|
||||
shadow bool
|
||||
provider string
|
||||
stateLock bool
|
||||
forceInitCopy bool
|
||||
}
|
||||
|
||||
// initStatePaths is used to initialize the default values for
|
||||
|
|
|
@ -684,16 +684,20 @@ func (m *Meta) backend_c_r_S(
|
|||
// Get the backend type for output
|
||||
backendType := s.Backend.Type
|
||||
|
||||
// Confirm with the user that the copy should occur
|
||||
copy, err := m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-local",
|
||||
Query: fmt.Sprintf("Do you want to copy the state from %q?", s.Backend.Type),
|
||||
Description: fmt.Sprintf(
|
||||
strings.TrimSpace(inputBackendMigrateLocal), s.Backend.Type),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
copy := m.forceInitCopy
|
||||
if !copy {
|
||||
var err error
|
||||
// Confirm with the user that the copy should occur
|
||||
copy, err = m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-local",
|
||||
Query: fmt.Sprintf("Do you want to copy the state from %q?", s.Backend.Type),
|
||||
Description: fmt.Sprintf(
|
||||
strings.TrimSpace(inputBackendMigrateLocal), s.Backend.Type),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If we're copying, perform the migration
|
||||
|
@ -805,16 +809,19 @@ func (m *Meta) backend_c_R_S(
|
|||
s := sMgr.State()
|
||||
|
||||
// Ask the user if they want to migrate their existing remote state
|
||||
copy, err := m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf(
|
||||
"Do you want to copy the legacy remote state from %q?",
|
||||
s.Remote.Type),
|
||||
Description: strings.TrimSpace(inputBackendMigrateLegacyLocal),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
copy := m.forceInitCopy
|
||||
if !copy {
|
||||
copy, err = m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf(
|
||||
"Do you want to copy the legacy remote state from %q?",
|
||||
s.Remote.Type),
|
||||
Description: strings.TrimSpace(inputBackendMigrateLegacyLocal),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If the user wants a copy, copy!
|
||||
|
@ -898,16 +905,19 @@ func (m *Meta) backend_C_R_s(
|
|||
|
||||
// Finally, ask the user if they want to copy the state from
|
||||
// their old remote state location.
|
||||
copy, err := m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf(
|
||||
"Do you want to copy the legacy remote state from %q?",
|
||||
s.Remote.Type),
|
||||
Description: strings.TrimSpace(inputBackendMigrateLegacy),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
copy := m.forceInitCopy
|
||||
if !copy {
|
||||
copy, err = m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf(
|
||||
"Do you want to copy the legacy remote state from %q?",
|
||||
s.Remote.Type),
|
||||
Description: strings.TrimSpace(inputBackendMigrateLegacy),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If the user wants a copy, copy!
|
||||
|
@ -1055,14 +1065,17 @@ func (m *Meta) backend_C_r_S_changed(
|
|||
}
|
||||
|
||||
// Check with the user if we want to migrate state
|
||||
copy, err := m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf("Do you want to copy the state from %q?", c.Type),
|
||||
Description: strings.TrimSpace(fmt.Sprintf(inputBackendMigrateChange, c.Type, s.Backend.Type)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
copy := m.forceInitCopy
|
||||
if !copy {
|
||||
copy, err = m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf("Do you want to copy the state from %q?", c.Type),
|
||||
Description: strings.TrimSpace(fmt.Sprintf(inputBackendMigrateChange, c.Type, s.Backend.Type)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If we are, then we need to initialize the old backend and
|
||||
|
@ -1198,16 +1211,19 @@ func (m *Meta) backend_C_R_S_unchanged(
|
|||
}
|
||||
|
||||
// Ask if the user wants to move their legacy remote state
|
||||
copy, err := m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf(
|
||||
"Do you want to copy the legacy remote state from %q?",
|
||||
s.Remote.Type),
|
||||
Description: strings.TrimSpace(inputBackendMigrateLegacy),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
copy := m.forceInitCopy
|
||||
if !copy {
|
||||
copy, err = m.confirm(&terraform.InputOpts{
|
||||
Id: "backend-migrate-to-new",
|
||||
Query: fmt.Sprintf(
|
||||
"Do you want to copy the legacy remote state from %q?",
|
||||
s.Remote.Type),
|
||||
Description: strings.TrimSpace(inputBackendMigrateLegacy),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf(
|
||||
"Error asking for state copy action: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
// If the user wants a copy, copy!
|
||||
|
|
|
@ -162,21 +162,26 @@ func (m *Meta) backendMigrateState_S_S(opts *backendMigrateOpts) error {
|
|||
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",
|
||||
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: fmt.Sprintf(
|
||||
strings.TrimSpace(inputBackendMigrateMultiToSingle),
|
||||
opts.OneType, opts.TwoType, currentEnv),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error asking for state migration action: %s", err)
|
||||
migrate := m.forceInitCopy
|
||||
if !migrate {
|
||||
var err 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: fmt.Sprintf(
|
||||
strings.TrimSpace(inputBackendMigrateMultiToSingle),
|
||||
opts.OneType, opts.TwoType, currentEnv),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf(
|
||||
"Error asking for state migration action: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
if !migrate {
|
||||
return fmt.Errorf("Migration aborted by user.")
|
||||
}
|
||||
|
@ -295,6 +300,10 @@ func (m *Meta) backendMigrateState_s_s(opts *backendMigrateOpts) error {
|
|||
}
|
||||
|
||||
func (m *Meta) backendMigrateEmptyConfirm(one, two state.State, opts *backendMigrateOpts) (bool, error) {
|
||||
if m.forceInitCopy {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
inputOpts := &terraform.InputOpts{
|
||||
Id: "backend-migrate-copy-to-empty",
|
||||
Query: fmt.Sprintf(
|
||||
|
@ -357,6 +366,10 @@ func (m *Meta) backendMigrateNonEmptyConfirm(
|
|||
return false, fmt.Errorf("Error saving temporary state: %s", err)
|
||||
}
|
||||
|
||||
if m.forceInitCopy {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Ask for confirmation
|
||||
inputOpts := &terraform.InputOpts{
|
||||
Id: "backend-migrate-to-backend",
|
||||
|
|
|
@ -480,11 +480,10 @@ func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
|
|||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
// Ask input
|
||||
defer testInteractiveInput(t, []string{"yes"})()
|
||||
|
||||
// Setup the meta
|
||||
m := testMetaBackend(t, nil)
|
||||
// suppress input
|
||||
m.forceInitCopy = true
|
||||
|
||||
// Get the backend
|
||||
b, err := m.Backend(&BackendOpts{Init: true})
|
||||
|
@ -722,12 +721,12 @@ func TestMetaBackend_configureNewLegacyCopy(t *testing.T) {
|
|||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
// Ask input
|
||||
defer testInteractiveInput(t, []string{"yes", "yes"})()
|
||||
|
||||
// Setup the meta
|
||||
m := testMetaBackend(t, nil)
|
||||
|
||||
// suppress input
|
||||
m.forceInitCopy = true
|
||||
|
||||
// Get the backend
|
||||
b, err := m.Backend(&BackendOpts{Init: true})
|
||||
if err != nil {
|
||||
|
@ -1593,11 +1592,9 @@ func TestMetaBackend_configuredUnchangedLegacyCopy(t *testing.T) {
|
|||
defer os.RemoveAll(td)
|
||||
defer testChdir(t, td)()
|
||||
|
||||
// Ask input
|
||||
defer testInteractiveInput(t, []string{"yes", "yes"})()
|
||||
|
||||
// Setup the meta
|
||||
m := testMetaBackend(t, nil)
|
||||
m.forceInitCopy = true
|
||||
|
||||
// Get the backend
|
||||
b, err := m.Backend(&BackendOpts{Init: true})
|
||||
|
|
Loading…
Reference in New Issue