From fc5863844c901ddaffbd6b1a4118662e9da910ce Mon Sep 17 00:00:00 2001 From: Omar Ismail Date: Wed, 27 Oct 2021 11:14:54 -0400 Subject: [PATCH] Cloud migration: ignore backend version check when empty worksapces --- internal/cloud/backend.go | 6 +- internal/cloud/e2e/helper_test.go | 7 ++ .../e2e/migrate_state_tfc_to_tfc_test.go | 76 ++++++++++++++++++- internal/command/meta_backend_migrate.go | 4 +- 4 files changed, 87 insertions(+), 6 deletions(-) diff --git a/internal/cloud/backend.go b/internal/cloud/backend.go index 786309fed..1a5607f58 100644 --- a/internal/cloud/backend.go +++ b/internal/cloud/backend.go @@ -548,8 +548,10 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { // object to do a nicely formatted message, so we're just assuming the // issue was that the version wasn't available since that's probably what // happened. - versionUnavailable := fmt.Sprintf(unavailableTerraformVersion, tfversion.String(), workspace.TerraformVersion) - b.CLI.Output(b.Colorize().Color(versionUnavailable)) + if b.CLI != nil { + versionUnavailable := fmt.Sprintf(unavailableTerraformVersion, tfversion.String(), workspace.TerraformVersion) + b.CLI.Output(b.Colorize().Color(versionUnavailable)) + } } } diff --git a/internal/cloud/e2e/helper_test.go b/internal/cloud/e2e/helper_test.go index 7af990f12..0b0a6be58 100644 --- a/internal/cloud/e2e/helper_test.go +++ b/internal/cloud/e2e/helper_test.go @@ -47,6 +47,13 @@ func createOrganization(t *testing.T) (*tfe.Organization, func()) { t.Fatal(err) } + _, err = tfeClient.Admin.Organizations.Update(ctx, org.Name, tfe.AdminOrganizationUpdateOptions{ + AccessBetaTools: tfe.Bool(true), + }) + if err != nil { + t.Fatal(err) + } + return org, func() { if err := tfeClient.Organizations.Delete(ctx, org.Name); err != nil { t.Errorf("Error destroying organization! WARNING: Dangling resources\n"+ diff --git a/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go b/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go index ab5d908ed..342ee2f3c 100644 --- a/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go +++ b/internal/cloud/e2e/migrate_state_tfc_to_tfc_test.go @@ -5,6 +5,7 @@ package main import ( "context" + "fmt" "io/ioutil" "os" "testing" @@ -16,7 +17,7 @@ import ( func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { ctx := context.Background() - tfVersion := "1.1.0-tfc-integration" + tfVersion := "1.1.0-alpha-20211027-dev-e51508be" if !hasTerraformVersion(t, tfVersion) { t.Skip("Skipping test because TFC does not have current terraform version.") } @@ -162,6 +163,75 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { } }, }, + "migrating from name to tags without ignore-version flag": { + setup: func(t *testing.T) (string, func()) { + organization, cleanup := createOrganization(t) + return organization.Name, cleanup + }, + operations: []operationSets{ + { + prep: func(t *testing.T, orgName, dir string) { + wsName := "prod" + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ + Name: tfe.String("prod"), + TerraformVersion: tfe.String(tfVersion), + }) + tfBlock := terraformConfigCloudBackendName(orgName, wsName) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init"}, + expectedCmdOutput: `Terraform Cloud has been successfully initialized!`, + }, + { + command: []string{"apply"}, + expectedCmdOutput: `Do you want to perform these actions in workspace "prod"?`, + userInput: []string{"yes"}, + postInputOutput: []string{`Apply complete!`}, + }, + }, + }, + { + prep: func(t *testing.T, orgName, dir string) { + tag := "app" + // This is only here to ensure that the updated terraform version is + // present in the workspace, and it does not default to a lower + // version that does not support `cloud`. + _ = createWorkspace(t, orgName, tfe.WorkspaceCreateOptions{ + Name: tfe.String("new-workspace"), + TerraformVersion: tfe.String(tfVersion), + }) + tfBlock := terraformConfigCloudBackendTags(orgName, tag) + writeMainTF(t, tfBlock, dir) + }, + commands: []tfCommand{ + { + command: []string{"init", "-migrate-state"}, + expectedCmdOutput: `The Terraform Cloud configuration only allows named workspaces!`, + expectError: true, + userInput: []string{"new-workspace", "yes"}, + postInputOutput: []string{ + // this is a temporary measure till we resolve some of the + // version mismatching. + fmt.Sprintf(`Remote workspace Terraform version "%s" does not match local Terraform version`, tfVersion)}, + }, + }, + }, + }, + validations: func(t *testing.T, orgName string) { + wsList, err := tfeClient.Workspaces.List(ctx, orgName, tfe.WorkspaceListOptions{ + Tags: tfe.String("app"), + }) + if err != nil { + t.Fatal(err) + } + // The migration never occured, so we have no workspaces with this tag. + if len(wsList.Items) != 0 { + t.Fatalf("Expected number of workspaces to be 0, but got %d", len(wsList.Items)) + } + }, + }, } for name, tc := range cases { @@ -225,7 +295,7 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { } err = cmd.Wait() - if err != nil { + if err != nil && !tfCmd.expectError { t.Fatal(err.Error()) } } @@ -239,7 +309,7 @@ func Test_migrate_tfc_to_tfc_single_workspace(t *testing.T) { func Test_migrate_tfc_to_tfc_multiple_workspace(t *testing.T) { ctx := context.Background() - tfVersion := "1.1.0-tfc-integration" + tfVersion := "1.1.0-alpha-20211027-dev-e51508be" if !hasTerraformVersion(t, tfVersion) { t.Skip("Skipping test because TFC does not have current terraform version.") } diff --git a/internal/command/meta_backend_migrate.go b/internal/command/meta_backend_migrate.go index 6cfb69be1..a4c0578cc 100644 --- a/internal/command/meta_backend_migrate.go +++ b/internal/command/meta_backend_migrate.go @@ -86,7 +86,9 @@ func (m *Meta) backendMigrateState(opts *backendMigrateOpts) error { } // If there are no specified destination workspaces, perform a remote // backend version check with the default workspace. - if len(destinationWorkspaces) == 0 { + // Ensure that we are not dealing with Terraform Cloud migrations, as it + // does not support the default name. + if len(destinationWorkspaces) == 0 && !destinationTFC { diags := m.remoteVersionCheck(opts.Destination, backend.DefaultStateName) if diags.HasErrors() { return diags.Err()