From d9ba0c69eaa93c120d683842b9524f6ee765660f Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Tue, 7 May 2019 15:23:26 +0200 Subject: [PATCH] Always try to select a workspace after initialization There are a number of use cases that can require a user to select a workspace after initializing Terraform. To make sure we cover all these use cases, we will always call the selectWorkspace method to verify a valid workspace is already selected or (if needed) offer to select one before moving on. --- command/init.go | 2 +- command/meta_backend.go | 121 ++++++++++++++++++++-------------------- 2 files changed, 61 insertions(+), 62 deletions(-) diff --git a/command/init.go b/command/init.go index b8c8faab5..12cd13592 100644 --- a/command/init.go +++ b/command/init.go @@ -299,7 +299,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. var backDiags tfdiags.Diagnostics diff --git a/command/meta_backend.go b/command/meta_backend.go index bfaa9b44e..7f94135f7 100644 --- a/command/meta_backend.go +++ b/command/meta_backend.go @@ -85,6 +85,14 @@ func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, tfdiags.Diagnostics b, backendDiags = m.backendFromConfig(opts) diags = diags.Append(backendDiags) + if opts.Init && b != nil && !diags.HasErrors() { + // Its possible that the currently selected workspace doesn't exist, so + // we call selectWorkspace to ensure an existing workspace is selected. + if err := m.selectWorkspace(b); err != nil { + diags = diags.Append(err) + } + } + if diags.HasErrors() { return nil, diags } @@ -156,6 +164,56 @@ func (m *Meta) Backend(opts *BackendOpts) (backend.Enhanced, tfdiags.Diagnostics 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.Workspaces() + if err == backend.ErrWorkspacesNotSupported { + return nil + } + if err != nil { + return fmt.Errorf("Failed to get existing workspaces: %s", err) + } + if len(workspaces) == 0 { + return fmt.Errorf(strings.TrimSpace(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( + "\n[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("Failed to select workspace: %s", err) + } + + idx, err := strconv.Atoi(v) + if err != nil || (idx < 1 || idx > len(workspaces)) { + return fmt.Errorf("Failed to select workspace: input not a valid number") + } + + return m.SetWorkspace(workspaces[idx-1]) +} + // BackendForPlan is similar to Backend, but uses backend settings that were // stored in a plan. // @@ -731,68 +789,9 @@ func (m *Meta) backend_C_r_s(c *configs.Backend, cHash int, sMgr *state.LocalSta m.Ui.Output(m.Colorize().Color(fmt.Sprintf( "[reset][green]\n"+strings.TrimSpace(successBackendSet), s.Backend.Type))) - // Its possible that the currently selected workspace is not migrated, - // so we call selectWorkspace to ensure a valid workspace is selected. - if err := m.selectWorkspace(b); err != nil { - diags = diags.Append(err) - return nil, diags - } - - // Return the backend return b, diags } -// 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.Workspaces() - if err != nil { - if err == backend.ErrWorkspacesNotSupported { - return nil - } - return fmt.Errorf("Failed to get migrated workspaces: %s", err) - } - - if len(workspaces) == 0 { - return fmt.Errorf(strings.TrimSpace(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( - "\n[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("Failed to select workspace: %s", err) - } - - idx, err := strconv.Atoi(v) - if err != nil || (idx < 1 || idx > len(workspaces)) { - return fmt.Errorf("Failed to select workspace: input not a valid number") - } - - return m.SetWorkspace(workspaces[idx-1]) -} - // Changing a previously saved backend. func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *state.LocalState, output bool) (backend.Backend, tfdiags.Diagnostics) { if output { @@ -1183,8 +1182,8 @@ 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 errBackendNoMigratedWorkspaces = ` -No workspaces are migrated. +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