Remove prefix from the cloud backend config

Now that we have tags we no longer need prefix.
This commit is contained in:
Barrett Clark 2021-10-11 16:26:07 -05:00 committed by Chris Arcand
parent edbc84420c
commit 83337de654
7 changed files with 81 additions and 302 deletions

View File

@ -128,11 +128,6 @@ func (b *Cloud) ConfigSchema() *configschema.Block {
Optional: true,
Description: schemaDescriptionName,
},
"prefix": {
Type: cty.String,
Optional: true,
Description: schemaDescriptionPrefix,
},
"tags": {
Type: cty.Set(cty.String),
Optional: true,
@ -162,9 +157,6 @@ func (b *Cloud) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
if val := workspaces.GetAttr("name"); !val.IsNull() {
WorkspaceMapping.Name = val.AsString()
}
if val := workspaces.GetAttr("prefix"); !val.IsNull() {
WorkspaceMapping.Prefix = val.AsString()
}
if val := workspaces.GetAttr("tags"); !val.IsNull() {
err := gocty.FromCtyValue(val, &WorkspaceMapping.Tags)
if err != nil {
@ -177,7 +169,7 @@ func (b *Cloud) PrepareConfig(obj cty.Value) (cty.Value, tfdiags.Diagnostics) {
// Make sure have a workspace mapping strategy present
case WorkspaceNoneStrategy:
diags = diags.Append(invalidWorkspaceConfigMissingValues)
// Make sure that only one of workspace name or a prefix is configured.
// Make sure that a workspace name is configured.
case WorkspaceInvalidStrategy:
diags = diags.Append(invalidWorkspaceConfigMisconfiguration)
}
@ -339,16 +331,13 @@ func (b *Cloud) setConfigurationFields(obj cty.Value) tfdiags.Diagnostics {
}
// Get the workspaces configuration block and retrieve the
// default workspace name and prefix.
// default workspace name.
if workspaces := obj.GetAttr("workspaces"); !workspaces.IsNull() {
// PrepareConfig checks that you cannot set both of these.
if val := workspaces.GetAttr("name"); !val.IsNull() {
b.WorkspaceMapping.Name = val.AsString()
}
if val := workspaces.GetAttr("prefix"); !val.IsNull() {
b.WorkspaceMapping.Prefix = val.AsString()
}
if val := workspaces.GetAttr("tags"); !val.IsNull() {
var tags []string
err := gocty.FromCtyValue(val, &tags)
@ -447,10 +436,7 @@ 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 WorkspacePrefixStrategy:
options.Search = tfe.String(b.WorkspaceMapping.Prefix)
case WorkspaceTagsStrategy:
if b.WorkspaceMapping.Strategy() == WorkspaceTagsStrategy {
taglist := strings.Join(b.WorkspaceMapping.Tags, ",")
options.Tags = &taglist
}
@ -462,18 +448,7 @@ func (b *Cloud) Workspaces() ([]string, error) {
}
for _, w := range wl.Items {
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. 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)
}
names = append(names, w.Name)
}
// Exit the loop when we've seen all pages.
@ -502,11 +477,6 @@ func (b *Cloud) DeleteWorkspace(name string) error {
}
// Configure the remote workspace name.
switch {
case b.WorkspaceMapping.Strategy() == WorkspacePrefixStrategy && !strings.HasPrefix(name, b.WorkspaceMapping.Prefix):
name = b.WorkspaceMapping.Prefix + name
}
client := &remoteClient{
client: b.client,
organization: b.organization,
@ -528,11 +498,6 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) {
return nil, backend.ErrWorkspacesNotSupported
}
// 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)
if err != nil && err != tfe.ErrResourceNotFound {
return nil, fmt.Errorf("Failed to retrieve workspace %s: %v", name, err)
@ -588,11 +553,6 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) {
func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.RunningOperation, error) {
name := 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.
w, err := b.client.Workspaces.Read(ctx, b.organization, name)
if err != nil {
@ -908,9 +868,8 @@ func (b *Cloud) cliColorize() *colorstring.Colorize {
}
type WorkspaceMapping struct {
Name string
Prefix string
Tags []string
Name string
Tags []string
}
type workspaceStrategy string
@ -918,20 +877,17 @@ type workspaceStrategy string
const (
WorkspaceTagsStrategy workspaceStrategy = "tags"
WorkspaceNameStrategy workspaceStrategy = "name"
WorkspacePrefixStrategy workspaceStrategy = "prefix"
WorkspaceNoneStrategy workspaceStrategy = "none"
WorkspaceInvalidStrategy workspaceStrategy = "invalid"
)
func (wm WorkspaceMapping) Strategy() workspaceStrategy {
switch {
case len(wm.Tags) > 0 && wm.Name == "" && wm.Prefix == "":
case len(wm.Tags) > 0 && wm.Name == "":
return WorkspaceTagsStrategy
case len(wm.Tags) == 0 && wm.Name != "" && wm.Prefix == "":
case len(wm.Tags) == 0 && wm.Name != "":
return WorkspaceNameStrategy
case len(wm.Tags) == 0 && wm.Name == "" && wm.Prefix != "":
return WorkspacePrefixStrategy
case len(wm.Tags) == 0 && wm.Name == "" && wm.Prefix == "":
case len(wm.Tags) == 0 && wm.Name == "":
return WorkspaceNoneStrategy
default:
// Any other combination is invalid as each strategy is mutually exclusive
@ -999,9 +955,7 @@ configuration to workspaces within a Terraform Cloud organization. Three strateg
[bold]tags[reset] - %s
[bold]name[reset] - %s
[bold]prefix[reset] - %s`, schemaDescriptionTags, schemaDescriptionName, schemaDescriptionPrefix)
[bold]name[reset] - %s`, schemaDescriptionTags, schemaDescriptionName)
schemaDescriptionHostname = `The Terraform Enterprise hostname to connect to. This optional argument defaults to app.terraform.io
for use with Terraform Cloud.`
@ -1014,11 +968,8 @@ configuration file or configured credential helper.`
schemaDescriptionTags = `A set of tags used to select remote Terraform Cloud workspaces to be used for this single
configuration. New workspaces will automatically be tagged with these tag values. Generally, this
is the primary and recommended strategy to use. This option conflicts with "prefix" and "name".`
is the primary and recommended strategy to use. This option conflicts with "name".`
schemaDescriptionName = `The name of a single Terraform Cloud workspace to be used with this configuration When configured
only the specified workspace can be used. This option conflicts with "tags" and "prefix".`
schemaDescriptionPrefix = `DEPRECATED. A name prefix used to select remote Terraform Cloud to be used for this single configuration. New
workspaces will automatically be prefixed with this prefix. This option conflicts with "tags" and "name".`
only the specified workspace can be used. This option conflicts with "tags".`
)

View File

@ -143,7 +143,7 @@ func TestCloud_applyCanceled(t *testing.T) {
}
func TestCloud_applyWithoutPermissions(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
// Create a named workspace without permissions.
@ -151,7 +151,7 @@ func TestCloud_applyWithoutPermissions(t *testing.T) {
context.Background(),
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"),
Name: tfe.String("prod"),
},
)
if err != nil {
@ -183,7 +183,7 @@ func TestCloud_applyWithoutPermissions(t *testing.T) {
}
func TestCloud_applyWithVCS(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
// Create a named workspace with a VCS.
@ -191,7 +191,7 @@ func TestCloud_applyWithVCS(t *testing.T) {
context.Background(),
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"),
Name: tfe.String("prod"),
VCSRepo: &tfe.VCSRepoOptions{},
},
)
@ -774,7 +774,7 @@ func TestCloud_applyDiscardedExternally(t *testing.T) {
}
func TestCloud_applyWithAutoApprove(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
ctrl := gomock.NewController(t)
@ -790,7 +790,7 @@ func TestCloud_applyWithAutoApprove(t *testing.T) {
context.Background(),
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"),
Name: tfe.String("prod"),
},
)
if err != nil {
@ -896,7 +896,7 @@ func TestCloud_applyForceLocal(t *testing.T) {
}
func TestCloud_applyWorkspaceWithoutOperations(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
ctx := context.Background()
@ -906,7 +906,7 @@ func TestCloud_applyWorkspaceWithoutOperations(t *testing.T) {
ctx,
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "no-operations"),
Name: tfe.String("no-operations"),
},
)
if err != nil {
@ -1360,7 +1360,7 @@ func TestCloud_applyPolicySoftFailAutoApprove(t *testing.T) {
context.Background(),
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"),
Name: tfe.String("prod"),
},
)
if err != nil {

View File

@ -4,7 +4,6 @@ import (
"context"
"fmt"
"log"
"strings"
tfe "github.com/hashicorp/go-tfe"
"github.com/hashicorp/hcl/v2"
@ -140,12 +139,8 @@ func (b *Cloud) LocalRun(op *backend.Operation) (*backend.LocalRun, statemgr.Ful
func (b *Cloud) getRemoteWorkspaceName(localWorkspaceName string) string {
switch {
case localWorkspaceName == backend.DefaultStateName:
// 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_.
// The default workspace name is a special case
return b.WorkspaceMapping.Name
case b.WorkspaceMapping.Prefix != "" && !strings.HasPrefix(localWorkspaceName, b.WorkspaceMapping.Prefix):
return b.WorkspaceMapping.Prefix + localWorkspaceName
default:
return localWorkspaceName
}

View File

@ -159,7 +159,7 @@ func TestCloud_planLongLine(t *testing.T) {
}
func TestCloud_planWithoutPermissions(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
// Create a named workspace without permissions.
@ -167,7 +167,7 @@ func TestCloud_planWithoutPermissions(t *testing.T) {
context.Background(),
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "prod"),
Name: tfe.String("prod"),
},
)
if err != nil {
@ -639,7 +639,7 @@ func TestCloud_planWithoutOperationsEntitlement(t *testing.T) {
}
func TestCloud_planWorkspaceWithoutOperations(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
ctx := context.Background()
@ -649,7 +649,7 @@ func TestCloud_planWorkspaceWithoutOperations(t *testing.T) {
ctx,
b.organization,
tfe.WorkspaceCreateOptions{
Name: tfe.String(b.WorkspaceMapping.Prefix + "no-operations"),
Name: tfe.String("no-operations"),
},
)
if err != nil {

View File

@ -5,7 +5,6 @@ import (
"fmt"
"net/http"
"os"
"reflect"
"strings"
"testing"
@ -50,13 +49,6 @@ func TestCloud_backendWithName(t *testing.T) {
}
}
func TestCloud_backendWithPrefix(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
defer bCleanup()
backend.TestBackendStates(t, b)
}
func TestCloud_backendWithTags(t *testing.T) {
b, bCleanup := testBackendWithTags(t)
defer bCleanup()
@ -90,9 +82,8 @@ func TestCloud_PrepareConfig(t *testing.T) {
config: cty.ObjectVal(map[string]cty.Value{
"organization": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedErr: `Invalid organization value: The "organization" attribute value must not be empty.`,
@ -102,36 +93,33 @@ func TestCloud_PrepareConfig(t *testing.T) {
"organization": cty.StringVal("org"),
"workspaces": cty.NullVal(cty.String),
}),
expectedErr: `Invalid workspaces configuration: Missing workspace mapping strategy. Either workspace "tags", "name", or "prefix" is required.`,
expectedErr: `Invalid workspaces configuration: Missing workspace mapping strategy. Either workspace "tags" or "name" is required.`,
},
"workspace: empty tags, name, and prefix": {
"workspace: empty tags, name": {
config: cty.ObjectVal(map[string]cty.Value{
"organization": cty.StringVal("org"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedErr: `Invalid workspaces configuration: Missing workspace mapping strategy. Either workspace "tags", "name", or "prefix" is required.`,
expectedErr: `Invalid workspaces configuration: Missing workspace mapping strategy. Either workspace "tags" or "name" is required.`,
},
"workspace: name and prefix present": {
"workspace: name present": {
config: cty.ObjectVal(map[string]cty.Value{
"organization": cty.StringVal("org"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.StringVal("app-"),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedErr: `Invalid workspaces configuration: Only one of workspace "tags", "name", or "prefix" is allowed.`,
expectedErr: `Invalid workspaces configuration: Only one of workspace "tags" or "name" is allowed.`,
},
"workspace: name and tags present": {
config: cty.ObjectVal(map[string]cty.Value{
"organization": cty.StringVal("org"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"name": cty.StringVal("prod"),
"tags": cty.SetVal(
[]cty.Value{
cty.StringVal("billing"),
@ -139,7 +127,7 @@ func TestCloud_PrepareConfig(t *testing.T) {
),
}),
}),
expectedErr: `Invalid workspaces configuration: Only one of workspace "tags", "name", or "prefix" is allowed.`,
expectedErr: `Invalid workspaces configuration: Only one of workspace "tags" or "name" is allowed.`,
},
}
@ -170,9 +158,8 @@ func TestCloud_config(t *testing.T) {
"organization": cty.StringVal("nonexisting"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
confErr: "organization \"nonexisting\" at host app.terraform.io not found",
@ -183,9 +170,8 @@ func TestCloud_config(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
confErr: "Failed to request discovery document",
@ -197,9 +183,8 @@ func TestCloud_config(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
confErr: "terraform login localhost",
@ -210,8 +195,7 @@ func TestCloud_config(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.NullVal(cty.String),
"name": cty.NullVal(cty.String),
"tags": cty.SetVal(
[]cty.Value{
cty.StringVal("billing"),
@ -226,58 +210,30 @@ func TestCloud_config(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
},
"with_a_prefix": {
"without_a_name_tags": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.StringVal("my-app-"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
},
"without_a_name_prefix_or_tags": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
valErr: `Missing workspace mapping strategy.`,
},
"with_both_a_name_and_a_prefix": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.StringVal("my-app-"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
valErr: `Only one of workspace "tags", "name", or "prefix" is allowed.`,
},
"with_both_a_name_and_tags": {
config: cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"name": cty.StringVal("prod"),
"tags": cty.SetVal(
[]cty.Value{
cty.StringVal("billing"),
@ -285,7 +241,7 @@ func TestCloud_config(t *testing.T) {
),
}),
}),
valErr: `Only one of workspace "tags", "name", or "prefix" is allowed.`,
valErr: `Only one of workspace "tags" or "name" is allowed.`,
},
"null config": {
config: cty.NullVal(cty.EmptyObject),
@ -318,8 +274,7 @@ func TestCloud_configVerifyMinimumTFEVersion(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.NullVal(cty.String),
"name": cty.NullVal(cty.String),
"tags": cty.SetVal(
[]cty.Value{
cty.StringVal("billing"),
@ -353,25 +308,23 @@ func TestCloud_setConfigurationFields(t *testing.T) {
originalForceBackendEnv := os.Getenv("TF_FORCE_LOCAL_BACKEND")
cases := map[string]struct {
obj cty.Value
expectedHostname string
expectedOrganziation string
expectedWorkspacePrefix string
expectedWorkspaceName string
expectedWorkspaceTags []string
expectedForceLocal bool
setEnv func()
resetEnv func()
expectedErr string
obj cty.Value
expectedHostname string
expectedOrganziation string
expectedWorkspaceName string
expectedWorkspaceTags []string
expectedForceLocal bool
setEnv func()
resetEnv func()
expectedErr string
}{
"with hostname set": {
obj: cty.ObjectVal(map[string]cty.Value{
"organization": cty.StringVal("hashicorp"),
"hostname": cty.StringVal("hashicorp.com"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedHostname: "hashicorp.com",
@ -382,9 +335,8 @@ func TestCloud_setConfigurationFields(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"hostname": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedHostname: defaultHostname,
@ -395,36 +347,20 @@ func TestCloud_setConfigurationFields(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"hostname": cty.StringVal("hashicorp.com"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal("prod"),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedHostname: "hashicorp.com",
expectedOrganziation: "hashicorp",
expectedWorkspaceName: "prod",
},
"with workspace prefix set": {
obj: cty.ObjectVal(map[string]cty.Value{
"organization": cty.StringVal("hashicorp"),
"hostname": cty.StringVal("hashicorp.com"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedHostname: "hashicorp.com",
expectedOrganziation: "hashicorp",
expectedWorkspacePrefix: "prod",
},
"with workspace tags set": {
obj: cty.ObjectVal(map[string]cty.Value{
"organization": cty.StringVal("hashicorp"),
"hostname": cty.StringVal("hashicorp.com"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.NullVal(cty.String),
"name": cty.NullVal(cty.String),
"tags": cty.SetVal(
[]cty.Value{
cty.StringVal("billing"),
@ -441,14 +377,12 @@ func TestCloud_setConfigurationFields(t *testing.T) {
"organization": cty.StringVal("hashicorp"),
"hostname": cty.StringVal("hashicorp.com"),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.StringVal("prod"),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
}),
expectedHostname: "hashicorp.com",
expectedOrganziation: "hashicorp",
expectedWorkspacePrefix: "prod",
expectedHostname: "hashicorp.com",
expectedOrganziation: "hashicorp",
setEnv: func() {
os.Setenv("TF_FORCE_LOCAL_BACKEND", "1")
},
@ -482,9 +416,6 @@ 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.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)
}
@ -557,87 +488,6 @@ func TestCloud_addAndRemoveWorkspacesDefault(t *testing.T) {
}
}
func TestCloud_addAndRemoveWorkspacesWithPrefix(t *testing.T) {
b, bCleanup := testBackendWithPrefix(t)
defer bCleanup()
states, err := b.Workspaces()
if err != nil {
t.Fatal(err)
}
expectedWorkspaces := []string(nil)
if !reflect.DeepEqual(states, expectedWorkspaces) {
t.Fatalf("expected states %#+v, got %#+v", expectedWorkspaces, states)
}
if _, err := b.StateMgr(backend.DefaultStateName); err != backend.ErrDefaultWorkspaceNotSupported {
t.Fatalf("expected error %v, got %v", backend.ErrDefaultWorkspaceNotSupported, err)
}
expectedA := "test_A"
if _, err := b.StateMgr(expectedA); err != nil {
t.Fatal(err)
}
states, err = b.Workspaces()
if err != nil {
t.Fatal(err)
}
expectedWorkspaces = append(expectedWorkspaces, expectedA)
if !reflect.DeepEqual(states, expectedWorkspaces) {
t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
}
expectedB := "test_B"
if _, err := b.StateMgr(expectedB); err != nil {
t.Fatal(err)
}
states, err = b.Workspaces()
if err != nil {
t.Fatal(err)
}
expectedWorkspaces = append(expectedWorkspaces, expectedB)
if !reflect.DeepEqual(states, expectedWorkspaces) {
t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
}
if err := b.DeleteWorkspace(backend.DefaultStateName); err != backend.ErrDefaultWorkspaceNotSupported {
t.Fatalf("expected error %v, got %v", backend.ErrDefaultWorkspaceNotSupported, err)
}
if err := b.DeleteWorkspace(expectedA); err != nil {
t.Fatal(err)
}
states, err = b.Workspaces()
if err != nil {
t.Fatal(err)
}
expectedWorkspaces = []string{expectedB}
if !reflect.DeepEqual(states, expectedWorkspaces) {
t.Fatalf("expected %#+v got %#+v", expectedWorkspaces, states)
}
if err := b.DeleteWorkspace(expectedB); err != nil {
t.Fatal(err)
}
states, err = b.Workspaces()
if err != nil {
t.Fatal(err)
}
expectedWorkspaces = []string(nil)
if !reflect.DeepEqual(states, expectedWorkspaces) {
t.Fatalf("expected %#+v, got %#+v", expectedWorkspaces, states)
}
}
func TestCloud_StateMgr_versionCheck(t *testing.T) {
b, bCleanup := testBackendWithName(t)
defer bCleanup()

View File

@ -18,14 +18,14 @@ var (
invalidWorkspaceConfigMissingValues = tfdiags.AttributeValue(
tfdiags.Error,
"Invalid workspaces configuration",
fmt.Sprintf("Missing workspace mapping strategy. Either workspace \"tags\", \"name\", or \"prefix\" is required.\n\n%s", workspaceConfigurationHelp),
fmt.Sprintf("Missing workspace mapping strategy. Either workspace \"tags\" or \"name\" is required.\n\n%s", workspaceConfigurationHelp),
cty.Path{cty.GetAttrStep{Name: "workspaces"}},
)
invalidWorkspaceConfigMisconfiguration = tfdiags.AttributeValue(
tfdiags.Error,
"Invalid workspaces configuration",
fmt.Sprintf("Only one of workspace \"tags\", \"name\", or \"prefix\" is allowed.\n\n%s", workspaceConfigurationHelp),
fmt.Sprintf("Only one of workspace \"tags\" or \"name\" is allowed.\n\n%s", workspaceConfigurationHelp),
cty.Path{cty.GetAttrStep{Name: "workspaces"}},
)
)

View File

@ -71,23 +71,8 @@ func testBackendWithName(t *testing.T) (*Cloud, func()) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.StringVal(testBackendSingleWorkspaceName),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
})
return testBackend(t, obj)
}
func testBackendWithPrefix(t *testing.T) (*Cloud, func()) {
obj := cty.ObjectVal(map[string]cty.Value{
"hostname": cty.NullVal(cty.String),
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.StringVal("my-app-"),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal(testBackendSingleWorkspaceName),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
})
return testBackend(t, obj)
@ -99,8 +84,7 @@ func testBackendWithTags(t *testing.T) (*Cloud, func()) {
"organization": cty.StringVal("hashicorp"),
"token": cty.NullVal(cty.String),
"workspaces": cty.ObjectVal(map[string]cty.Value{
"name": cty.NullVal(cty.String),
"prefix": cty.NullVal(cty.String),
"name": cty.NullVal(cty.String),
"tags": cty.SetVal(
[]cty.Value{
cty.StringVal("billing"),
@ -117,9 +101,8 @@ 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(testBackendSingleWorkspaceName),
"prefix": cty.NullVal(cty.String),
"tags": cty.NullVal(cty.Set(cty.String)),
"name": cty.StringVal(testBackendSingleWorkspaceName),
"tags": cty.NullVal(cty.Set(cty.String)),
}),
})
return testBackend(t, obj)