Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion command/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ func (c *InitCommand) Run(args []string) int {

if back == nil {
// If we didn't initialize a backend then we'll try to at least
// instantiate one. This might fail if it wasn't already initalized
// instantiate one. This might fail if it wasn't already initialized
// by a previous run, so we must still expect that "back" may be nil
// in code that follows.
back, err = c.Backend(nil)
Expand Down
65 changes: 64 additions & 1 deletion command/meta_backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"io/ioutil"
"log"
"path/filepath"
"strconv"
"strings"

"github.com/hashicorp/go-multierror"
Expand Down Expand Up @@ -86,6 +87,11 @@ func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, error) {
b, err = m.backendFromPlan(opts)
} else {
b, err = m.backendFromConfig(opts)
if opts.Init && b != nil && err == nil {
// Its possible that the currently selected workspace doesn't exist, so
// we call selectWorkspace to ensure an existing workspace is selected.
err = m.selectWorkspace(b)
}
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -145,6 +151,56 @@ func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, error) {
return local, nil
}

// selectWorkspace gets a list of existing workspaces and then checks
// if the currently selected workspace is valid. If not, it will ask
// the user to select a workspace from the list.
func (m *Meta) selectWorkspace(b backend.Backend) error {
workspaces, err := b.States()
if err == backend.ErrNamedStatesNotSupported {
return nil
}
if err != nil {
return fmt.Errorf("Failed to get existing workspaces: %s", err)
}
if len(workspaces) == 0 {
return fmt.Errorf(errBackendNoExistingWorkspaces)
}

// Get the currently selected workspace.
workspace := m.Workspace()

// Check if any of the existing workspaces matches the selected
// workspace and create a numbered list of existing workspaces.
var list strings.Builder
for i, w := range workspaces {
if w == workspace {
return nil
}
fmt.Fprintf(&list, "%d. %s\n", i+1, w)
}

// If the selected workspace doesn't exist, ask the user to select
// a workspace from the list of existing workspaces.
v, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
Id: "select-workspace",
Query: fmt.Sprintf(
"[reset][bold][yellow]The currently selected workspace (%s) does not exist.[reset]",
workspace),
Description: fmt.Sprintf(
strings.TrimSpace(inputBackendSelectWorkspace), list.String()),
})
if err != nil {
return fmt.Errorf("Error asking to select workspace: %s", err)
}

idx, err := strconv.Atoi(v)
if err != nil || (idx < 1 || idx > len(workspaces)) {
return fmt.Errorf("Error selecting workspace: input not a valid number")
}

return m.SetWorkspace(workspaces[idx-1])
}

// IsLocalBackend returns true if the backend is a local backend. We use this
// for some checks that require a remote backend.
func (m *Meta) IsLocalBackend(b backend.Backend) bool {
Expand Down Expand Up @@ -997,7 +1053,6 @@ func (m *Meta) backend_C_r_s(
m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
"[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type)))

// Return the backend
return b, nil
}

Expand Down Expand Up @@ -1408,6 +1463,14 @@ If you'd like to run Terraform and store state locally, you can fix this
error by removing the backend configuration from your configuration.
`

const errBackendNoExistingWorkspaces = `
No existing workspaces. Use the "terraform workspace" command to create
and select a new workspace.

If the backend already contains existing workspaces, you may need to update
the workspace name or prefix in the backend configuration.
`

const errBackendRemoteRead = `
Error reading backend state: %s

Expand Down
60 changes: 1 addition & 59 deletions command/meta_backend_migrate.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"os"
"path/filepath"
"sort"
"strconv"
"strings"

"github.com/hashicorp/terraform/backend"
Expand Down Expand Up @@ -169,56 +168,7 @@ func (m *Meta) backendMigrateState_S_S(opts *backendMigrateOpts) error {
}
}

// Its possible that the currently selected workspace is not migrated,
// so we call selectWorkspace to ensure a valid workspace is selected.
return m.selectWorkspace(opts.Two)
}

// selectWorkspace gets a list of migrated workspaces and then checks
// if the currently selected workspace is valid. If not, it will ask
// the user to select a workspace from the list.
func (m *Meta) selectWorkspace(b backend.Backend) error {
workspaces, err := b.States()
if err != nil {
return fmt.Errorf("Failed to get migrated workspaces: %s", err)
}
if len(workspaces) == 0 {
return fmt.Errorf(errBackendNoMigratedWorkspaces)
}

// Get the currently selected workspace.
workspace := m.Workspace()

// Check if any of the migrated workspaces match the selected workspace
// and create a numbered list with migrated workspaces.
var list strings.Builder
for i, w := range workspaces {
if w == workspace {
return nil
}
fmt.Fprintf(&list, "%d. %s\n", i+1, w)
}

// If the selected workspace is not migrated, ask the user to select
// a workspace from the list of migrated workspaces.
v, err := m.UIInput().Input(context.Background(), &terraform.InputOpts{
Id: "select-workspace",
Query: fmt.Sprintf(
"[reset][bold][yellow]The currently selected workspace (%s) is not migrated.[reset]",
workspace),
Description: fmt.Sprintf(
strings.TrimSpace(inputBackendSelectWorkspace), list.String()),
})
if err != nil {
return fmt.Errorf("Error asking to select workspace: %s", err)
}

idx, err := strconv.Atoi(v)
if err != nil || (idx < 1 || idx > len(workspaces)) {
return fmt.Errorf("Error selecting workspace: input not a valid number")
}

return m.SetWorkspace(workspaces[idx-1])
return nil
}

// Multi-state to single state.
Expand Down Expand Up @@ -530,14 +480,6 @@ The state in the previous backend remains intact and unmodified. Please resolve
the error above and try again.
`

const errBackendNoMigratedWorkspaces = `
No workspaces are migrated. Use the "terraform workspace" command to create
and select a new workspace.

If the backend already contains existing workspaces, you may need to update
the workspace name or prefix in the backend configuration.
`

const inputBackendMigrateEmpty = `
Pre-existing state was found while migrating the previous %q backend to the
newly configured %q backend. No existing state was found in the newly
Expand Down