From 50f4d79867244d3bfe00f973dc3b490ebe547f65 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 3 Dec 2020 12:54:09 -0500 Subject: [PATCH] terraform: Write state if sensitivity changes When applying, we return early if only sensitivity changed between the before and after values of the changeset. This avoids unnecessarily invoking the provider. Previously, we did not write the new value for a resource to the state when this happened. The result was a permanent diff for resource updates which only change sensitivity, as the apply step is skipped and the state is unchanged. This commit adds a state write to this shortcut return path, and fixes a test for this exact case which was accidentally relying on a value diff caused by an incorrect manual state value. --- terraform/context_apply_test.go | 5 ++++- terraform/eval_apply.go | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index a4acd0085..f332aeec7 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -12049,7 +12049,7 @@ resource "test_resource" "foo" { }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), &states.ResourceInstanceObjectSrc{ Status: states.ObjectReady, - AttrsJSON: []byte(`{"id":"foo", "value":"hello"}`), + AttrsJSON: []byte(`{"id":"foo", "value":"hello", "network_interface":[]}`), // No AttrSensitivePaths present }, addrs.AbsProviderConfig{ @@ -12070,6 +12070,9 @@ resource "test_resource" "foo" { fooState := state.ResourceInstance(addr) + if len(fooState.Current.AttrSensitivePaths) != 1 { + t.Fatalf("wrong number of sensitive paths, expected 1, got, %v", len(fooState.Current.AttrSensitivePaths)) + } got := fooState.Current.AttrSensitivePaths[0] want := cty.PathValueMarks{ Path: cty.GetAttrPath("value"), diff --git a/terraform/eval_apply.go b/terraform/eval_apply.go index a62fcaa8b..7d14ad13a 100644 --- a/terraform/eval_apply.go +++ b/terraform/eval_apply.go @@ -118,10 +118,26 @@ func (n *EvalApply) Eval(ctx EvalContext) tfdiags.Diagnostics { // If we have an Update action, our before and after values are equal, // and only differ on their sensitivity, the newVal is the after val - // and we should not communicate with the provider or perform further action. + // and we should not communicate with the provider. We do need to update + // the state with this new value, to ensure the sensitivity change is + // persisted. eqV := unmarkedBefore.Equals(unmarkedAfter) eq := eqV.IsKnown() && eqV.True() if change.Action == plans.Update && eq && !reflect.DeepEqual(beforePaths, afterPaths) { + // Copy the previous state, changing only the value + newState := &states.ResourceInstanceObject{ + CreateBeforeDestroy: state.CreateBeforeDestroy, + Dependencies: state.Dependencies, + Private: state.Private, + Status: state.Status, + Value: change.After, + } + + // Write the final state + if n.Output != nil { + *n.Output = newState + } + return diags }