From d2b6b5f2b392894e7241231f5eaa13b9a2811020 Mon Sep 17 00:00:00 2001 From: Chris Arcand Date: Mon, 20 Sep 2021 13:07:53 -0500 Subject: [PATCH] cloud: Align local and remote workspace name with 'name' strategy This changes the 'name' strategy to always align the local configured workspace name and the remote Terraform Cloud workspace, rather than the implicit use of the 'default' unnamed workspace being used instead. What this essentially means is that the Cloud integration does not fully support workspaces when configured for a single TFC workspace (as was the case with the 'remote' backend), but *does* use the backend.Workspaces() interface to allow for normal local behaviors like terraform.workspace to resolve to the correct name. It does this by always setting the local workspace name when the 'name' strategy is used, as a part of initialization. Part of the diff here is exporting all the previously unexported types for mapping workspaces. The command package (and init in particular) needs to be able to handle setting the local workspace in this particular scenario. --- internal/cloud/backend.go | 151 ++++++++++++------------- internal/cloud/backend_apply_test.go | 78 ++++++------- internal/cloud/backend_context.go | 6 +- internal/cloud/backend_context_test.go | 8 +- internal/cloud/backend_plan_test.go | 72 ++++++------ internal/cloud/backend_state_test.go | 5 +- internal/cloud/backend_test.go | 79 +++++++------ internal/cloud/testing.go | 11 +- 8 files changed, 202 insertions(+), 208 deletions(-) diff --git a/internal/cloud/backend.go b/internal/cloud/backend.go index 09a9995c7b..22adb98d17 100644 --- a/internal/cloud/backend.go +++ b/internal/cloud/backend.go @@ -64,9 +64,9 @@ type Cloud struct { // organization is the organization that contains the target workspaces. organization string - // workspaceMapping contains strategies for mapping CLI workspaces in the working directory + // WorkspaceMapping contains strategies for mapping CLI workspaces in the working directory // to remote Terraform Cloud workspaces. - workspaceMapping workspaceMapping + WorkspaceMapping WorkspaceMapping // services is used for service discovery services *disco.Disco @@ -157,28 +157,28 @@ func (b *Cloud) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) { diags = diags.Append(invalidOrganizationConfigMissingValue) } - workspaceMapping := workspaceMapping{} + WorkspaceMapping := WorkspaceMapping{} if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() { if val := workspaces.GetAttr("name"); !val.IsNull() { - workspaceMapping.name = val.AsString() + WorkspaceMapping.Name = val.AsString() } if val := workspaces.GetAttr("prefix"); !val.IsNull() { - workspaceMapping.prefix = val.AsString() + WorkspaceMapping.Prefix = val.AsString() } if val := workspaces.GetAttr("tags"); !val.IsNull() { - err := gocty.FromCtyValue(val, &workspaceMapping.tags) + err := gocty.FromCtyValue(val, &WorkspaceMapping.Tags) if err != nil { log.Panicf("An unxpected error occurred: %s", err) } } } - switch workspaceMapping.strategy() { + switch WorkspaceMapping.Strategy() { // Make sure have a workspace mapping strategy present - case workspaceNoneStrategy: + case WorkspaceNoneStrategy: diags = diags.Append(invalidWorkspaceConfigMissingValues) // Make sure that only one of workspace name or a prefix is configured. - case workspaceInvalidStrategy: + case WorkspaceInvalidStrategy: diags = diags.Append(invalidWorkspaceConfigMisconfiguration) } @@ -335,10 +335,10 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics { // PrepareConfig checks that you cannot set both of these. if val := workspaces.GetAttr("name"); !val.IsNull() { - b.workspaceMapping.name = val.AsString() + b.WorkspaceMapping.Name = val.AsString() } if val := workspaces.GetAttr("prefix"); !val.IsNull() { - b.workspaceMapping.prefix = val.AsString() + b.WorkspaceMapping.Prefix = val.AsString() } if val := workspaces.GetAttr("tags"); !val.IsNull() { var tags []string @@ -347,7 +347,7 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics { log.Panicf("An unxpected error occurred: %s", err) } - b.workspaceMapping.tags = tags + b.WorkspaceMapping.Tags = tags } } @@ -530,31 +530,30 @@ func (b *Cloud) retryLogHook(attemptNum int, resp *http.Response) { } } -// Workspaces implements backend.Enhanced. +// Workspaces implements backend.Enhanced, returning a filtered list of workspace names according to +// the workspace mapping strategy configured. func (b *Cloud) Workspaces() ([]string, error) { - if b.workspaceMapping.strategy() == workspaceNameStrategy { - return nil, backend.ErrWorkspacesNotSupported + // Create a slice to contain all the names. + var names []string + + // If configured for a single workspace, return that exact name only. The StateMgr for this + // backend will automatically create the remote workspace if it does not yet exist. + if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy { + names = append(names, b.WorkspaceMapping.Name) + return names, nil } - return b.workspaces() -} -// workspaces returns a filtered list of remote workspace names according to the workspace mapping -// strategy configured. -func (b *Cloud) workspaces() ([]string, error) { + // Otherwise, multiple workspaces are being mapped. Query Terraform Cloud for all the remote + // workspaces by the provided mapping strategy. options := tfe.WorkspaceListOptions{} - switch b.workspaceMapping.strategy() { - case workspaceNameStrategy: - options.Search = tfe.String(b.workspaceMapping.name) - case workspacePrefixStrategy: - options.Search = tfe.String(b.workspaceMapping.prefix) - case workspaceTagsStrategy: - taglist := strings.Join(b.workspaceMapping.tags, ",") + switch b.WorkspaceMapping.Strategy() { + case WorkspacePrefixStrategy: + options.Search = tfe.String(b.WorkspaceMapping.Prefix) + case WorkspaceTagsStrategy: + taglist := strings.Join(b.WorkspaceMapping.Tags, ",") options.Tags = &taglist } - // Create a slice to contain all the names. - var names []string - for { wl, err := b.client.Workspaces.List(context.Background(), b.organization, options) if err != nil { @@ -562,20 +561,15 @@ func (b *Cloud) workspaces() ([]string, error) { } for _, w := range wl.Items { - switch b.workspaceMapping.strategy() { - case workspaceNameStrategy: - if w.Name == b.workspaceMapping.name { - names = append(names, backend.DefaultStateName) - continue - } - case workspacePrefixStrategy: - if strings.HasPrefix(w.Name, b.workspaceMapping.prefix) { - names = append(names, strings.TrimPrefix(w.Name, b.workspaceMapping.prefix)) + switch b.WorkspaceMapping.Strategy() { + case WorkspacePrefixStrategy: + if strings.HasPrefix(w.Name, b.WorkspaceMapping.Prefix) { + names = append(names, strings.TrimPrefix(w.Name, b.WorkspaceMapping.Prefix)) continue } default: - // Pass-through. "name" and "prefix" strategies are naive and do - // client-side filtering above, but for tags and any other future + // Pass-through. The "prefix" strategy is naive and does + // client-side filtering, but for tags and any other future // strategy this filtering should be left to the API. names = append(names, w.Name) } @@ -598,19 +592,18 @@ func (b *Cloud) workspaces() ([]string, error) { // DeleteWorkspace implements backend.Enhanced. func (b *Cloud) DeleteWorkspace(name string) error { - if b.workspaceMapping.strategy() != workspaceNameStrategy && name == backend.DefaultStateName { + if name == backend.DefaultStateName { return backend.ErrDefaultWorkspaceNotSupported } - if b.workspaceMapping.strategy() == workspaceNameStrategy && name != backend.DefaultStateName { + + if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy { return backend.ErrWorkspacesNotSupported } // Configure the remote workspace name. switch { - case name == backend.DefaultStateName: - name = b.workspaceMapping.name - case b.workspaceMapping.strategy() == workspacePrefixStrategy && !strings.HasPrefix(name, b.workspaceMapping.prefix): - name = b.workspaceMapping.prefix + name + case b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy && !strings.HasPrefix(name, b.WorkspaceMapping.Prefix): + name = b.WorkspaceMapping.Prefix + name } client := &remoteClient{ @@ -626,19 +619,17 @@ func (b *Cloud) DeleteWorkspace(name string) error { // StateMgr implements backend.Enhanced. func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { - if b.workspaceMapping.strategy() != workspaceNameStrategy && name == backend.DefaultStateName { + if name == backend.DefaultStateName { return nil, backend.ErrDefaultWorkspaceNotSupported } - if b.workspaceMapping.strategy() == workspaceNameStrategy && name != backend.DefaultStateName { + + if b.WorkspaceMapping.Strategy() == WorkspaceNameStrategy && name != b.WorkspaceMapping.Name { return nil, backend.ErrWorkspacesNotSupported } - // Configure the remote workspace name. - switch { - case name == backend.DefaultStateName: - name = b.workspaceMapping.name - case b.workspaceMapping.strategy() == workspacePrefixStrategy && !strings.HasPrefix(name, b.workspaceMapping.prefix): - name = b.workspaceMapping.prefix + name + // If the prefix strategy is used, translate the local name to the TFC workspace name. + if b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy { + name = b.WorkspaceMapping.Prefix + name } workspace, err := b.client.Workspaces.Read(context.Background(), b.organization, name) @@ -652,7 +643,7 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { } var tags []*tfe.Tag - for _, tag := range b.workspaceMapping.tags { + for _, tag := range b.WorkspaceMapping.Tags { t := tfe.Tag{Name: tag} tags = append(tags, &t) } @@ -698,13 +689,11 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) { // Operation implements backend.Enhanced. func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) { - // Get the remote workspace name. name := op.Workspace - switch { - case op.Workspace == backend.DefaultStateName: - name = b.workspaceMapping.name - case b.workspaceMapping.strategy() == workspacePrefixStrategy && !strings.HasPrefix(op.Workspace, b.workspaceMapping.prefix): - name = b.workspaceMapping.prefix + op.Workspace + + // If the prefix strategy is used, translate the local name to the TFC workspace name. + if b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy { + name = b.WorkspaceMapping.Prefix + op.Workspace } // Retrieve the workspace for this operation. @@ -1014,35 +1003,35 @@ func (b *Cloud) cliColorize() *colorstring.Colorize { } } -type workspaceMapping struct { - name string - prefix string - tags []string +type WorkspaceMapping struct { + Name string + Prefix string + Tags []string } type workspaceStrategy string const ( - workspaceTagsStrategy workspaceStrategy = "tags" - workspaceNameStrategy workspaceStrategy = "name" - workspacePrefixStrategy workspaceStrategy = "prefix" - workspaceNoneStrategy workspaceStrategy = "none" - workspaceInvalidStrategy workspaceStrategy = "invalid" + WorkspaceTagsStrategy workspaceStrategy = "tags" + WorkspaceNameStrategy workspaceStrategy = "name" + WorkspacePrefixStrategy workspaceStrategy = "prefix" + WorkspaceNoneStrategy workspaceStrategy = "none" + WorkspaceInvalidStrategy workspaceStrategy = "invalid" ) -func (wm workspaceMapping) strategy() workspaceStrategy { +func (wm WorkspaceMapping) Strategy() workspaceStrategy { switch { - case len(wm.tags) > 0 && wm.name == "" && wm.prefix == "": - return workspaceTagsStrategy - case len(wm.tags) == 0 && wm.name != "" && wm.prefix == "": - return workspaceNameStrategy - case len(wm.tags) == 0 && wm.name == "" && wm.prefix != "": - return workspacePrefixStrategy - case len(wm.tags) == 0 && wm.name == "" && wm.prefix == "": - return workspaceNoneStrategy + case len(wm.Tags) > 0 && wm.Name == "" && wm.Prefix == "": + return WorkspaceTagsStrategy + case len(wm.Tags) == 0 && wm.Name != "" && wm.Prefix == "": + return WorkspaceNameStrategy + case len(wm.Tags) == 0 && wm.Name == "" && wm.Prefix != "": + return WorkspacePrefixStrategy + case len(wm.Tags) == 0 && wm.Name == "" && wm.Prefix == "": + return WorkspaceNoneStrategy default: // Any other combination is invalid as each strategy is mutually exclusive - return workspaceInvalidStrategy + return WorkspaceInvalidStrategy } } diff --git a/internal/cloud/backend_apply_test.go b/internal/cloud/backend_apply_test.go index 1af4b4726a..9f464c3f37 100644 --- a/internal/cloud/backend_apply_test.go +++ b/internal/cloud/backend_apply_test.go @@ -67,7 +67,7 @@ func TestCloud_applyBasic(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -97,7 +97,7 @@ func TestCloud_applyBasic(t *testing.T) { t.Fatalf("expected apply summery in output: %s", output) } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) // An error suggests that the state was not unlocked after apply if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after apply: %s", err.Error()) @@ -112,7 +112,7 @@ func TestCloud_applyCanceled(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -127,7 +127,7 @@ func TestCloud_applyCanceled(t *testing.T) { t.Fatal("expected apply operation to fail") } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after cancelling apply: %s", err.Error()) } @@ -142,7 +142,7 @@ func TestCloud_applyWithoutPermissions(t *testing.T) { context.Background(), b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -182,7 +182,7 @@ func TestCloud_applyWithVCS(t *testing.T) { context.Background(), b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), VCSRepo: &tfe.VCSRepoOptions{}, }, ) @@ -226,7 +226,7 @@ func TestCloud_applyWithParallelism(t *testing.T) { b.ContextOpts = &terraform.ContextOpts{} } b.ContextOpts.Parallelism = 3 - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -253,7 +253,7 @@ func TestCloud_applyWithPlan(t *testing.T) { defer configCleanup() op.PlanFile = &planfile.Reader{} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -284,7 +284,7 @@ func TestCloud_applyWithoutRefresh(t *testing.T) { defer done(t) op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -322,7 +322,7 @@ func TestCloud_applyWithoutRefreshIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -353,7 +353,7 @@ func TestCloud_applyWithRefreshOnly(t *testing.T) { defer done(t) op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -391,7 +391,7 @@ func TestCloud_applyWithRefreshOnlyIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -424,7 +424,7 @@ func TestCloud_applyWithTarget(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -466,7 +466,7 @@ func TestCloud_applyWithTargetIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -499,7 +499,7 @@ func TestCloud_applyWithReplace(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -539,7 +539,7 @@ func TestCloud_applyWithReplaceIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -569,7 +569,7 @@ func TestCloud_applyWithVariables(t *testing.T) { defer configCleanup() op.Variables = testVariables(terraform.ValueFromNamedFile, "foo", "bar") - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -595,7 +595,7 @@ func TestCloud_applyNoConfig(t *testing.T) { op, configCleanup, done := testOperationApply(t, "./testdata/empty") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -616,7 +616,7 @@ func TestCloud_applyNoConfig(t *testing.T) { t.Fatalf("expected configuration files error, got: %v", errOutput) } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) // An error suggests that the state was not unlocked after apply if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after failed apply: %s", err.Error()) @@ -631,7 +631,7 @@ func TestCloud_applyNoChanges(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -668,7 +668,7 @@ func TestCloud_applyNoApprove(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -709,7 +709,7 @@ func TestCloud_applyAutoApprove(t *testing.T) { op.AutoApprove = true op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -754,7 +754,7 @@ func TestCloud_applyApprovedExternally(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName ctx := context.Background() @@ -828,7 +828,7 @@ func TestCloud_applyDiscardedExternally(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName ctx := context.Background() @@ -898,7 +898,7 @@ func TestCloud_applyWithAutoApply(t *testing.T) { b.organization, tfe.WorkspaceCreateOptions{ AutoApply: tfe.Bool(true), - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -967,7 +967,7 @@ func TestCloud_applyForceLocal(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName streams, done := terminal.StreamsForTesting(t) view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams)) @@ -1013,7 +1013,7 @@ func TestCloud_applyWorkspaceWithoutOperations(t *testing.T) { ctx, b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "no-operations"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "no-operations"), }, ) if err != nil { @@ -1072,7 +1072,7 @@ func TestCloud_applyLockTimeout(t *testing.T) { ctx := context.Background() // Retrieve the workspace used to run this operation in. - w, err := b.client.Workspaces.Read(ctx, b.organization, b.workspaceMapping.name) + w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name) if err != nil { t.Fatalf("error retrieving workspace: %v", err) } @@ -1103,7 +1103,7 @@ func TestCloud_applyLockTimeout(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName _, err = b.Operation(context.Background(), op) if err != nil { @@ -1154,7 +1154,7 @@ func TestCloud_applyDestroy(t *testing.T) { op.PlanMode = plans.DestroyMode op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1200,7 +1200,7 @@ func TestCloud_applyDestroyNoConfig(t *testing.T) { op.PlanMode = plans.DestroyMode op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1234,7 +1234,7 @@ func TestCloud_applyPolicyPass(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1281,7 +1281,7 @@ func TestCloud_applyPolicyHardFail(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1337,7 +1337,7 @@ func TestCloud_applyPolicySoftFail(t *testing.T) { op.AutoApprove = false op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1383,7 +1383,7 @@ func TestCloud_applyPolicySoftFailAutoApproveSuccess(t *testing.T) { op.AutoApprove = true op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1432,7 +1432,7 @@ func TestCloud_applyPolicySoftFailAutoApply(t *testing.T) { b.organization, tfe.WorkspaceCreateOptions{ AutoApply: tfe.Bool(true), - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -1492,7 +1492,7 @@ func TestCloud_applyWithRemoteError(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1581,7 +1581,7 @@ func TestCloud_applyVersionCheck(t *testing.T) { _, err := b.client.Workspaces.Update( ctx, b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ Operations: tfe.Bool(tc.hasOperations), TerraformVersion: tfe.String(tc.remoteVersion), @@ -1606,7 +1606,7 @@ func TestCloud_applyVersionCheck(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(ctx, op) if err != nil { diff --git a/internal/cloud/backend_context.go b/internal/cloud/backend_context.go index 32a1e52a25..95c80c5cbf 100644 --- a/internal/cloud/backend_context.go +++ b/internal/cloud/backend_context.go @@ -143,9 +143,9 @@ func (b *Cloud) getRemoteWorkspaceName(localWorkspaceName string) string { // The default workspace name is a special case, for when the backend // is configured to with to an exact remote workspace rather than with // a remote workspace _prefix_. - return b.workspaceMapping.name - case b.workspaceMapping.prefix != "" && !strings.HasPrefix(localWorkspaceName, b.workspaceMapping.prefix): - return b.workspaceMapping.prefix + localWorkspaceName + return b.WorkspaceMapping.Name + case b.WorkspaceMapping.Prefix != "" && !strings.HasPrefix(localWorkspaceName, b.WorkspaceMapping.Prefix): + return b.WorkspaceMapping.Prefix + localWorkspaceName default: return localWorkspaceName } diff --git a/internal/cloud/backend_context_test.go b/internal/cloud/backend_context_test.go index 683ad98eba..7a7668a83a 100644 --- a/internal/cloud/backend_context_test.go +++ b/internal/cloud/backend_context_test.go @@ -182,7 +182,7 @@ func TestRemoteContextWithVars(t *testing.T) { _, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir) defer configCleanup() - workspaceID, err := b.getRemoteWorkspaceID(context.Background(), backend.DefaultStateName) + workspaceID, err := b.getRemoteWorkspaceID(context.Background(), testBackendSingleWorkspaceName) if err != nil { t.Fatal(err) } @@ -194,7 +194,7 @@ func TestRemoteContextWithVars(t *testing.T) { ConfigDir: configDir, ConfigLoader: configLoader, StateLocker: clistate.NewLocker(0, view), - Workspace: backend.DefaultStateName, + Workspace: testBackendSingleWorkspaceName, } v := test.Opts @@ -216,7 +216,7 @@ func TestRemoteContextWithVars(t *testing.T) { } // When Context() returns an error, it should unlock the state, // so re-locking it is expected to succeed. - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state: %s", err.Error()) } @@ -225,7 +225,7 @@ func TestRemoteContextWithVars(t *testing.T) { t.Fatalf("unexpected error\ngot: %s\nwant: ", diags.Err().Error()) } // When Context() succeeds, this should fail w/ "workspace already locked" - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil { t.Fatal("unexpected success locking state after Context") } diff --git a/internal/cloud/backend_plan_test.go b/internal/cloud/backend_plan_test.go index 1dcfdeb07c..a76841f2b2 100644 --- a/internal/cloud/backend_plan_test.go +++ b/internal/cloud/backend_plan_test.go @@ -59,7 +59,7 @@ func TestCloud_planBasic(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -82,7 +82,7 @@ func TestCloud_planBasic(t *testing.T) { t.Fatalf("expected plan summary in output: %s", output) } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) // An error suggests that the state was not unlocked after the operation finished if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after successful plan: %s", err.Error()) @@ -97,7 +97,7 @@ func TestCloud_planCanceled(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -112,7 +112,7 @@ func TestCloud_planCanceled(t *testing.T) { t.Fatal("expected plan operation to fail") } - stateMgr, _ := b.StateMgr(backend.DefaultStateName) + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) // An error suggests that the state was not unlocked after the operation finished if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err != nil { t.Fatalf("unexpected error locking state after cancelled plan: %s", err.Error()) @@ -127,7 +127,7 @@ func TestCloud_planLongLine(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -160,7 +160,7 @@ func TestCloud_planWithoutPermissions(t *testing.T) { context.Background(), b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "prod"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"), }, ) if err != nil { @@ -201,7 +201,7 @@ func TestCloud_planWithParallelism(t *testing.T) { b.ContextOpts = &terraform.ContextOpts{} } b.ContextOpts.Parallelism = 3 - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -228,7 +228,7 @@ func TestCloud_planWithPlan(t *testing.T) { defer configCleanup() op.PlanFile = &planfile.Reader{} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -258,7 +258,7 @@ func TestCloud_planWithPath(t *testing.T) { defer configCleanup() op.PlanOutPath = "./testdata/plan" - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -289,7 +289,7 @@ func TestCloud_planWithoutRefresh(t *testing.T) { defer done(t) op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -327,7 +327,7 @@ func TestCloud_planWithoutRefreshIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanRefresh = false - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -358,7 +358,7 @@ func TestCloud_planWithRefreshOnly(t *testing.T) { defer done(t) op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -396,7 +396,7 @@ func TestCloud_planWithRefreshOnlyIncompatibleAPIVersion(t *testing.T) { b.client.SetFakeRemoteAPIVersion("2.3") op.PlanMode = plans.RefreshOnlyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -452,7 +452,7 @@ func TestCloud_planWithTarget(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -501,7 +501,7 @@ func TestCloud_planWithTargetIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceStr("null_resource.foo") op.Targets = []addrs.Targetable{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -534,7 +534,7 @@ func TestCloud_planWithReplace(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -574,7 +574,7 @@ func TestCloud_planWithReplaceIncompatibleAPIVersion(t *testing.T) { addr, _ := addrs.ParseAbsResourceInstanceStr("null_resource.foo") op.ForceReplace = []addrs.AbsResourceInstance{addr} - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -604,7 +604,7 @@ func TestCloud_planWithVariables(t *testing.T) { defer configCleanup() op.Variables = testVariables(terraform.ValueFromCLIArg, "foo", "bar") - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -630,7 +630,7 @@ func TestCloud_planNoConfig(t *testing.T) { op, configCleanup, done := testOperationPlan(t, "./testdata/empty") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -660,7 +660,7 @@ func TestCloud_planNoChanges(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -699,7 +699,7 @@ func TestCloud_planForceLocal(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName streams, done := terminal.StreamsForTesting(t) view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams)) @@ -735,7 +735,7 @@ func TestCloud_planWithoutOperationsEntitlement(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName streams, done := terminal.StreamsForTesting(t) view := views.NewOperation(arguments.ViewHuman, false, views.NewView(streams)) @@ -774,7 +774,7 @@ func TestCloud_planWorkspaceWithoutOperations(t *testing.T) { ctx, b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.prefix + "no-operations"), + Name: tfe.String(b.WorkspaceMapping.Prefix + "no-operations"), }, ) if err != nil { @@ -820,7 +820,7 @@ func TestCloud_planLockTimeout(t *testing.T) { ctx := context.Background() // Retrieve the workspace used to run this operation in. - w, err := b.client.Workspaces.Read(ctx, b.organization, b.workspaceMapping.name) + w, err := b.client.Workspaces.Read(ctx, b.organization, b.WorkspaceMapping.Name) if err != nil { t.Fatalf("error retrieving workspace: %v", err) } @@ -851,7 +851,7 @@ func TestCloud_planLockTimeout(t *testing.T) { op.UIIn = input op.UIOut = b.CLI - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName _, err = b.Operation(context.Background(), op) if err != nil { @@ -893,7 +893,7 @@ func TestCloud_planDestroy(t *testing.T) { defer done(t) op.PlanMode = plans.DestroyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -918,7 +918,7 @@ func TestCloud_planDestroyNoConfig(t *testing.T) { defer done(t) op.PlanMode = plans.DestroyMode - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -943,7 +943,7 @@ func TestCloud_planWithWorkingDirectory(t *testing.T) { } // Configure the workspace to use a custom working directory. - _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.workspaceMapping.name, options) + _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.WorkspaceMapping.Name, options) if err != nil { t.Fatalf("error configuring working directory: %v", err) } @@ -952,7 +952,7 @@ func TestCloud_planWithWorkingDirectory(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -988,7 +988,7 @@ func TestCloud_planWithWorkingDirectoryFromCurrentPath(t *testing.T) { } // Configure the workspace to use a custom working directory. - _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.workspaceMapping.name, options) + _, err := b.client.Workspaces.Update(context.Background(), b.organization, b.WorkspaceMapping.Name, options) if err != nil { t.Fatalf("error configuring working directory: %v", err) } @@ -1011,7 +1011,7 @@ func TestCloud_planWithWorkingDirectoryFromCurrentPath(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1043,7 +1043,7 @@ func TestCloud_planCostEstimation(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1078,7 +1078,7 @@ func TestCloud_planPolicyPass(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1112,7 +1112,7 @@ func TestCloud_planPolicyHardFail(t *testing.T) { op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-hard-failed") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1152,7 +1152,7 @@ func TestCloud_planPolicySoftFail(t *testing.T) { op, configCleanup, done := testOperationPlan(t, "./testdata/plan-policy-soft-failed") defer configCleanup() - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { @@ -1193,7 +1193,7 @@ func TestCloud_planWithRemoteError(t *testing.T) { defer configCleanup() defer done(t) - op.Workspace = backend.DefaultStateName + op.Workspace = testBackendSingleWorkspaceName run, err := b.Operation(context.Background(), op) if err != nil { diff --git a/internal/cloud/backend_state_test.go b/internal/cloud/backend_state_test.go index a94c60c6ee..e39dd211f1 100644 --- a/internal/cloud/backend_state_test.go +++ b/internal/cloud/backend_state_test.go @@ -5,7 +5,6 @@ import ( "os" "testing" - "github.com/hashicorp/terraform/internal/backend" "github.com/hashicorp/terraform/internal/states" "github.com/hashicorp/terraform/internal/states/remote" "github.com/hashicorp/terraform/internal/states/statefile" @@ -24,12 +23,12 @@ func TestRemoteClient_stateLock(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() - s1, err := b.StateMgr(backend.DefaultStateName) + s1, err := b.StateMgr(testBackendSingleWorkspaceName) if err != nil { t.Fatalf("expected no error, got %v", err) } - s2, err := b.StateMgr(backend.DefaultStateName) + s2, err := b.StateMgr(testBackendSingleWorkspaceName) if err != nil { t.Fatalf("expected no error, got %v", err) } diff --git a/internal/cloud/backend_test.go b/internal/cloud/backend_test.go index 928182b535..9f1a5190b2 100644 --- a/internal/cloud/backend_test.go +++ b/internal/cloud/backend_test.go @@ -24,13 +24,30 @@ func TestCloud(t *testing.T) { var _ backend.CLI = New(nil) } -func TestCloud_backendDefault(t *testing.T) { +func TestCloud_backendWithName(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() - backend.TestBackendStates(t, b) - backend.TestBackendStateLocks(t, b, b) - backend.TestBackendStateForceUnlock(t, b, b) + workspaces, err := b.Workspaces() + if err != nil { + t.Fatalf("error: %v", err) + } + + if len(workspaces) != 1 || workspaces[0] != testBackendSingleWorkspaceName { + t.Fatalf("should only have a single configured workspace matching the configured 'name' strategy, but got: %#v", workspaces) + } + + if _, err := b.StateMgr("foo"); err != backend.ErrWorkspacesNotSupported { + t.Fatalf("expected fetching a state which is NOT the single configured workspace to have an ErrWorkspacesNotSupported error, but got: %v", err) + } + + if err := b.DeleteWorkspace(testBackendSingleWorkspaceName); err != backend.ErrWorkspacesNotSupported { + t.Fatalf("expected deleting the single configured workspace name to result in an error, but got: %v", err) + } + + if err := b.DeleteWorkspace("foo"); err != backend.ErrWorkspacesNotSupported { + t.Fatalf("expected deleting a workspace which is NOT the configured workspace name to result in an error, but got: %v", err) + } } func TestCloud_backendWithPrefix(t *testing.T) { @@ -428,15 +445,15 @@ func TestCloud_setConfigurationFields(t *testing.T) { if tc.expectedOrganziation != "" && b.organization != tc.expectedOrganziation { t.Fatalf("%s: expected organization (%s) to match configured organization (%s)", name, b.organization, tc.expectedOrganziation) } - if tc.expectedWorkspacePrefix != "" && b.workspaceMapping.prefix != tc.expectedWorkspacePrefix { - t.Fatalf("%s: expected workspace prefix mapping (%s) to match configured workspace prefix (%s)", name, b.workspaceMapping.prefix, tc.expectedWorkspacePrefix) + if tc.expectedWorkspacePrefix != "" && b.WorkspaceMapping.Prefix != tc.expectedWorkspacePrefix { + t.Fatalf("%s: expected workspace prefix mapping (%s) to match configured workspace prefix (%s)", name, b.WorkspaceMapping.Prefix, tc.expectedWorkspacePrefix) } - if tc.expectedWorkspaceName != "" && b.workspaceMapping.name != tc.expectedWorkspaceName { - t.Fatalf("%s: expected workspace name mapping (%s) to match configured workspace name (%s)", name, b.workspaceMapping.name, tc.expectedWorkspaceName) + if tc.expectedWorkspaceName != "" && b.WorkspaceMapping.Name != tc.expectedWorkspaceName { + t.Fatalf("%s: expected workspace name mapping (%s) to match configured workspace name (%s)", name, b.WorkspaceMapping.Name, tc.expectedWorkspaceName) } if len(tc.expectedWorkspaceTags) > 0 { presentSet := make(map[string]struct{}) - for _, tag := range b.workspaceMapping.tags { + for _, tag := range b.WorkspaceMapping.Tags { presentSet[tag] = struct{}{} } @@ -454,18 +471,18 @@ func TestCloud_setConfigurationFields(t *testing.T) { } } - for _, actual := range b.workspaceMapping.tags { + for _, actual := range b.WorkspaceMapping.Tags { if _, ok := expectedSet[actual]; !ok { unexpected = append(missing, actual) } } if len(missing) > 0 { - t.Fatalf("%s: expected workspace tag mapping (%s) to contain the following tags: %s", name, b.workspaceMapping.tags, missing) + t.Fatalf("%s: expected workspace tag mapping (%s) to contain the following tags: %s", name, b.WorkspaceMapping.Tags, missing) } if len(unexpected) > 0 { - t.Fatalf("%s: expected workspace tag mapping (%s) to NOT contain the following tags: %s", name, b.workspaceMapping.tags, unexpected) + t.Fatalf("%s: expected workspace tag mapping (%s) to NOT contain the following tags: %s", name, b.WorkspaceMapping.Tags, unexpected) } } @@ -575,28 +592,16 @@ func TestCloud_addAndRemoveWorkspacesDefault(t *testing.T) { b, bCleanup := testBackendDefault(t) defer bCleanup() - if _, err := b.Workspaces(); err != backend.ErrWorkspacesNotSupported { - t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) - } - - if _, err := b.StateMgr(backend.DefaultStateName); err != nil { - t.Fatalf("expected no error, got %v", err) - } - - if _, err := b.StateMgr("prod"); err != backend.ErrWorkspacesNotSupported { - t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) - } - - if err := b.DeleteWorkspace(backend.DefaultStateName); err != nil { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil { t.Fatalf("expected no error, got %v", err) } - if err := b.DeleteWorkspace("prod"); err != backend.ErrWorkspacesNotSupported { + if err := b.DeleteWorkspace(testBackendSingleWorkspaceName); err != backend.ErrWorkspacesNotSupported { t.Fatalf("expected error %v, got %v", backend.ErrWorkspacesNotSupported, err) } } -func TestCloud_addAndRemoveWorkspacesNoDefault(t *testing.T) { +func TestCloud_addAndRemoveWorkspacesWithPrefix(t *testing.T) { b, bCleanup := testBackendWithPrefix(t) defer bCleanup() @@ -808,7 +813,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String(v0140.String()), }, @@ -817,7 +822,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { } // This should succeed - if _, err := b.StateMgr(backend.DefaultStateName); err != nil { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil { t.Fatalf("expected no error, got %v", err) } @@ -825,7 +830,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String(v0135.String()), }, @@ -835,7 +840,7 @@ func TestCloud_StateMgr_versionCheck(t *testing.T) { // This should fail want := `Remote workspace Terraform version "0.13.5" does not match local Terraform version "0.14.0"` - if _, err := b.StateMgr(backend.DefaultStateName); err.Error() != want { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err.Error() != want { t.Fatalf("wrong error\n got: %v\nwant: %v", err.Error(), want) } } @@ -865,7 +870,7 @@ func TestCloud_StateMgr_versionCheckLatest(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String("latest"), }, @@ -874,7 +879,7 @@ func TestCloud_StateMgr_versionCheckLatest(t *testing.T) { } // This should succeed despite not being a string match - if _, err := b.StateMgr(backend.DefaultStateName); err != nil { + if _, err := b.StateMgr(testBackendSingleWorkspaceName); err != nil { t.Fatalf("expected no error, got %v", err) } } @@ -923,7 +928,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ Operations: tfe.Bool(tc.operations), TerraformVersion: tfe.String(tc.remote), @@ -974,7 +979,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion_workspaceErrors(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String("1.0.cheetarah"), }, @@ -1022,7 +1027,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion_ignoreFlagSet(t *testing.T) { if _, err := b.client.Workspaces.Update( context.Background(), b.organization, - b.workspaceMapping.name, + b.WorkspaceMapping.Name, tfe.WorkspaceUpdateOptions{ TerraformVersion: tfe.String(remote.String()), }, @@ -1041,7 +1046,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion_ignoreFlagSet(t *testing.T) { if got, want := diags[0].Description().Summary, "Terraform version mismatch"; got != want { t.Errorf("wrong summary: got %s, want %s", got, want) } - wantDetail := "The local Terraform version (0.14.0) does not match the configured version for remote workspace hashicorp/prod (0.13.5)." + wantDetail := "The local Terraform version (0.14.0) does not match the configured version for remote workspace hashicorp/app-prod (0.13.5)." if got := diags[0].Description().Detail; got != wantDetail { t.Errorf("wrong summary: got %s, want %s", got, wantDetail) } diff --git a/internal/cloud/testing.go b/internal/cloud/testing.go index d289a42c2d..9dd570e693 100644 --- a/internal/cloud/testing.go +++ b/internal/cloud/testing.go @@ -38,6 +38,7 @@ var ( credsSrc = auth.StaticCredentialsSource(map[svchost.Hostname]map[string]interface{}{ tfeHost: {"token": testCred}, }) + testBackendSingleWorkspaceName = "app-prod" ) // mockInput is a mock implementation of terraform.UIInput. @@ -70,7 +71,7 @@ func testBackendDefault(t *testing.T) (*Cloud, func()) { "organization": cty.StringVal("hashicorp"), "token": cty.NullVal(cty.String), "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), + "name": cty.StringVal(testBackendSingleWorkspaceName), "prefix": cty.NullVal(cty.String), "tags": cty.NullVal(cty.Set(cty.String)), }), @@ -116,7 +117,7 @@ func testBackendNoOperations(t *testing.T) (*Cloud, func()) { "organization": cty.StringVal("no-operations"), "token": cty.NullVal(cty.String), "workspaces": cty.ObjectVal(map[string]cty.Value{ - "name": cty.StringVal("prod"), + "name": cty.StringVal(testBackendSingleWorkspaceName), "prefix": cty.NullVal(cty.String), "tags": cty.NullVal(cty.Set(cty.String)), }), @@ -128,7 +129,7 @@ func testRemoteClient(t *testing.T) remote.Client { b, bCleanup := testBackendDefault(t) defer bCleanup() - raw, err := b.StateMgr(backend.DefaultStateName) + raw, err := b.StateMgr(testBackendSingleWorkspaceName) if err != nil { t.Fatalf("error: %v", err) } @@ -182,9 +183,9 @@ func testBackend(t *testing.T, obj cty.Value) (*Cloud, func()) { } // Create the default workspace if required. - if b.workspaceMapping.name != "" { + if b.WorkspaceMapping.Name != "" { _, err = b.client.Workspaces.Create(ctx, b.organization, tfe.WorkspaceCreateOptions{ - Name: tfe.String(b.workspaceMapping.name), + Name: tfe.String(b.WorkspaceMapping.Name), }) if err != nil { t.Fatalf("error: %v", err)