cloud.StateMgr(): Set terraform version AFTER creating workspace

Previously, if the remote TFC/TFE instance doesn't happen to have a tool_version
record whose name exactly matches the value of `tfversion.String()`, Terraform
would be completely blocked from using the `terraform workspace new` command
(when configured with the tags strategy) — the API would give a 422 to the
whole create request.

This commit changes the StateMgr() function to do the work in two passes; first
create the workspace (which should work fine regardless), THEN update the
Terraform version and print a warning to the terminal if it fails (which 99% of
the time is a benign failure with little impact on your future CLI usage).
This commit is contained in:
Nick Fagerlund 2021-10-22 14:50:16 -07:00 committed by Chris Arcand
parent aace0015c2
commit c99f5972de
1 changed files with 24 additions and 2 deletions

View File

@ -506,6 +506,7 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) {
}
if err == tfe.ErrResourceNotFound {
// Create a workspace
options := tfe.WorkspaceCreateOptions{
Name: tfe.String(name),
}
@ -517,12 +518,27 @@ func (b *Cloud) StateMgr(name string) (statemgr.Full, error) {
}
options.Tags = tags
options.TerraformVersion = tfe.String(tfversion.String())
workspace, err = b.client.Workspaces.Create(context.Background(), b.organization, options)
if err != nil {
return nil, fmt.Errorf("Error creating workspace %s: %v", name, err)
}
// Attempt to set the new workspace to use this version of Terraform. This
// can fail if there's no enabled tool_version whose name matches our
// version string, but that's expected sometimes -- just warn and continue.
versionOptions := tfe.WorkspaceUpdateOptions{
TerraformVersion: tfe.String(tfversion.String()),
}
_, err := b.client.Workspaces.UpdateByID(context.Background(), workspace.ID, versionOptions)
if err != nil {
// TODO: Ideally we could rely on the client to tell us what the actual
// problem was, but we currently can't get enough context from the error
// object to do a nicely formatted message, so we're just assuming the
// issue was that the version wasn't available since that's probably what
// happened.
versionUnavailable := fmt.Sprintf(unavailableTerraformVersion, tfversion.String(), workspace.TerraformVersion)
b.CLI.Output(b.Colorize().Color(versionUnavailable))
}
}
// This is a fallback error check. Most code paths should use other
@ -948,6 +964,12 @@ const operationNotCanceled = `
const refreshToApplyRefresh = `[bold][yellow]Proceeding with 'terraform apply -refresh-only -auto-approve'.[reset]`
const unavailableTerraformVersion = `
[reset][yellow]The local Terraform version (%s) is not available in Terraform Cloud, or your
organization does not have access to it. The new workspace will use %s. You can
change this later in the workspace settings.[reset]
`
var (
workspaceConfigurationHelp = fmt.Sprintf(
`The 'workspaces' block configures how Terraform CLI maps its workspaces for this single