From e2a6397a06115a9ae3f3c17a48f58e289a8e1157 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 13 Jan 2023 10:49:25 -0500 Subject: [PATCH] typed null input should be reflected in output The configuration may be supplying a typed null value to the terraform_data.input attribute, which must be reflected in the output to have a valid plan. --- .../builtin/providers/terraform/resource_data.go | 8 +++++--- .../providers/terraform/resource_data_test.go | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/internal/builtin/providers/terraform/resource_data.go b/internal/builtin/providers/terraform/resource_data.go index 23ae91fc4a..91a2a68794 100644 --- a/internal/builtin/providers/terraform/resource_data.go +++ b/internal/builtin/providers/terraform/resource_data.go @@ -74,8 +74,10 @@ func planDataStoreResourceChange(req providers.PlanResourceChangeRequest) (resp // Set the id value to unknown. planned["id"] = cty.UnknownVal(cty.String) - // Only compute a new output if input has a non-null value. - if !input.IsNull() { + // Output type must always match the input, even when it's null. + if input.IsNull() { + planned["output"] = cty.NullVal(input.Type()) + } else { planned["output"] = cty.UnknownVal(input.Type()) } @@ -90,7 +92,7 @@ func planDataStoreResourceChange(req providers.PlanResourceChangeRequest) (resp // We need to check the input for the replacement instance to compute a // new output. if input.IsNull() { - planned["output"] = cty.NullVal(cty.DynamicPseudoType) + planned["output"] = cty.NullVal(input.Type()) } else { planned["output"] = cty.UnknownVal(input.Type()) } diff --git a/internal/builtin/providers/terraform/resource_data_test.go b/internal/builtin/providers/terraform/resource_data_test.go index 6b1c3a30e1..33deb0ddf1 100644 --- a/internal/builtin/providers/terraform/resource_data_test.go +++ b/internal/builtin/providers/terraform/resource_data_test.go @@ -125,6 +125,22 @@ func TestManagedDataPlan(t *testing.T) { }), }, + "create-typed-null-input": { + prior: cty.NullVal(ty), + proposed: cty.ObjectVal(map[string]cty.Value{ + "input": cty.NullVal(cty.String), + "output": cty.NullVal(cty.DynamicPseudoType), + "triggers_replace": cty.NullVal(cty.DynamicPseudoType), + "id": cty.NullVal(cty.String), + }), + planned: cty.ObjectVal(map[string]cty.Value{ + "input": cty.NullVal(cty.String), + "output": cty.NullVal(cty.String), + "triggers_replace": cty.NullVal(cty.DynamicPseudoType), + "id": cty.UnknownVal(cty.String), + }), + }, + "create-output": { prior: cty.NullVal(ty), proposed: cty.ObjectVal(map[string]cty.Value{