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.
This commit is contained in:
Alisdair McDiarmid 2020-12-03 12:54:09 -05:00
parent 2ce71ab43c
commit 50f4d79867
2 changed files with 21 additions and 2 deletions

View File

@ -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"),

View File

@ -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
}