From da153fb3975cac8d154f606e9c5cb577875cf67d Mon Sep 17 00:00:00 2001 From: Theo Chupp Date: Wed, 15 Dec 2021 12:39:13 -0500 Subject: [PATCH] chore: applied the same fix in the 'internal/cloud' package --- .../backend/remote/backend_context_test.go | 2 +- internal/cloud/backend_context.go | 6 +- internal/cloud/backend_context_test.go | 220 ++++++++++++++++++ internal/cloud/testdata/variables/main.tf | 8 + 4 files changed, 233 insertions(+), 3 deletions(-) create mode 100644 internal/cloud/testdata/variables/main.tf diff --git a/internal/backend/remote/backend_context_test.go b/internal/backend/remote/backend_context_test.go index a67bd04c96b5..f3a133421aed 100644 --- a/internal/backend/remote/backend_context_test.go +++ b/internal/backend/remote/backend_context_test.go @@ -351,7 +351,7 @@ func TestRemoteVariablesDoNotOverride(t *testing.T) { }, }, }, - "no-conflicting local variable": { + "no conflicting local variable": { map[string]backend.UnparsedVariableValue{ varName3: testUnparsedVariableValue(varValue3), }, diff --git a/internal/cloud/backend_context.go b/internal/cloud/backend_context.go index 27afadd2ffe1..57eab722cee1 100644 --- a/internal/cloud/backend_context.go +++ b/internal/cloud/backend_context.go @@ -110,8 +110,10 @@ func (b *Cloud) LocalRun(op *backend.Operation) (*backend.LocalRun, statemgr.Ful } for _, v := range tfeVariables.Items { if v.Category == tfe.CategoryTerraform { - op.Variables[v.Key] = &remoteStoredVariableValue{ - definition: v, + if _, ok := op.Variables[v.Key]; !ok { + op.Variables[v.Key] = &remoteStoredVariableValue{ + definition: v, + } } } } diff --git a/internal/cloud/backend_context_test.go b/internal/cloud/backend_context_test.go index e1001ee5292a..635efc88b046 100644 --- a/internal/cloud/backend_context_test.go +++ b/internal/cloud/backend_context_test.go @@ -2,6 +2,7 @@ package cloud import ( "context" + "reflect" "testing" tfe "github.com/hashicorp/go-tfe" @@ -13,6 +14,8 @@ import ( "github.com/hashicorp/terraform/internal/initwd" "github.com/hashicorp/terraform/internal/states/statemgr" "github.com/hashicorp/terraform/internal/terminal" + "github.com/hashicorp/terraform/internal/terraform" + "github.com/hashicorp/terraform/internal/tfdiags" "github.com/zclconf/go-cty/cty" ) @@ -233,3 +236,220 @@ func TestRemoteContextWithVars(t *testing.T) { }) } } + +func TestRemoteVariablesDoNotOverride(t *testing.T) { + catTerraform := tfe.CategoryTerraform + + varName1 := "key1" + varName2 := "key2" + varName3 := "key3" + + varValue1 := "value1" + varValue2 := "value2" + varValue3 := "value3" + + tests := map[string]struct { + localVariables map[string]backend.UnparsedVariableValue + remoteVariables []*tfe.VariableCreateOptions + expectedVariables terraform.InputValues + }{ + "no local variables": { + map[string]backend.UnparsedVariableValue{}, + []*tfe.VariableCreateOptions{ + { + Key: &varName1, + Value: &varValue1, + Category: &catTerraform, + }, + { + Key: &varName2, + Value: &varValue2, + Category: &catTerraform, + }, + { + Key: &varName3, + Value: &varValue3, + Category: &catTerraform, + }, + }, + terraform.InputValues{ + varName1: &terraform.InputValue{ + Value: cty.StringVal(varValue1), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + varName2: &terraform.InputValue{ + Value: cty.StringVal(varValue2), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + varName3: &terraform.InputValue{ + Value: cty.StringVal(varValue3), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + }, + }, + "single conflicting local variable": { + map[string]backend.UnparsedVariableValue{ + varName3: testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.StringVal(varValue3)}, + }, + []*tfe.VariableCreateOptions{ + { + Key: &varName1, + Value: &varValue1, + Category: &catTerraform, + }, { + Key: &varName2, + Value: &varValue2, + Category: &catTerraform, + }, { + Key: &varName3, + Value: &varValue3, + Category: &catTerraform, + }, + }, + terraform.InputValues{ + varName1: &terraform.InputValue{ + Value: cty.StringVal(varValue1), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + varName2: &terraform.InputValue{ + Value: cty.StringVal(varValue2), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + varName3: &terraform.InputValue{ + Value: cty.StringVal(varValue3), + SourceType: terraform.ValueFromNamedFile, + SourceRange: tfdiags.SourceRange{ + Filename: "fake.tfvars", + Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0}, + End: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0}, + }, + }, + }, + }, + "no conflicting local variable": { + map[string]backend.UnparsedVariableValue{ + varName3: testUnparsedVariableValue{source: terraform.ValueFromNamedFile, value: cty.StringVal(varValue3)}, + }, + []*tfe.VariableCreateOptions{ + { + Key: &varName1, + Value: &varValue1, + Category: &catTerraform, + }, { + Key: &varName2, + Value: &varValue2, + Category: &catTerraform, + }, + }, + terraform.InputValues{ + varName1: &terraform.InputValue{ + Value: cty.StringVal(varValue1), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + varName2: &terraform.InputValue{ + Value: cty.StringVal(varValue2), + SourceType: terraform.ValueFromInput, + SourceRange: tfdiags.SourceRange{ + Filename: "", + Start: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + End: tfdiags.SourcePos{Line: 0, Column: 0, Byte: 0}, + }, + }, + varName3: &terraform.InputValue{ + Value: cty.StringVal(varValue3), + SourceType: terraform.ValueFromNamedFile, + SourceRange: tfdiags.SourceRange{ + Filename: "fake.tfvars", + Start: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0}, + End: tfdiags.SourcePos{Line: 1, Column: 1, Byte: 0}, + }, + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + configDir := "./testdata/variables" + + b, bCleanup := testBackendWithName(t) + defer bCleanup() + + _, configLoader, configCleanup := initwd.MustLoadConfigForTests(t, configDir) + defer configCleanup() + + workspaceID, err := b.getRemoteWorkspaceID(context.Background(), testBackendSingleWorkspaceName) + if err != nil { + t.Fatal(err) + } + + streams, _ := terminal.StreamsForTesting(t) + view := views.NewStateLocker(arguments.ViewHuman, views.NewView(streams)) + + op := &backend.Operation{ + ConfigDir: configDir, + ConfigLoader: configLoader, + StateLocker: clistate.NewLocker(0, view), + Workspace: testBackendSingleWorkspaceName, + Variables: test.localVariables, + } + + for _, v := range test.remoteVariables { + b.client.Variables.Create(context.TODO(), workspaceID, *v) + } + + lr, _, diags := b.LocalRun(op) + + if diags.HasErrors() { + t.Fatalf("unexpected error\ngot: %s\nwant: ", diags.Err().Error()) + } + // When Context() succeeds, this should fail w/ "workspace already locked" + stateMgr, _ := b.StateMgr(testBackendSingleWorkspaceName) + if _, err := stateMgr.Lock(statemgr.NewLockInfo()); err == nil { + t.Fatal("unexpected success locking state after Context") + } + + actual := lr.PlanOpts.SetVariables + expected := test.expectedVariables + + for expectedKey := range expected { + actualValue := actual[expectedKey] + expectedValue := expected[expectedKey] + + if !reflect.DeepEqual(*actualValue, *expectedValue) { + t.Fatalf("unexpected variable '%s'\ngot: %v\nwant: %v", expectedKey, actualValue, expectedValue) + } + } + }) + } +} diff --git a/internal/cloud/testdata/variables/main.tf b/internal/cloud/testdata/variables/main.tf new file mode 100644 index 000000000000..9e1a0a40ff6e --- /dev/null +++ b/internal/cloud/testdata/variables/main.tf @@ -0,0 +1,8 @@ +variable "key1" { +} + +variable "key2" { +} + +variable "key3" { +}