Sort dependencies when encoding `ResourceInstanceObject`

Resource dependencies are by nature an unordered collection, but they're
persisted to state as a JSON array (in random order). This makes a mess for
`terraform apply -refresh-only`, which sees the new random order as a change
that requires the user to approve a state update.

(As an additional problem on top of that, the user interface for refresh-only
runs doesn't expect to see that as a type of change, so it says "no changes!
would you like to update to reflect these detected changes?")

This commit changes `ResourceInstanceObject.Encode()` to sort the in-memory
slice of dependencies (lexically, by address) before passing it on to be
compared and persisted. This appears to fix the observed UI issues with a
minimum of logic changes.
This commit is contained in:
Nick Fagerlund 2021-12-20 21:46:39 -08:00
parent 8b6522169f
commit 9b449bec99
1 changed files with 9 additions and 0 deletions

View File

@ -1,6 +1,8 @@
package states package states
import ( import (
"sort"
"github.com/zclconf/go-cty/cty" "github.com/zclconf/go-cty/cty"
ctyjson "github.com/zclconf/go-cty/cty/json" ctyjson "github.com/zclconf/go-cty/cty/json"
@ -108,6 +110,13 @@ func (o *ResourceInstanceObject) Encode(ty cty.Type, schemaVersion uint64) (*Res
return nil, err return nil, err
} }
// Dependencies are collected and merged in an unordered format (using map
// keys as a set), then later changed to a slice (in random ordering) to be
// stored in state as an array. To avoid pointless thrashing of state in
// refresh-only runs, we can either override comparison of dependency lists
// (more desirable, but tricky for Reasons) or just sort when encoding.
sort.Slice(o.Dependencies, func(i, j int) bool { return o.Dependencies[i].String() < o.Dependencies[j].String() })
return &ResourceInstanceObjectSrc{ return &ResourceInstanceObjectSrc{
SchemaVersion: schemaVersion, SchemaVersion: schemaVersion,
AttrsJSON: src, AttrsJSON: src,