mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-23 23:50:12 -06:00
cb2e9119aa
Signed-off-by: namgyalangmo <75657887+namgyalangmo@users.noreply.github.com>
269 lines
9.2 KiB
Go
269 lines
9.2 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package plans
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
"github.com/opentofu/opentofu/internal/states"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// ResourceInstanceChangeSrc is a not-yet-decoded ResourceInstanceChange.
|
|
// Pass the associated resource type's schema type to method Decode to
|
|
// obtain a ResourceInstanceChange.
|
|
type ResourceInstanceChangeSrc struct {
|
|
// Addr is the absolute address of the resource instance that the change
|
|
// will apply to.
|
|
Addr addrs.AbsResourceInstance
|
|
|
|
// PrevRunAddr is the absolute address that this resource instance had at
|
|
// the conclusion of a previous run.
|
|
//
|
|
// This will typically be the same as Addr, but can be different if the
|
|
// previous resource instance was subject to a "moved" block that we
|
|
// handled in the process of creating this plan.
|
|
//
|
|
// For the initial creation of a resource instance there isn't really any
|
|
// meaningful "previous run address", but PrevRunAddr will still be set
|
|
// equal to Addr in that case in order to simplify logic elsewhere which
|
|
// aims to detect and react to the movement of instances between addresses.
|
|
PrevRunAddr addrs.AbsResourceInstance
|
|
|
|
// DeposedKey is the identifier for a deposed object associated with the
|
|
// given instance, or states.NotDeposed if this change applies to the
|
|
// current object.
|
|
//
|
|
// A Replace change for a resource with create_before_destroy set will
|
|
// create a new DeposedKey temporarily during replacement. In that case,
|
|
// DeposedKey in the plan is always states.NotDeposed, representing that
|
|
// the current object is being replaced with the deposed.
|
|
DeposedKey states.DeposedKey
|
|
|
|
// Provider is the address of the provider configuration that was used
|
|
// to plan this change, and thus the configuration that must also be
|
|
// used to apply it.
|
|
ProviderAddr addrs.AbsProviderConfig
|
|
|
|
// ChangeSrc is an embedded description of the not-yet-decoded change.
|
|
ChangeSrc
|
|
|
|
// ActionReason is an optional extra indication of why we chose the
|
|
// action recorded in Change.Action for this particular resource instance.
|
|
//
|
|
// This is an approximate mechanism only for the purpose of explaining the
|
|
// plan to end-users in the UI and is not to be used for any
|
|
// decision-making during the apply step; if apply behavior needs to vary
|
|
// depending on the "action reason" then the information for that decision
|
|
// must be recorded more precisely elsewhere for that purpose.
|
|
//
|
|
// See the field of the same name in ResourceInstanceChange for more
|
|
// details.
|
|
ActionReason ResourceInstanceChangeActionReason
|
|
|
|
// RequiredReplace is a set of paths that caused the change action to be
|
|
// Replace rather than Update. Always nil if the change action is not
|
|
// Replace.
|
|
RequiredReplace cty.PathSet
|
|
|
|
// Private allows a provider to stash any extra data that is opaque to
|
|
// OpenTofu that relates to this change. OpenTofu will save this
|
|
// byte-for-byte and return it to the provider in the apply call.
|
|
Private []byte
|
|
}
|
|
|
|
// Decode unmarshals the raw representation of the instance object being
|
|
// changed. Pass the implied type of the corresponding resource type schema
|
|
// for correct operation.
|
|
func (rcs *ResourceInstanceChangeSrc) Decode(ty cty.Type) (*ResourceInstanceChange, error) {
|
|
change, err := rcs.ChangeSrc.Decode(ty)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
prevRunAddr := rcs.PrevRunAddr
|
|
if prevRunAddr.Resource.Resource.Type == "" {
|
|
// Suggests an old caller that hasn't been properly updated to
|
|
// populate this yet.
|
|
prevRunAddr = rcs.Addr
|
|
}
|
|
return &ResourceInstanceChange{
|
|
Addr: rcs.Addr,
|
|
PrevRunAddr: prevRunAddr,
|
|
DeposedKey: rcs.DeposedKey,
|
|
ProviderAddr: rcs.ProviderAddr,
|
|
Change: *change,
|
|
ActionReason: rcs.ActionReason,
|
|
RequiredReplace: rcs.RequiredReplace,
|
|
Private: rcs.Private,
|
|
}, nil
|
|
}
|
|
|
|
// DeepCopy creates a copy of the receiver where any pointers to nested mutable
|
|
// values are also copied, thus ensuring that future mutations of the receiver
|
|
// will not affect the copy.
|
|
//
|
|
// Some types used within a resource change are immutable by convention even
|
|
// though the Go language allows them to be mutated, such as the types from
|
|
// the addrs package. These are _not_ copied by this method, under the
|
|
// assumption that callers will behave themselves.
|
|
func (rcs *ResourceInstanceChangeSrc) DeepCopy() *ResourceInstanceChangeSrc {
|
|
if rcs == nil {
|
|
return nil
|
|
}
|
|
ret := *rcs
|
|
|
|
ret.RequiredReplace = cty.NewPathSet(ret.RequiredReplace.List()...)
|
|
|
|
if len(ret.Private) != 0 {
|
|
private := make([]byte, len(ret.Private))
|
|
copy(private, ret.Private)
|
|
ret.Private = private
|
|
}
|
|
|
|
ret.ChangeSrc.Before = ret.ChangeSrc.Before.Copy()
|
|
ret.ChangeSrc.After = ret.ChangeSrc.After.Copy()
|
|
|
|
return &ret
|
|
}
|
|
|
|
func (rcs *ResourceInstanceChangeSrc) Moved() bool {
|
|
return !rcs.Addr.Equal(rcs.PrevRunAddr)
|
|
}
|
|
|
|
// OutputChangeSrc describes a change to an output value.
|
|
type OutputChangeSrc struct {
|
|
// Addr is the absolute address of the output value that the change
|
|
// will apply to.
|
|
Addr addrs.AbsOutputValue
|
|
|
|
// ChangeSrc is an embedded description of the not-yet-decoded change.
|
|
//
|
|
// For output value changes, the type constraint for the DynamicValue
|
|
// instances is always cty.DynamicPseudoType.
|
|
ChangeSrc
|
|
|
|
// Sensitive, if true, indicates that either the old or new value in the
|
|
// change is sensitive and so a rendered version of the plan in the UI
|
|
// should elide the actual values while still indicating the action of the
|
|
// change.
|
|
Sensitive bool
|
|
}
|
|
|
|
// Decode unmarshals the raw representation of the output value being
|
|
// changed.
|
|
func (ocs *OutputChangeSrc) Decode() (*OutputChange, error) {
|
|
change, err := ocs.ChangeSrc.Decode(cty.DynamicPseudoType)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &OutputChange{
|
|
Addr: ocs.Addr,
|
|
Change: *change,
|
|
Sensitive: ocs.Sensitive,
|
|
}, nil
|
|
}
|
|
|
|
// DeepCopy creates a copy of the receiver where any pointers to nested mutable
|
|
// values are also copied, thus ensuring that future mutations of the receiver
|
|
// will not affect the copy.
|
|
//
|
|
// Some types used within a resource change are immutable by convention even
|
|
// though the Go language allows them to be mutated, such as the types from
|
|
// the addrs package. These are _not_ copied by this method, under the
|
|
// assumption that callers will behave themselves.
|
|
func (ocs *OutputChangeSrc) DeepCopy() *OutputChangeSrc {
|
|
if ocs == nil {
|
|
return nil
|
|
}
|
|
ret := *ocs
|
|
|
|
ret.ChangeSrc.Before = ret.ChangeSrc.Before.Copy()
|
|
ret.ChangeSrc.After = ret.ChangeSrc.After.Copy()
|
|
|
|
return &ret
|
|
}
|
|
|
|
// ImportingSrc is the part of a ChangeSrc that describes the embedded import
|
|
// action.
|
|
//
|
|
// The fields in here are subject to change, so downstream consumers should be
|
|
// prepared for backwards compatibility in case the contents changes.
|
|
type ImportingSrc struct {
|
|
// ID is the original ID of the imported resource.
|
|
ID string
|
|
}
|
|
|
|
// ChangeSrc is a not-yet-decoded Change.
|
|
type ChangeSrc struct {
|
|
// Action defines what kind of change is being made.
|
|
Action Action
|
|
|
|
// Before and After correspond to the fields of the same name in Change,
|
|
// but have not yet been decoded from the serialized value used for
|
|
// storage.
|
|
Before, After DynamicValue
|
|
|
|
// BeforeValMarks and AfterValMarks are stored path+mark combinations
|
|
// that might be discovered when encoding a change. Marks are removed
|
|
// to enable encoding (marked values cannot be marshalled), and so storing
|
|
// the path+mark combinations allow us to re-mark the value later
|
|
// when, for example, displaying the diff to the UI.
|
|
BeforeValMarks, AfterValMarks []cty.PathValueMarks
|
|
|
|
// Importing is present if the resource is being imported as part of this
|
|
// change.
|
|
//
|
|
// Use the simple presence of this field to detect if a ChangeSrc is to be
|
|
// imported, the contents of this structure may be modified going forward.
|
|
Importing *ImportingSrc
|
|
|
|
// GeneratedConfig contains any HCL config generated for this resource
|
|
// during planning, as a string. If GeneratedConfig is populated, Importing
|
|
// should be true. However, not all Importing changes contain generated
|
|
// config.
|
|
GeneratedConfig string
|
|
}
|
|
|
|
// Decode unmarshals the raw representations of the before and after values
|
|
// to produce a Change object. Pass the type constraint that the result must
|
|
// conform to.
|
|
//
|
|
// Where a ChangeSrc is embedded in some other struct, it's generally better
|
|
// to call the corresponding Decode method of that struct rather than working
|
|
// directly with its embedded Change.
|
|
func (cs *ChangeSrc) Decode(ty cty.Type) (*Change, error) {
|
|
var err error
|
|
before := cty.NullVal(ty)
|
|
after := cty.NullVal(ty)
|
|
|
|
if len(cs.Before) > 0 {
|
|
before, err = cs.Before.Decode(ty)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding 'before' value: %w", err)
|
|
}
|
|
}
|
|
if len(cs.After) > 0 {
|
|
after, err = cs.After.Decode(ty)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("error decoding 'after' value: %w", err)
|
|
}
|
|
}
|
|
|
|
var importing *Importing
|
|
if cs.Importing != nil {
|
|
importing = &Importing{ID: cs.Importing.ID}
|
|
}
|
|
|
|
return &Change{
|
|
Action: cs.Action,
|
|
Before: before.MarkWithPaths(cs.BeforeValMarks),
|
|
After: after.MarkWithPaths(cs.AfterValMarks),
|
|
Importing: importing,
|
|
GeneratedConfig: cs.GeneratedConfig,
|
|
}, nil
|
|
}
|