backend/remote: Fix for "latest" workspace version
Terraform Cloud/Enterprise support a pseudo-version of "latest" for the configured workspace Terraform version. If this is chosen, we abandon the attempt to verify the versions are compatible, as the meaning of "latest" cannot be predicted. This affects both the StateMgr check (used for commands which execute remotely) and the full version check (for local commands).
This commit is contained in:
parent
93c36e67b1
commit
6e0d8cde91
|
@ -641,7 +641,10 @@ func (b *Remote) StateMgr(name string) (statemgr.Full, error) {
|
||||||
// accidentally upgrade state with a new code path, and the version check
|
// accidentally upgrade state with a new code path, and the version check
|
||||||
// logic is coarser and simpler.
|
// logic is coarser and simpler.
|
||||||
if !b.ignoreVersionConflict {
|
if !b.ignoreVersionConflict {
|
||||||
if workspace.TerraformVersion != tfversion.String() {
|
wsv := workspace.TerraformVersion
|
||||||
|
// Explicitly ignore the pseudo-version "latest" here, as it will cause
|
||||||
|
// plan and apply to always fail.
|
||||||
|
if wsv != tfversion.String() && wsv != "latest" {
|
||||||
return nil, fmt.Errorf("Remote workspace Terraform version %q does not match local Terraform version %q", workspace.TerraformVersion, tfversion.String())
|
return nil, fmt.Errorf("Remote workspace Terraform version %q does not match local Terraform version %q", workspace.TerraformVersion, tfversion.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -890,6 +893,13 @@ func (b *Remote) VerifyWorkspaceTerraformVersion(workspaceName string) tfdiags.D
|
||||||
return diags
|
return diags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the workspace has the pseudo-version "latest", all bets are off. We
|
||||||
|
// cannot reasonably determine what the intended Terraform version is, so
|
||||||
|
// we'll skip version verification.
|
||||||
|
if workspace.TerraformVersion == "latest" {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
remoteVersion, err := version.NewSemver(workspace.TerraformVersion)
|
remoteVersion, err := version.NewSemver(workspace.TerraformVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
|
|
|
@ -515,6 +515,45 @@ func TestRemote_StateMgr_versionCheck(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRemote_StateMgr_versionCheckLatest(t *testing.T) {
|
||||||
|
b, bCleanup := testBackendDefault(t)
|
||||||
|
defer bCleanup()
|
||||||
|
|
||||||
|
v0140 := version.Must(version.NewSemver("0.14.0"))
|
||||||
|
|
||||||
|
// Save original local version state and restore afterwards
|
||||||
|
p := tfversion.Prerelease
|
||||||
|
v := tfversion.Version
|
||||||
|
s := tfversion.SemVer
|
||||||
|
defer func() {
|
||||||
|
tfversion.Prerelease = p
|
||||||
|
tfversion.Version = v
|
||||||
|
tfversion.SemVer = s
|
||||||
|
}()
|
||||||
|
|
||||||
|
// For this test, the local Terraform version is set to 0.14.0
|
||||||
|
tfversion.Prerelease = ""
|
||||||
|
tfversion.Version = v0140.String()
|
||||||
|
tfversion.SemVer = v0140
|
||||||
|
|
||||||
|
// Update the remote workspace to the pseudo-version "latest"
|
||||||
|
if _, err := b.client.Workspaces.Update(
|
||||||
|
context.Background(),
|
||||||
|
b.organization,
|
||||||
|
b.workspace,
|
||||||
|
tfe.WorkspaceUpdateOptions{
|
||||||
|
TerraformVersion: tfe.String("latest"),
|
||||||
|
},
|
||||||
|
); err != nil {
|
||||||
|
t.Fatalf("error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// This should succeed despite not being a string match
|
||||||
|
if _, err := b.StateMgr(backend.DefaultStateName); err != nil {
|
||||||
|
t.Fatalf("expected no error, got %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRemote_VerifyWorkspaceTerraformVersion(t *testing.T) {
|
func TestRemote_VerifyWorkspaceTerraformVersion(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
local string
|
local string
|
||||||
|
@ -528,6 +567,7 @@ func TestRemote_VerifyWorkspaceTerraformVersion(t *testing.T) {
|
||||||
{"0.14.0", "1.1.0", true},
|
{"0.14.0", "1.1.0", true},
|
||||||
{"1.2.0", "1.2.99", false},
|
{"1.2.0", "1.2.99", false},
|
||||||
{"1.2.0", "1.3.0", true},
|
{"1.2.0", "1.3.0", true},
|
||||||
|
{"0.15.0", "latest", false},
|
||||||
}
|
}
|
||||||
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) {
|
||||||
|
@ -535,7 +575,6 @@ func TestRemote_VerifyWorkspaceTerraformVersion(t *testing.T) {
|
||||||
defer bCleanup()
|
defer bCleanup()
|
||||||
|
|
||||||
local := version.Must(version.NewSemver(tc.local))
|
local := version.Must(version.NewSemver(tc.local))
|
||||||
remote := version.Must(version.NewSemver(tc.remote))
|
|
||||||
|
|
||||||
// Save original local version state and restore afterwards
|
// Save original local version state and restore afterwards
|
||||||
p := tfversion.Prerelease
|
p := tfversion.Prerelease
|
||||||
|
@ -559,7 +598,7 @@ func TestRemote_VerifyWorkspaceTerraformVersion(t *testing.T) {
|
||||||
b.organization,
|
b.organization,
|
||||||
b.workspace,
|
b.workspace,
|
||||||
tfe.WorkspaceUpdateOptions{
|
tfe.WorkspaceUpdateOptions{
|
||||||
TerraformVersion: tfe.String(remote.String()),
|
TerraformVersion: tfe.String(tc.remote),
|
||||||
},
|
},
|
||||||
); err != nil {
|
); err != nil {
|
||||||
t.Fatalf("error: %v", err)
|
t.Fatalf("error: %v", err)
|
||||||
|
|
Loading…
Reference in New Issue