Merge pull request #29881 from hashicorp/chrisarcand/streamline-remote-migration

cloud: Add streamlined 'remote' backend state migration path
This commit is contained in:
Chris Arcand 2021-11-03 15:30:12 -05:00 committed by GitHub
commit 4f66479506
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 10 deletions

View File

@ -569,6 +569,17 @@ func (b *Remote) workspaces() ([]string, error) {
return names, nil
}
// WorkspaceNamePattern provides an appropriate workspace renaming pattern for backend migration
// purposes (handled outside of this package), based on previous usage of this backend with the
// 'prefix' workspace functionality. As of this writing, see meta_backend.migrate.go
func (b *Remote) WorkspaceNamePattern() string {
if b.prefix != "" {
return b.prefix + "*"
}
return ""
}
// DeleteWorkspace implements backend.Enhanced.
func (b *Remote) DeleteWorkspace(name string) error {
if b.workspace == "" && name == backend.DefaultStateName {

View File

@ -1002,7 +1002,7 @@ func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *clista
if output {
// Notify the user
m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
"[reset]%s\n\n",
"[reset]%s\n",
strings.TrimSpace(outputBackendReconfigure))))
}
@ -1021,7 +1021,9 @@ func (m *Meta) backend_C_r_S_changed(c *configs.Backend, cHash int, sMgr *clista
if c.Type == "cloud" {
output = fmt.Sprintf(outputBackendMigrateChangeCloud, s.Backend.Type)
}
m.Ui.Output(strings.TrimSpace(output))
m.Ui.Output(m.Colorize().Color(fmt.Sprintf(
"[reset]%s\n",
strings.TrimSpace(output))))
}
// Grab the existing backend

View File

@ -13,6 +13,7 @@ import (
"strings"
"github.com/hashicorp/terraform/internal/backend"
"github.com/hashicorp/terraform/internal/backend/remote"
"github.com/hashicorp/terraform/internal/cloud"
"github.com/hashicorp/terraform/internal/command/arguments"
"github.com/hashicorp/terraform/internal/command/clistate"
@ -635,10 +636,33 @@ func (m *Meta) backendMigrateState_S_TFC(opts *backendMigrateOpts, sourceWorkspa
defaultNewName[sourceWorkspaces[i]] = newName
}
}
pattern, err := m.promptMultiStateMigrationPattern(opts.SourceType)
// Fetch the pattern that will be used to rename the workspaces for Terraform Cloud.
//
// * For the general case, this will be a pattern provided by the user.
//
// * Specifically for a migration from the "remote" backend using 'prefix', we will
// instead 'migrate' the workspaces using a pattern based on the old prefix+name,
// not allowing a user to accidentally input the wrong pattern to line up with
// what the the remote backend was already using before (which presumably already
// meets the naming considerations for Terraform Cloud).
// In other words, this is a fast-track migration path from the remote backend, retaining
// how things already are in Terraform Cloud with no user intervention needed.
pattern := ""
if remoteBackend, ok := opts.Source.(*remote.Remote); ok {
if err := m.promptRemotePrefixToCloudTagsMigration(opts); err != nil {
return err
}
pattern = remoteBackend.WorkspaceNamePattern()
log.Printf("[TRACE] backendMigrateTFC: Remote backend reports workspace name pattern as: %q", pattern)
}
if pattern == "" {
pattern, err = m.promptMultiStateMigrationPattern(opts.SourceType)
if err != nil {
return err
}
}
// Go through each and migrate
for _, name := range sourceWorkspaces {
@ -712,6 +736,27 @@ func (m *Meta) backendMigrateState_S_TFC(opts *backendMigrateOpts, sourceWorkspa
return nil
}
func (m *Meta) promptRemotePrefixToCloudTagsMigration(opts *backendMigrateOpts) error {
migrate := opts.force
if !migrate {
var err error
migrate, err = m.confirm(&terraform.InputOpts{
Id: "backend-migrate-remote-multistate-to-cloud",
Query: "Do you wish to proceed?",
Description: strings.TrimSpace(tfcInputBackendMigrateRemoteMultiToCloud),
})
if err != nil {
return fmt.Errorf("Error asking for state migration action: %s", err)
}
}
if !migrate {
return fmt.Errorf("Migration aborted by user.")
}
return nil
}
// Multi-state to single state.
func (m *Meta) promptMultiToSingleCloudMigration(opts *backendMigrateOpts) error {
migrate := opts.force
@ -867,11 +912,26 @@ For more information on workspace naming, see https://www.terraform.io/docs/clou
`
const tfcInputBackendMigrateMultiToSingle = `
The previous backend %[1]q has multiple workspaces, but Terraform Cloud has been
configured to use a single workspace (%[2]q). By continuing, you will only
migrate your current workspace. If you wish to migrate all workspaces from the
previous backend, use the 'tags' strategy in your workspace configuration block
instead.
The previous backend %[1]q has multiple workspaces, but Terraform Cloud has
been configured to use a single workspace (%[2]q). By continuing, you will
only migrate your current workspace. If you wish to migrate all workspaces
from the previous backend, you may cancel this operation and use the 'tags'
strategy in your workspace configuration block instead.
Enter "yes" to proceed or "no" to cancel.
`
const tfcInputBackendMigrateRemoteMultiToCloud = `
When migrating from the 'remote' backend to Terraform's native integration
with Terraform Cloud, Terraform will automatically create or use existing
workspaces based on the previous backend configuration's 'prefix' value.
When the migration is complete, workspace names in Terraform will match the
fully qualified Terraform Cloud workspace name. If necessary, the workspace
tags configured in the 'cloud' option block will be added to the associated
Terraform Cloud workspaces.
Enter "yes" to proceed or "no" to cancel.
`
const inputBackendMigrateEmpty = `