From d7cb69e96d6e9a8d82fa473d17c6a25dc1d697f3 Mon Sep 17 00:00:00 2001 From: Liam Cervante Date: Mon, 17 Oct 2022 10:30:57 +0200 Subject: [PATCH] Convert variable types before applying defaults --- internal/terraform/context_apply_test.go | 2 +- internal/terraform/eval_variable.go | 16 +++--- internal/terraform/eval_variable_test.go | 62 ++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 9 deletions(-) diff --git a/internal/terraform/context_apply_test.go b/internal/terraform/context_apply_test.go index 4f16453310ee..150141df5fe4 100644 --- a/internal/terraform/context_apply_test.go +++ b/internal/terraform/context_apply_test.go @@ -12027,7 +12027,7 @@ output "out" { Mode: plans.NormalMode, SetVariables: InputValues{ "in": &InputValue{ - Value: cty.MapVal(map[string]cty.Value{ + Value: cty.ObjectVal(map[string]cty.Value{ "required": cty.StringVal("boop"), }), SourceType: ValueFromCaller, diff --git a/internal/terraform/eval_variable.go b/internal/terraform/eval_variable.go index 167840e7c110..c355204b1046 100644 --- a/internal/terraform/eval_variable.go +++ b/internal/terraform/eval_variable.go @@ -90,14 +90,6 @@ func prepareFinalInputVariableValue(addr addrs.AbsInputVariableInstance, raw *In given = defaultVal // must be set, because we checked above that the variable isn't required } - // Apply defaults from the variable's type constraint to the given value, - // unless the given value is null. We do not apply defaults to top-level - // null values, as doing so could prevent assigning null to a nullable - // variable. - if cfg.TypeDefaults != nil && !given.IsNull() { - given = cfg.TypeDefaults.Apply(given) - } - val, err := convert.Convert(given, convertTy) if err != nil { log.Printf("[ERROR] prepareFinalInputVariableValue: %s has unsuitable type\n got: %s\n want: %s", addr, given.Type(), convertTy) @@ -140,6 +132,14 @@ func prepareFinalInputVariableValue(addr addrs.AbsInputVariableInstance, raw *In return cty.UnknownVal(cfg.Type), diags } + // Apply defaults from the variable's type constraint to the given value, + // unless the given value is null. We do not apply defaults to top-level + // null values, as doing so could prevent assigning null to a nullable + // variable. + if cfg.TypeDefaults != nil && !val.IsNull() { + val = cfg.TypeDefaults.Apply(val) + } + // By the time we get here, we know: // - val matches the variable's type constraint // - val is definitely not cty.NilVal, but might be a null value if the given was already null. diff --git a/internal/terraform/eval_variable_test.go b/internal/terraform/eval_variable_test.go index cb6c1bb2b816..7974203f2d07 100644 --- a/internal/terraform/eval_variable_test.go +++ b/internal/terraform/eval_variable_test.go @@ -68,6 +68,15 @@ func TestPrepareFinalInputVariableValue(t *testing.T) { nullable = false type = string } + variable "complex_type_with_nested_default_optional" { + type = set(object({ + name = string + schedules = set(object({ + name = string + cold_storage_after = optional(number, 10) + })) + })) + } ` cfg := testModuleInline(t, map[string]string{ "main.tf": cfgSrc, @@ -399,6 +408,59 @@ func TestPrepareFinalInputVariableValue(t *testing.T) { ``, }, + // complex types + + { + "complex_type_with_nested_default_optional", + cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("test1"), + "schedules": cty.SetVal([]cty.Value{ + cty.MapVal(map[string]cty.Value{ + "name": cty.StringVal("daily"), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("test2"), + "schedules": cty.SetVal([]cty.Value{ + cty.MapVal(map[string]cty.Value{ + "name": cty.StringVal("daily"), + }), + cty.MapVal(map[string]cty.Value{ + "name": cty.StringVal("weekly"), + "cold_storage_after": cty.StringVal("0"), + }), + }), + }), + }), + cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("test1"), + "schedules": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("daily"), + "cold_storage_after": cty.NumberIntVal(10), + }), + }), + }), + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("test2"), + "schedules": cty.SetVal([]cty.Value{ + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("daily"), + "cold_storage_after": cty.NumberIntVal(10), + }), + cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("weekly"), + "cold_storage_after": cty.NumberIntVal(0), + }), + }), + }), + }), + ``, + }, + // sensitive { "constrained_string_sensitive_required",