4 "github.com/hashicorp/terraform/addrs"
5 "github.com/hashicorp/terraform/states"
6 "github.com/zclconf/go-cty/cty"
9 // Changes describes various actions that Terraform will attempt to take if
10 // the corresponding plan is applied.
12 // A Changes object can be rendered into a visual diff (by the caller, using
13 // code in another package) for display to the user.
15 // Resources tracks planned changes to resource instance objects.
16 Resources []*ResourceInstanceChangeSrc
18 // Outputs tracks planned changes output values.
20 // Note that although an in-memory plan contains planned changes for
21 // outputs throughout the configuration, a plan serialized
22 // to disk retains only the root outputs because they are
23 // externally-visible, while other outputs are implementation details and
24 // can be easily re-calculated during the apply phase. Therefore only root
25 // module outputs will survive a round-trip through a plan file.
26 Outputs []*OutputChangeSrc
29 // NewChanges returns a valid Changes object that describes no changes.
30 func NewChanges() *Changes {
34 func (c *Changes) Empty() bool {
35 for _, res := range c.Resources {
36 if res.Action != NoOp {
43 // ResourceInstance returns the planned change for the current object of the
44 // resource instance of the given address, if any. Returns nil if no change is
46 func (c *Changes) ResourceInstance(addr addrs.AbsResourceInstance) *ResourceInstanceChangeSrc {
47 addrStr := addr.String()
48 for _, rc := range c.Resources {
49 if rc.Addr.String() == addrStr && rc.DeposedKey == states.NotDeposed {
57 // ResourceInstanceDeposed returns the plan change of a deposed object of
58 // the resource instance of the given address, if any. Returns nil if no change
60 func (c *Changes) ResourceInstanceDeposed(addr addrs.AbsResourceInstance, key states.DeposedKey) *ResourceInstanceChangeSrc {
61 addrStr := addr.String()
62 for _, rc := range c.Resources {
63 if rc.Addr.String() == addrStr && rc.DeposedKey == key {
71 // OutputValue returns the planned change for the output value with the
72 // given address, if any. Returns nil if no change is planned.
73 func (c *Changes) OutputValue(addr addrs.AbsOutputValue) *OutputChangeSrc {
74 addrStr := addr.String()
75 for _, oc := range c.Outputs {
76 if oc.Addr.String() == addrStr {
84 // SyncWrapper returns a wrapper object around the receiver that can be used
85 // to make certain changes to the receiver in a concurrency-safe way, as long
86 // as all callers share the same wrapper object.
87 func (c *Changes) SyncWrapper() *ChangesSync {
93 // ResourceInstanceChange describes a change to a particular resource instance
95 type ResourceInstanceChange struct {
96 // Addr is the absolute address of the resource instance that the change
98 Addr addrs.AbsResourceInstance
100 // DeposedKey is the identifier for a deposed object associated with the
101 // given instance, or states.NotDeposed if this change applies to the
104 // A Replace change for a resource with create_before_destroy set will
105 // create a new DeposedKey temporarily during replacement. In that case,
106 // DeposedKey in the plan is always states.NotDeposed, representing that
107 // the current object is being replaced with the deposed.
108 DeposedKey states.DeposedKey
110 // Provider is the address of the provider configuration that was used
111 // to plan this change, and thus the configuration that must also be
113 ProviderAddr addrs.AbsProviderConfig
115 // Change is an embedded description of the change.
118 // RequiredReplace is a set of paths that caused the change action to be
119 // Replace rather than Update. Always nil if the change action is not
122 // This is retained only for UI-plan-rendering purposes and so it does not
123 // currently survive a round-trip through a saved plan file.
124 RequiredReplace cty.PathSet
126 // Private allows a provider to stash any extra data that is opaque to
127 // Terraform that relates to this change. Terraform will save this
128 // byte-for-byte and return it to the provider in the apply call.
132 // Encode produces a variant of the reciever that has its change values
133 // serialized so it can be written to a plan file. Pass the implied type of the
134 // corresponding resource type schema for correct operation.
135 func (rc *ResourceInstanceChange) Encode(ty cty.Type) (*ResourceInstanceChangeSrc, error) {
136 cs, err := rc.Change.Encode(ty)
140 return &ResourceInstanceChangeSrc{
142 DeposedKey: rc.DeposedKey,
143 ProviderAddr: rc.ProviderAddr,
145 RequiredReplace: rc.RequiredReplace,
150 // Simplify will, where possible, produce a change with a simpler action than
151 // the receiever given a flag indicating whether the caller is dealing with
152 // a normal apply or a destroy. This flag deals with the fact that Terraform
153 // Core uses a specialized graph node type for destroying; only that
154 // specialized node should set "destroying" to true.
156 // The following table shows the simplification behavior:
158 // Action Destroying? New Action
159 // --------+-------------+-----------
162 // Replace true Delete
163 // Replace false Create
165 // For any combination not in the above table, the Simplify just returns the
167 func (rc *ResourceInstanceChange) Simplify(destroying bool) *ResourceInstanceChange {
171 // We'll fall out and just return rc verbatim, then.
172 case CreateThenDelete, DeleteThenCreate:
173 return &ResourceInstanceChange{
175 DeposedKey: rc.DeposedKey,
177 ProviderAddr: rc.ProviderAddr,
181 After: cty.NullVal(rc.Before.Type()),
185 return &ResourceInstanceChange{
187 DeposedKey: rc.DeposedKey,
189 ProviderAddr: rc.ProviderAddr,
200 return &ResourceInstanceChange{
202 DeposedKey: rc.DeposedKey,
204 ProviderAddr: rc.ProviderAddr,
211 case CreateThenDelete, DeleteThenCreate:
212 return &ResourceInstanceChange{
214 DeposedKey: rc.DeposedKey,
216 ProviderAddr: rc.ProviderAddr,
219 Before: cty.NullVal(rc.After.Type()),
226 // If we fall out here then our change is already simple enough.
230 // OutputChange describes a change to an output value.
231 type OutputChange struct {
232 // Addr is the absolute address of the output value that the change
234 Addr addrs.AbsOutputValue
236 // Change is an embedded description of the change.
238 // For output value changes, the type constraint for the DynamicValue
239 // instances is always cty.DynamicPseudoType.
242 // Sensitive, if true, indicates that either the old or new value in the
243 // change is sensitive and so a rendered version of the plan in the UI
244 // should elide the actual values while still indicating the action of the
249 // Encode produces a variant of the reciever that has its change values
250 // serialized so it can be written to a plan file.
251 func (oc *OutputChange) Encode() (*OutputChangeSrc, error) {
252 cs, err := oc.Change.Encode(cty.DynamicPseudoType)
256 return &OutputChangeSrc{
259 Sensitive: oc.Sensitive,
263 // Change describes a single change with a given action.
265 // Action defines what kind of change is being made.
268 // Interpretation of Before and After depend on Action:
270 // NoOp Before and After are the same, unchanged value
271 // Create Before is nil, and After is the expected value after create.
272 // Read Before is any prior value (nil if no prior), and After is the
273 // value that was or will be read.
274 // Update Before is the value prior to update, and After is the expected
275 // value after update.
276 // Replace As with Update.
277 // Delete Before is the value prior to delete, and After is always nil.
279 // Unknown values may appear anywhere within the Before and After values,
280 // either as the values themselves or as nested elements within known
281 // collections/structures.
282 Before, After cty.Value
285 // Encode produces a variant of the reciever that has its change values
286 // serialized so it can be written to a plan file. Pass the type constraint
287 // that the values are expected to conform to; to properly decode the values
288 // later an identical type constraint must be provided at that time.
290 // Where a Change is embedded in some other struct, it's generally better
291 // to call the corresponding Encode method of that struct rather than working
292 // directly with its embedded Change.
293 func (c *Change) Encode(ty cty.Type) (*ChangeSrc, error) {
294 beforeDV, err := NewDynamicValue(c.Before, ty)
298 afterDV, err := NewDynamicValue(c.After, ty)