package plans import ( "github.com/hashicorp/terraform/addrs" "github.com/hashicorp/terraform/states" "github.com/zclconf/go-cty/cty" ) // Changes describes various actions that Terraform will attempt to take if // the corresponding plan is applied. // // A Changes object can be rendered into a visual diff (by the caller, using // code in another package) for display to the user. type Changes struct { Resources []*ResourceInstanceChangeSrc RootOutputs map[string]*OutputChangeSrc } // NewChanges returns a valid Changes object that describes no changes. func NewChanges() *Changes { return &Changes{ RootOutputs: make(map[string]*OutputChangeSrc), } } // ResourceInstanceChange describes a change to a particular resource instance // object. type ResourceInstanceChange struct { // Addr is the absolute address of the resource instance that the change // will apply to. Addr 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 // Change is an embedded description of the change. Change } // Encode produces a variant of the reciever that has its change values // serialized so it can be written to a plan file. Pass the implied type of the // corresponding resource type schema for correct operation. func (rc *ResourceInstanceChange) Encode(ty cty.Type) (*ResourceInstanceChangeSrc, error) { cs, err := rc.Change.Encode(ty) if err != nil { return nil, err } return &ResourceInstanceChangeSrc{ Addr: rc.Addr, DeposedKey: rc.DeposedKey, ProviderAddr: rc.ProviderAddr, ChangeSrc: *cs, }, err } // OutputChange describes a change to an output value. type OutputChange struct { // Change is an embedded description of the change. // // For output value changes, the type constraint for the DynamicValue // instances is always cty.DynamicPseudoType. Change // 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 } // Encode produces a variant of the reciever that has its change values // serialized so it can be written to a plan file. func (oc *OutputChange) Encode() (*OutputChangeSrc, error) { cs, err := oc.Change.Encode(cty.DynamicPseudoType) if err != nil { return nil, err } return &OutputChangeSrc{ ChangeSrc: *cs, Sensitive: oc.Sensitive, }, err } // Change describes a single change with a given action. type Change struct { // Action defines what kind of change is being made. Action Action // Interpretation of Before and After depend on Action: // // NoOp Before and After are the same, unchanged value // Create Before is nil, and After is the expected value after create. // Read Before is any prior value (nil if no prior), and After is the // value that was or will be read. // Update Before is the value prior to update, and After is the expected // value after update. // Replace As with Update. // Delete Before is the value prior to delete, and After is always nil. // // Unknown values may appear anywhere within the Before and After values, // either as the values themselves or as nested elements within known // collections/structures. Before, After cty.Value } // Encode produces a variant of the reciever that has its change values // serialized so it can be written to a plan file. Pass the type constraint // that the values are expected to conform to; to properly decode the values // later an identical type constraint must be provided at that time. // // Where a Change is embedded in some other struct, it's generally better // to call the corresponding Encode method of that struct rather than working // directly with its embedded Change. func (c *Change) Encode(ty cty.Type) (*ChangeSrc, error) { beforeDV, err := NewDynamicValue(c.Before, ty) if err != nil { return nil, err } afterDV, err := NewDynamicValue(c.After, ty) if err != nil { return nil, err } return &ChangeSrc{ Action: c.Action, Before: beforeDV, After: afterDV, }, nil }