From 785d3de0f233221b5c0fd6bdb9960bf24ca32d03 Mon Sep 17 00:00:00 2001 From: James Bardin Date: Thu, 14 Jan 2021 09:24:47 -0500 Subject: [PATCH] detect new outputs and plans as Create actions Rather than using a prior value of null to indicate create, which is imprecise because null is a valid output value, only plan values that didn't exist in the prior state as Create changes. --- terraform/context_plan_test.go | 26 ++++++++++++++++++++++++++ terraform/node_output.go | 10 ++++++++-- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/terraform/context_plan_test.go b/terraform/context_plan_test.go index a9caa5e2a7..129e279a3d 100644 --- a/terraform/context_plan_test.go +++ b/terraform/context_plan_test.go @@ -6670,3 +6670,29 @@ output "planned" { } } } + +func TestContext2Plan_createOutput(t *testing.T) { + // this should always plan a NoOp change for the output + m := testModuleInline(t, map[string]string{ + "main.tf": ` +output "planned" { + value = 1 +} +`, + }) + + ctx := testContext2(t, &ContextOpts{ + Config: m, + State: states.NewState(), + }) + plan, diags := ctx.Plan() + if diags.HasErrors() { + t.Fatal(diags.Err()) + } + + for _, c := range plan.Changes.Outputs { + if c.Action != plans.Create { + t.Fatalf("expected Create change, got %s for %q", c.Action, c.Addr) + } + } +} diff --git a/terraform/node_output.go b/terraform/node_output.go index d13e28b9b2..0a6c1a6156 100644 --- a/terraform/node_output.go +++ b/terraform/node_output.go @@ -418,12 +418,17 @@ func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.C // the diff sensitiveBefore := false before := cty.NullVal(cty.DynamicPseudoType) + + // is this output new to our state? + newOutput := true + mod := state.Module(n.Addr.Module) if n.Addr.Module.IsRoot() && mod != nil { for name, o := range mod.OutputValues { if name == n.Addr.OutputValue.Name { before = o.Value sensitiveBefore = o.Sensitive + newOutput = false break } } @@ -441,10 +446,11 @@ func (n *NodeApplyableOutput) setValue(state *states.SyncState, changes *plans.C switch { case val.IsNull() && before.IsNull(): // This is separate from the NoOp case below, since we can ignore - // sensitivity here if there are only null values. + // sensitivity here when there are only null values. action = plans.NoOp - case before.IsNull(): + case newOutput: + // This output was just added to the configuration action = plans.Create case val.IsWhollyKnown() &&