From 66923365418d0194585e255b9bc15bab3cbb14de Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Wed, 2 Jun 2021 15:23:56 -0400 Subject: [PATCH 1/2] cli: Fix state migration version check When migrating multiple local workspaces to a remote backend target using the `prefix` argument, we need to perform the version check against all existing workspaces returned by the `Workspaces` method. Failing to do so will result in a version check error. --- internal/command/meta_backend_migrate.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/internal/command/meta_backend_migrate.go b/internal/command/meta_backend_migrate.go index e7c8a34c0..5307b50e7 100644 --- a/internal/command/meta_backend_migrate.go +++ b/internal/command/meta_backend_migrate.go @@ -57,7 +57,7 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error { errMigrateLoadStates), opts.OneType, err) } - _, err = opts.Two.Workspaces() + twoWorkspaces, err := opts.Two.Workspaces() if err == backend.ErrWorkspacesNotSupported { twoSingle = true err = nil @@ -77,12 +77,14 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error { // as we are migrating away and will not break a remote workspace. m.ignoreRemoteBackendVersionConflict(opts.One) - // Check the remote Terraform version for the state destination backend. If - // it's a Terraform Cloud remote backend, we want to ensure that we don't - // break the workspace by uploading an incompatible state file. - diags := m.remoteBackendVersionCheck(opts.Two, opts.twoEnv) - if diags.HasErrors() { - return diags.Err() + for _, twoWorkspace := range twoWorkspaces { + // Check the remote Terraform version for the state destination backend. If + // it's a Terraform Cloud remote backend, we want to ensure that we don't + // break the workspace by uploading an incompatible state file. + diags := m.remoteBackendVersionCheck(opts.Two, twoWorkspace) + if diags.HasErrors() { + return diags.Err() + } } // Determine migration behavior based on whether the source/destination From 3f0c6a221708a670f5c3f6698610ac2dc99d91dd Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Wed, 2 Jun 2021 15:30:05 -0400 Subject: [PATCH 2/2] cli: Add -ignore-remote-version flag for init When performing state migration to a remote backend target, Terraform may fail due to mismatched remote and local Terraform versions. Here we add the `-ignore-remote-version` flag to allow users to ignore this version check when necessary. --- internal/command/init.go | 62 +++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 29 deletions(-) diff --git a/internal/command/init.go b/internal/command/init.go index 29f97215b..96a383159 100644 --- a/internal/command/init.go +++ b/internal/command/init.go @@ -49,6 +49,7 @@ func (c *InitCommand) Run(args []string) int { cmdFlags.BoolVar(&flagUpgrade, "upgrade", false, "") cmdFlags.Var(&flagPluginPath, "plugin-dir", "plugin directory") cmdFlags.StringVar(&flagLockfile, "lockfile", "", "Set a dependency lockfile mode") + cmdFlags.BoolVar(&c.Meta.ignoreRemoteVersion, "ignore-remote-version", false, "continue even if remote and local Terraform versions are incompatible") cmdFlags.Usage = func() { c.Ui.Error(c.Help()) } if err := cmdFlags.Parse(args); err != nil { return 1 @@ -962,46 +963,49 @@ Usage: terraform [global options] init [options] Options: - -backend=true Configure the backend for this configuration. + -backend=true Configure the backend for this configuration. - -backend-config=path This can be either a path to an HCL file with key/value - assignments (same format as terraform.tfvars) or a - 'key=value' format. This is merged with what is in the - configuration file. This can be specified multiple - times. The backend type must be in the configuration - itself. + -backend-config=path This can be either a path to an HCL file with key/value + assignments (same format as terraform.tfvars) or a + 'key=value' format. This is merged with what is in the + configuration file. This can be specified multiple + times. The backend type must be in the configuration + itself. - -force-copy Suppress prompts about copying state data. This is - equivalent to providing a "yes" to all confirmation - prompts. + -force-copy Suppress prompts about copying state data. This is + equivalent to providing a "yes" to all confirmation + prompts. - -from-module=SOURCE Copy the contents of the given module into the target - directory before initialization. + -from-module=SOURCE Copy the contents of the given module into the target + directory before initialization. - -get=true Download any modules for this configuration. + -get=true Download any modules for this configuration. - -input=true Ask for input if necessary. If false, will error if - input was required. + -input=true Ask for input if necessary. If false, will error if + input was required. - -no-color If specified, output won't contain any color. + -no-color If specified, output won't contain any color. - -plugin-dir Directory containing plugin binaries. This overrides all - default search paths for plugins, and prevents the - automatic installation of plugins. This flag can be used - multiple times. + -plugin-dir Directory containing plugin binaries. This overrides all + default search paths for plugins, and prevents the + automatic installation of plugins. This flag can be used + multiple times. - -reconfigure Reconfigure the backend, ignoring any saved - configuration. + -reconfigure Reconfigure the backend, ignoring any saved + configuration. - -migrate-state Reconfigure the backend, and attempt to migrate any - existing state. + -migrate-state Reconfigure the backend, and attempt to migrate any + existing state. - -upgrade=false If installing modules (-get) or plugins, ignore - previously-downloaded objects and install the - latest version allowed within configured constraints. + -upgrade=false If installing modules (-get) or plugins, ignore + previously-downloaded objects and install the + latest version allowed within configured constraints. - -lockfile=MODE Set a dependency lockfile mode. - Currently only "readonly" is valid. + -lockfile=MODE Set a dependency lockfile mode. + Currently only "readonly" is valid. + + -ignore-remote-version A rare option used for the remote backend only. See + the remote backend documentation for more information. ` return strings.TrimSpace(helpText)