core: Plan drift includes move-only changes

Previously, drifted resources included only updates and deletes. To
correctly display the full changes which would result as part of a
refresh-only apply, the drifted resources must also include move-only
changes.
This commit is contained in:
Alisdair McDiarmid 2021-09-16 12:42:00 -04:00
parent 9a7bbdab6f
commit 61b2d8e3fe
1 changed files with 27 additions and 9 deletions

View File

@ -499,6 +499,14 @@ func (c *Context) driftedResources(config *configs.Config, oldState, newState *s
continue
}
addr := rs.Addr.Instance(key)
// Previous run address defaults to the current address, but
// can differ if the resource moved before refreshing
prevRunAddr := addr
if move, ok := moves[addr.UniqueKey()]; ok {
prevRunAddr = move.From
}
newIS := newState.ResourceInstance(addr)
schema, _ := schemas.ResourceTypeConfig(
@ -547,20 +555,30 @@ func (c *Context) driftedResources(config *configs.Config, oldState, newState *s
newVal = cty.NullVal(ty)
}
if oldVal.RawEquals(newVal) {
if oldVal.RawEquals(newVal) && addr.Equal(prevRunAddr) {
// No drift if the two values are semantically equivalent
// and no move has happened
continue
}
// We can only detect updates and deletes as drift.
action := plans.Update
if newVal.IsNull() {
// We can detect three types of changes after refreshing state,
// only two of which are easily understood as "drift":
//
// - Resources which were deleted outside of Terraform;
// - Resources where the object value has changed outside of
// Terraform;
// - Resources which have been moved without other changes.
//
// All of these are returned as drift, to allow refresh-only plans
// to present a full set of changes which will be applied.
var action plans.Action
switch {
case newVal.IsNull():
action = plans.Delete
}
prevRunAddr := addr
if move, ok := moves[addr.UniqueKey()]; ok {
prevRunAddr = move.From
case !oldVal.RawEquals(newVal):
action = plans.Update
default:
action = plans.NoOp
}
change := &plans.ResourceInstanceChange{