package plans import ( "fmt" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/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 // Terraform that relates to this change. Terraform 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 } // 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 } // 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: %s", err) } } if len(cs.After) > 0 { after, err = cs.After.Decode(ty) if err != nil { return nil, fmt.Errorf("error decoding 'after' value: %s", err) } } return &Change{ Action: cs.Action, Before: before.MarkWithPaths(cs.BeforeValMarks), After: after.MarkWithPaths(cs.AfterValMarks), }, nil }