mirror of
https://github.com/hashicorp/terraform.git
synced 2026-02-03 20:50:59 -05:00
the use of reflect.DeepEqual fails for states, because they contain value which cannot be directly compared for equality. The Equal method is not used much, except to aid in backend migration, so the failure there was rarely noticed. The failure of ManagedResourcesEqual would show up in the CLI after Terraform reported there were no changes, by exiting with a non-zero code because the resource states incorrectly reported as being changed.
112 lines
2.7 KiB
Go
112 lines
2.7 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package states
|
|
|
|
// Equal returns true if the receiver is functionally equivalent to other,
|
|
// including any ephemeral portions of the state that would not be included
|
|
// if the state were saved to files.
|
|
//
|
|
// To test only the persistent portions of two states for equality, instead
|
|
// use statefile.StatesMarshalEqual.
|
|
func (s *State) Equal(other *State) bool {
|
|
if s == other {
|
|
return true
|
|
}
|
|
if s == nil || other == nil {
|
|
return false
|
|
}
|
|
|
|
if !s.RootOutputValuesEqual(other) {
|
|
return false
|
|
}
|
|
|
|
if !s.CheckResults.Equal(other.CheckResults) {
|
|
return false
|
|
}
|
|
|
|
return s.ManagedResourcesEqual(other)
|
|
}
|
|
|
|
// ManagedResourcesEqual returns true if all of the managed resources tracked
|
|
// in the receiver are functionally equivalent to the same tracked in the
|
|
// other given state.
|
|
//
|
|
// This is a more constrained version of Equal that disregards other
|
|
// differences, including but not limited to changes to data resources and
|
|
// changes to output values.
|
|
func (s *State) ManagedResourcesEqual(other *State) bool {
|
|
// First, some accommodations for situations where one of the objects is
|
|
// nil, for robustness since we sometimes use a nil state to represent
|
|
// a prior state being entirely absent.
|
|
if s == other {
|
|
// covers both states being nil, or both states being the exact same
|
|
// object.
|
|
return true
|
|
}
|
|
|
|
// Managed resources are technically equal if one state is nil while the
|
|
// other has no resources.
|
|
if s == nil {
|
|
return !other.HasManagedResourceInstanceObjects()
|
|
}
|
|
if other == nil {
|
|
return !s.HasManagedResourceInstanceObjects()
|
|
}
|
|
|
|
// If we get here then both states are non-nil.
|
|
|
|
if len(s.Modules) != len(other.Modules) {
|
|
return false
|
|
}
|
|
|
|
for key, sMod := range s.Modules {
|
|
otherMod, ok := other.Modules[key]
|
|
if !ok {
|
|
return false
|
|
}
|
|
// Something else is wrong if the addresses don't match, but they are
|
|
// definitely not equal
|
|
if !sMod.Addr.Equal(otherMod.Addr) {
|
|
return false
|
|
}
|
|
|
|
if len(sMod.Resources) != len(otherMod.Resources) {
|
|
return false
|
|
}
|
|
|
|
for key, sRes := range sMod.Resources {
|
|
otherRes, ok := otherMod.Resources[key]
|
|
if !ok {
|
|
return false
|
|
}
|
|
if !sRes.Equal(otherRes) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// RootOutputValuesEqual returns true if the root output values tracked in the
|
|
// receiver are functionally equivalent to the same tracked in the other given
|
|
// state.
|
|
func (s *State) RootOutputValuesEqual(s2 *State) bool {
|
|
if s == nil && s2 == nil {
|
|
return true
|
|
}
|
|
|
|
if len(s.RootOutputValues) != len(s2.RootOutputValues) {
|
|
return false
|
|
}
|
|
|
|
for k, v1 := range s2.RootOutputValues {
|
|
v2, ok := s2.RootOutputValues[k]
|
|
if !ok || !v1.Equal(v2) {
|
|
return false
|
|
}
|
|
}
|
|
|
|
return true
|
|
}
|