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.
This commit is contained in:
Chris Arcand 2021-09-20 13:07:53 -05:00
parent a94b2405b1
commit d2b6b5f2b3
8 changed files with 205 additions and 211 deletions

View File

@ -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
}
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) {
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, ",")
options.Tags = &taglist
}
// 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
}
// 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 WorkspacePrefixStrategy:
options.Search = tfe.String(b.WorkspaceMapping.Prefix)
case WorkspaceTagsStrategy:
taglist := strings.Join(b.WorkspaceMapping.Tags, ",")
options.Tags = &taglist
}
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
}
}

View File

@ -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 {

View File

@ -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
}

View File

@ -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: <no error>", 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")
}

View File

@ -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 {

View File

@ -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)
}

View File

@ -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 {
if _, err := b.StateMgr(testBackendSingleWorkspaceName); 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 {
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)
}

View File

@ -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)