cloud: convert uses of worspaces.operations into workspaces.executionMode (#29844)

* convert uses of worspaces.operations into workspaces.executionMode

The cloud package currently uses a deprecated API on workspaces to determine a workspace's execution mode.

Deprecated: Operations (boolean)
New hotness: Execution mode (string - "local", "remote", or "agent")

More details: https://www.terraform.io/docs/cloud/api/workspaces.html#request-body

All uses of Operations field coming from the client (within the cloud package) should be converted to the appropriate ExecutionMode equivalent.
Also, we need to update all acknowledgment of operations field on the tests that are testing the behavior of workspaces.

Co-authored-by: Nick Fagerlund <nick.fagerlund@gmail.com>

Co-authored-by: Nick Fagerlund <nick.fagerlund@gmail.com>
This commit is contained in:
Luces Huayhuaca 2021-11-08 07:20:15 -08:00 committed by GitHub
parent 5ac1074c54
commit 4e3218b4d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 36 deletions

View File

@ -636,7 +636,7 @@ func (b *Cloud) Operation(ctx context.Context, op *backend.Operation) (*backend.
b.IgnoreVersionConflict() b.IgnoreVersionConflict()
// Check if we need to use the local backend to run the operation. // Check if we need to use the local backend to run the operation.
if b.forceLocal || !w.Operations { if b.forceLocal || isLocalExecutionMode(w.ExecutionMode) {
// Record that we're forced to run operations locally to allow the // Record that we're forced to run operations locally to allow the
// command package UI to operate correctly // command package UI to operate correctly
b.forceLocal = true b.forceLocal = true
@ -825,9 +825,9 @@ func (b *Cloud) VerifyWorkspaceTerraformVersion(workspaceName string) tfdiags.Di
return nil return nil
} }
// If the workspace has remote operations disabled, the remote Terraform // If the workspace has execution-mode set to local, the remote Terraform
// version is effectively meaningless, so we'll skip version verification. // version is effectively meaningless, so we'll skip version verification.
if !workspace.Operations { if isLocalExecutionMode(workspace.ExecutionMode) {
return nil return nil
} }
@ -965,6 +965,10 @@ func (wm WorkspaceMapping) Strategy() workspaceStrategy {
} }
} }
func isLocalExecutionMode(execMode string) bool {
return execMode == "local"
}
func (wm WorkspaceMapping) tfeTags() []*tfe.Tag { func (wm WorkspaceMapping) tfeTags() []*tfe.Tag {
var tags []*tfe.Tag var tags []*tfe.Tag

View File

@ -1447,36 +1447,36 @@ func TestCloud_applyVersionCheck(t *testing.T) {
localVersion string localVersion string
remoteVersion string remoteVersion string
forceLocal bool forceLocal bool
hasOperations bool executionMode string
wantErr string wantErr string
}{ }{
"versions can be different for remote apply": { "versions can be different for remote apply": {
localVersion: "0.14.0", localVersion: "0.14.0",
remoteVersion: "0.13.5", remoteVersion: "0.13.5",
hasOperations: true, executionMode: "remote",
}, },
"versions can be different for local apply": { "versions can be different for local apply": {
localVersion: "0.14.0", localVersion: "0.14.0",
remoteVersion: "0.13.5", remoteVersion: "0.13.5",
hasOperations: false, executionMode: "local",
}, },
"force local with remote operations and different versions is acceptable": { "force local with remote operations and different versions is acceptable": {
localVersion: "0.14.0", localVersion: "0.14.0",
remoteVersion: "0.14.0-acme-provider-bundle", remoteVersion: "0.14.0-acme-provider-bundle",
forceLocal: true, forceLocal: true,
hasOperations: true, executionMode: "remote",
}, },
"no error if versions are identical": { "no error if versions are identical": {
localVersion: "0.14.0", localVersion: "0.14.0",
remoteVersion: "0.14.0", remoteVersion: "0.14.0",
forceLocal: true, forceLocal: true,
hasOperations: true, executionMode: "remote",
}, },
"no error if force local but workspace has remote operations disabled": { "no error if force local but workspace has remote operations disabled": {
localVersion: "0.14.0", localVersion: "0.14.0",
remoteVersion: "0.13.5", remoteVersion: "0.13.5",
forceLocal: true, forceLocal: true,
hasOperations: false, executionMode: "local",
}, },
} }
@ -1512,7 +1512,7 @@ func TestCloud_applyVersionCheck(t *testing.T) {
b.organization, b.organization,
b.WorkspaceMapping.Name, b.WorkspaceMapping.Name,
tfe.WorkspaceUpdateOptions{ tfe.WorkspaceUpdateOptions{
Operations: tfe.Bool(tc.hasOperations), ExecutionMode: tfe.String(tc.executionMode),
TerraformVersion: tfe.String(tc.remoteVersion), TerraformVersion: tfe.String(tc.remoteVersion),
}, },
) )
@ -1566,7 +1566,7 @@ func TestCloud_applyVersionCheck(t *testing.T) {
hasRemote := strings.Contains(output, "Running apply in Terraform Cloud") hasRemote := strings.Contains(output, "Running apply in Terraform Cloud")
hasSummary := strings.Contains(output, "1 added, 0 changed, 0 destroyed") hasSummary := strings.Contains(output, "1 added, 0 changed, 0 destroyed")
hasResources := run.State.HasManagedResourceInstanceObjects() hasResources := run.State.HasManagedResourceInstanceObjects()
if !tc.forceLocal && tc.hasOperations { if !tc.forceLocal && !isLocalExecutionMode(tc.executionMode) {
if !hasRemote { if !hasRemote {
t.Errorf("missing TFC header in output: %s", output) t.Errorf("missing TFC header in output: %s", output)
} }

View File

@ -682,29 +682,29 @@ func TestCloud_VerifyWorkspaceTerraformVersion(t *testing.T) {
testCases := []struct { testCases := []struct {
local string local string
remote string remote string
operations bool executionMode string
wantErr bool wantErr bool
}{ }{
{"0.13.5", "0.13.5", true, false}, {"0.13.5", "0.13.5", "agent", false},
{"0.14.0", "0.13.5", true, true}, {"0.14.0", "0.13.5", "remote", true},
{"0.14.0", "0.13.5", false, false}, {"0.14.0", "0.13.5", "local", false},
{"0.14.0", "0.14.1", true, false}, {"0.14.0", "0.14.1", "remote", false},
{"0.14.0", "1.0.99", true, false}, {"0.14.0", "1.0.99", "remote", false},
{"0.14.0", "1.1.0", true, false}, {"0.14.0", "1.1.0", "remote", false},
{"0.14.0", "1.2.0", true, true}, {"0.14.0", "1.2.0", "remote", true},
{"1.2.0", "1.2.99", true, false}, {"1.2.0", "1.2.99", "remote", false},
{"1.2.0", "1.3.0", true, true}, {"1.2.0", "1.3.0", "remote", true},
{"0.15.0", "latest", true, false}, {"0.15.0", "latest", "remote", false},
{"1.1.5", "~> 1.1.1", true, false}, {"1.1.5", "~> 1.1.1", "remote", false},
{"1.1.5", "> 1.1.0, < 1.3.0", true, false}, {"1.1.5", "> 1.1.0, < 1.3.0", "remote", false},
{"1.1.5", "~> 1.0.1", true, true}, {"1.1.5", "~> 1.0.1", "remote", true},
// pre-release versions are comparable within their pre-release stage (dev, // pre-release versions are comparable within their pre-release stage (dev,
// alpha, beta), but not comparable to different stages and not comparable // alpha, beta), but not comparable to different stages and not comparable
// to final releases. // to final releases.
{"1.1.0-beta1", "1.1.0-beta1", true, false}, {"1.1.0-beta1", "1.1.0-beta1", "remote", false},
{"1.1.0-beta1", "~> 1.1.0-beta", true, false}, {"1.1.0-beta1", "~> 1.1.0-beta", "remote", false},
{"1.1.0", "~> 1.1.0-beta", true, true}, {"1.1.0", "~> 1.1.0-beta", "remote", true},
{"1.1.0-beta1", "~> 1.1.0-dev", true, true}, {"1.1.0-beta1", "~> 1.1.0-dev", "remote", true},
} }
for _, tc := range testCases { for _, tc := range testCases {
t.Run(fmt.Sprintf("local %s, remote %s", tc.local, tc.remote), func(t *testing.T) { t.Run(fmt.Sprintf("local %s, remote %s", tc.local, tc.remote), func(t *testing.T) {
@ -735,7 +735,7 @@ func TestCloud_VerifyWorkspaceTerraformVersion(t *testing.T) {
b.organization, b.organization,
b.WorkspaceMapping.Name, b.WorkspaceMapping.Name,
tfe.WorkspaceUpdateOptions{ tfe.WorkspaceUpdateOptions{
Operations: tfe.Bool(tc.operations), ExecutionMode: &tc.executionMode,
TerraformVersion: tfe.String(tc.remote), TerraformVersion: tfe.String(tc.remote),
}, },
); err != nil { ); err != nil {

View File

@ -1165,12 +1165,15 @@ func (m *MockWorkspaces) Create(ctx context.Context, organization string, option
} }
if strings.HasSuffix(*options.Name, "no-operations") { if strings.HasSuffix(*options.Name, "no-operations") {
options.Operations = tfe.Bool(false) options.Operations = tfe.Bool(false)
options.ExecutionMode = tfe.String("local")
} else if options.Operations == nil { } else if options.Operations == nil {
options.Operations = tfe.Bool(true) options.Operations = tfe.Bool(true)
options.ExecutionMode = tfe.String("remote")
} }
w := &tfe.Workspace{ w := &tfe.Workspace{
ID: GenerateID("ws-"), ID: GenerateID("ws-"),
Name: *options.Name, Name: *options.Name,
ExecutionMode: *options.ExecutionMode,
Operations: *options.Operations, Operations: *options.Operations,
Permissions: &tfe.WorkspacePermissions{ Permissions: &tfe.WorkspacePermissions{
CanQueueApply: true, CanQueueApply: true,
@ -1276,6 +1279,9 @@ func updateMockWorkspaceAttributes(w *tfe.Workspace, options tfe.WorkspaceUpdate
if options.Operations != nil { if options.Operations != nil {
w.Operations = *options.Operations w.Operations = *options.Operations
} }
if options.ExecutionMode != nil {
w.ExecutionMode = *options.ExecutionMode
}
if options.Name != nil { if options.Name != nil {
w.Name = *options.Name w.Name = *options.Name
} }