Skip to content

Commit 3207836

Browse files
ephemeral: tests for setting unplanned vars during apply
1 parent fa44937 commit 3207836

File tree

2 files changed

+103
-17
lines changed

2 files changed

+103
-17
lines changed

internal/backend/local/backend_apply.go

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -328,35 +328,30 @@ func (b *Local) opApply(
328328
applyTimeValues[varName] = val
329329
} else {
330330
// If a non-ephemeral variable is set differently between plan and apply, we should emit a diagnostic.
331-
value, ok := plan.VariableValues[varName]
331+
plannedVariableValue, ok := plan.VariableValues[varName]
332332
if !ok {
333-
if v.Value.IsNull() {
334-
continue
335-
} else {
336-
// TODO: Add test for this case
337-
diags = diags.Append(&hcl.Diagnostic{
338-
Severity: hcl.DiagError,
339-
Summary: "Can't set variable when applying a saved plan",
340-
Detail: fmt.Sprintf("The variable %s cannot be set using the -var and -var-file options when applying a saved plan file, because a saved plan includes the variable values that were set when it was created. To declare an ephemeral variable which is not saved in the plan file, use ephemeral = true.", varName),
341-
Subject: rng,
342-
})
343-
}
333+
diags = diags.Append(&hcl.Diagnostic{
334+
Severity: hcl.DiagError,
335+
Summary: "Can't set variable when applying a saved plan",
336+
Detail: fmt.Sprintf("The variable %s cannot be set using the -var and -var-file options when applying a saved plan file, because it is neither ephemeral nor has it been declared during the plan operation. To declare an ephemeral variable which is not saved in the plan file, use ephemeral = true.", varName),
337+
Subject: rng,
338+
})
339+
continue
344340
}
345341

346-
val, err := value.Decode(cty.DynamicPseudoType)
342+
val, err := plannedVariableValue.Decode(cty.DynamicPseudoType)
347343
if err != nil {
348-
// TODO: Reword error message
349344
diags = diags.Append(&hcl.Diagnostic{
350345
Severity: hcl.DiagError,
351-
Summary: "Variable was set with a different type when applying a saved plan",
352-
Detail: fmt.Sprintf("The variable %s was set to a different type of value during plan than during apply. Please either don't supply the value or supply the same value if the variable.", varName),
346+
Summary: "Could not decode variable value from plan",
347+
Detail: fmt.Sprintf("The variable %s could not be decoded from the plan. %s. This is a bug in Terraform, please report it.", varName, err),
353348
Subject: rng,
354349
})
355350
} else {
356351
if v.Value.Equals(val) == cty.False {
357352
diags = diags.Append(&hcl.Diagnostic{
358353
Severity: hcl.DiagError,
359-
Summary: "Can't set variable when applying a saved plan",
354+
Summary: "Can't change variable when applying a saved plan",
360355
Detail: fmt.Sprintf("The variable %s cannot be set using the -var and -var-file options when applying a saved plan file, because a saved plan includes the variable values that were set when it was created. The saved plan specifies %s as the value whereas during apply the value %s was %s. To declare an ephemeral variable which is not saved in the plan file, use ephemeral = true.", varName, viewsjson.CompactValueStr(v.Value), viewsjson.CompactValueStr(val), v.SourceType.DiagnosticLabel()),
361356
Subject: rng,
362357
})

internal/command/apply_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,6 +860,7 @@ func TestApply_planWithVarFile(t *testing.T) {
860860
t.Fatalf("err: %s", err)
861861
}
862862

863+
// The value of foo is the same as in the var file
863864
planPath := applyFixturePlanFileWithVariableValue(t, "bar")
864865
statePath := testTempFile(t)
865866

@@ -901,6 +902,96 @@ func TestApply_planWithVarFile(t *testing.T) {
901902
}
902903
}
903904

905+
func TestApply_planWithVarFilePreviouslyUnset(t *testing.T) {
906+
varFileDir := testTempDir(t)
907+
varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
908+
if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
909+
t.Fatalf("err: %s", err)
910+
}
911+
912+
// The value of foo is not set
913+
planPath := applyFixturePlanFile(t)
914+
statePath := testTempFile(t)
915+
916+
cwd, err := os.Getwd()
917+
if err != nil {
918+
t.Fatalf("err: %s", err)
919+
}
920+
if err := os.Chdir(varFileDir); err != nil {
921+
t.Fatalf("err: %s", err)
922+
}
923+
defer os.Chdir(cwd)
924+
925+
p := applyFixtureProvider()
926+
view, done := testView(t)
927+
c := &ApplyCommand{
928+
Meta: Meta{
929+
testingOverrides: metaOverridesForProvider(p),
930+
View: view,
931+
},
932+
}
933+
934+
args := []string{
935+
"-state-out", statePath,
936+
planPath,
937+
}
938+
code := c.Run(args)
939+
output := done(t)
940+
if code == 0 {
941+
t.Fatalf("expected to fail, but succeeded. \n\n%s", output.All())
942+
}
943+
944+
expectedTitle := "Can't set variable when applying a saved plan"
945+
if !strings.Contains(output.Stderr(), expectedTitle) {
946+
t.Fatalf("Expected stderr to contain %q, got %q", expectedTitle, output.Stderr())
947+
}
948+
}
949+
950+
func TestApply_planWithVarFileChangingVariableValue(t *testing.T) {
951+
varFileDir := testTempDir(t)
952+
varFilePath := filepath.Join(varFileDir, "terraform.tfvars")
953+
if err := ioutil.WriteFile(varFilePath, []byte(applyVarFile), 0644); err != nil {
954+
t.Fatalf("err: %s", err)
955+
}
956+
957+
// The value of foo is differnet from the var file
958+
planPath := applyFixturePlanFileWithVariableValue(t, "lorem ipsum")
959+
statePath := testTempFile(t)
960+
961+
cwd, err := os.Getwd()
962+
if err != nil {
963+
t.Fatalf("err: %s", err)
964+
}
965+
if err := os.Chdir(varFileDir); err != nil {
966+
t.Fatalf("err: %s", err)
967+
}
968+
defer os.Chdir(cwd)
969+
970+
p := applyFixtureProvider()
971+
view, done := testView(t)
972+
c := &ApplyCommand{
973+
Meta: Meta{
974+
testingOverrides: metaOverridesForProvider(p),
975+
View: view,
976+
},
977+
}
978+
979+
args := []string{
980+
"-state-out", statePath,
981+
planPath,
982+
}
983+
code := c.Run(args)
984+
output := done(t)
985+
if code == 0 {
986+
t.Fatalf("expected to fail, but succeeded. \n\n%s", output.All())
987+
}
988+
989+
expectedTitle := "Can't change variable when applying a saved plan"
990+
if !strings.Contains(output.Stderr(), expectedTitle) {
991+
t.Fatalf("Expected stderr to contain %q, got %q", expectedTitle, output.Stderr())
992+
}
993+
}
994+
904995
func TestApply_planVars(t *testing.T) {
905996
// This test ensures that it isn't allowed to set non-ephemeral input
906997
// variables when applying from a saved plan file, since in that case the

0 commit comments

Comments
 (0)