6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/dag"
8 "github.com/hashicorp/terraform/plans"
9 "github.com/hashicorp/terraform/providers"
10 "github.com/hashicorp/terraform/states"
13 // ConcreteResourceInstanceDeposedNodeFunc is a callback type used to convert
14 // an abstract resource instance to a concrete one of some type that has
15 // an associated deposed object key.
16 type ConcreteResourceInstanceDeposedNodeFunc func(*NodeAbstractResourceInstance, states.DeposedKey) dag.Vertex
18 type GraphNodeDeposedResourceInstanceObject interface {
19 DeposedInstanceObjectKey() states.DeposedKey
22 // NodePlanDeposedResourceInstanceObject represents deposed resource
23 // instance objects during plan. These are distinct from the primary object
24 // for each resource instance since the only valid operation to do with them
25 // is to destroy them.
27 // This node type is also used during the refresh walk to ensure that the
28 // record of a deposed object is up-to-date before we plan to destroy it.
29 type NodePlanDeposedResourceInstanceObject struct {
30 *NodeAbstractResourceInstance
31 DeposedKey states.DeposedKey
35 _ GraphNodeDeposedResourceInstanceObject = (*NodePlanDeposedResourceInstanceObject)(nil)
36 _ GraphNodeResource = (*NodePlanDeposedResourceInstanceObject)(nil)
37 _ GraphNodeResourceInstance = (*NodePlanDeposedResourceInstanceObject)(nil)
38 _ GraphNodeReferenceable = (*NodePlanDeposedResourceInstanceObject)(nil)
39 _ GraphNodeReferencer = (*NodePlanDeposedResourceInstanceObject)(nil)
40 _ GraphNodeEvalable = (*NodePlanDeposedResourceInstanceObject)(nil)
41 _ GraphNodeProviderConsumer = (*NodePlanDeposedResourceInstanceObject)(nil)
42 _ GraphNodeProvisionerConsumer = (*NodePlanDeposedResourceInstanceObject)(nil)
45 func (n *NodePlanDeposedResourceInstanceObject) Name() string {
46 return fmt.Sprintf("%s (deposed %s)", n.ResourceInstanceAddr().String(), n.DeposedKey)
49 func (n *NodePlanDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey {
53 // GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
54 func (n *NodePlanDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
55 // Deposed objects don't participate in references.
59 // GraphNodeReferencer implementation, overriding the one from NodeAbstractResourceInstance
60 func (n *NodePlanDeposedResourceInstanceObject) References() []*addrs.Reference {
61 // We don't evaluate configuration for deposed objects, so they effectively
62 // make no references.
66 // GraphNodeEvalable impl.
67 func (n *NodePlanDeposedResourceInstanceObject) EvalTree() EvalNode {
68 addr := n.ResourceInstanceAddr()
70 var provider providers.Interface
71 var providerSchema *ProviderSchema
72 var state *states.ResourceInstanceObject
74 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
76 // During the refresh walk we will ensure that our record of the deposed
77 // object is up-to-date. If it was already deleted outside of Terraform
78 // then this will remove it from state and thus avoid us planning a
79 // destroy for it during the subsequent plan walk.
80 seq.Nodes = append(seq.Nodes, &EvalOpFilter{
81 Ops: []walkOperation{walkRefresh},
85 Addr: n.ResolvedProvider,
87 Schema: &providerSchema,
89 &EvalReadStateDeposed{
92 ProviderSchema: &providerSchema,
98 ProviderAddr: n.ResolvedProvider,
100 ProviderSchema: &providerSchema,
104 &EvalWriteStateDeposed{
107 ProviderAddr: n.ResolvedProvider,
108 ProviderSchema: &providerSchema,
115 // During the plan walk we always produce a planned destroy change, because
116 // destroying is the only supported action for deposed objects.
117 var change *plans.ResourceInstanceChange
118 seq.Nodes = append(seq.Nodes, &EvalOpFilter{
119 Ops: []walkOperation{walkPlan, walkPlanDestroy},
123 Addr: n.ResolvedProvider,
125 Schema: &providerSchema,
127 &EvalReadStateDeposed{
132 ProviderSchema: &providerSchema,
136 ProviderAddr: n.ResolvedProvider,
137 DeposedKey: n.DeposedKey,
143 DeposedKey: n.DeposedKey,
144 ProviderSchema: &providerSchema,
147 // Since deposed objects cannot be referenced by expressions
148 // elsewhere, we don't need to also record the planned new
149 // state in this case.
157 // NodeDestroyDeposedResourceInstanceObject represents deposed resource
158 // instance objects during apply. Nodes of this type are inserted by
159 // DiffTransformer when the planned changeset contains "delete" changes for
160 // deposed instance objects, and its only supported operation is to destroy
161 // and then forget the associated object.
162 type NodeDestroyDeposedResourceInstanceObject struct {
163 *NodeAbstractResourceInstance
164 DeposedKey states.DeposedKey
168 _ GraphNodeDeposedResourceInstanceObject = (*NodeDestroyDeposedResourceInstanceObject)(nil)
169 _ GraphNodeResource = (*NodeDestroyDeposedResourceInstanceObject)(nil)
170 _ GraphNodeResourceInstance = (*NodeDestroyDeposedResourceInstanceObject)(nil)
171 _ GraphNodeDestroyer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
172 _ GraphNodeDestroyerCBD = (*NodeDestroyDeposedResourceInstanceObject)(nil)
173 _ GraphNodeReferenceable = (*NodeDestroyDeposedResourceInstanceObject)(nil)
174 _ GraphNodeReferencer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
175 _ GraphNodeEvalable = (*NodeDestroyDeposedResourceInstanceObject)(nil)
176 _ GraphNodeProviderConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
177 _ GraphNodeProvisionerConsumer = (*NodeDestroyDeposedResourceInstanceObject)(nil)
180 func (n *NodeDestroyDeposedResourceInstanceObject) Name() string {
181 return fmt.Sprintf("%s (destroy deposed %s)", n.Addr.String(), n.DeposedKey)
184 func (n *NodeDestroyDeposedResourceInstanceObject) DeposedInstanceObjectKey() states.DeposedKey {
188 // GraphNodeReferenceable implementation, overriding the one from NodeAbstractResourceInstance
189 func (n *NodeDestroyDeposedResourceInstanceObject) ReferenceableAddrs() []addrs.Referenceable {
190 // Deposed objects don't participate in references.
194 // GraphNodeReferencer implementation, overriding the one from NodeAbstractResourceInstance
195 func (n *NodeDestroyDeposedResourceInstanceObject) References() []*addrs.Reference {
196 // We don't evaluate configuration for deposed objects, so they effectively
197 // make no references.
201 // GraphNodeDestroyer
202 func (n *NodeDestroyDeposedResourceInstanceObject) DestroyAddr() *addrs.AbsResourceInstance {
203 addr := n.ResourceInstanceAddr()
207 // GraphNodeDestroyerCBD
208 func (n *NodeDestroyDeposedResourceInstanceObject) CreateBeforeDestroy() bool {
209 // A deposed instance is always CreateBeforeDestroy by definition, since
210 // we use deposed only to handle create-before-destroy.
214 // GraphNodeDestroyerCBD
215 func (n *NodeDestroyDeposedResourceInstanceObject) ModifyCreateBeforeDestroy(v bool) error {
217 // Should never happen: deposed instances are _always_ create_before_destroy.
218 return fmt.Errorf("can't deactivate create_before_destroy for a deposed instance")
223 // GraphNodeEvalable impl.
224 func (n *NodeDestroyDeposedResourceInstanceObject) EvalTree() EvalNode {
225 addr := n.ResourceInstanceAddr()
227 var provider providers.Interface
228 var providerSchema *ProviderSchema
229 var state *states.ResourceInstanceObject
230 var change *plans.ResourceInstanceChange
233 return &EvalSequence{
236 Addr: n.ResolvedProvider,
238 Schema: &providerSchema,
240 &EvalReadStateDeposed{
245 ProviderSchema: &providerSchema,
249 ProviderAddr: n.ResolvedProvider,
253 // Call pre-apply hook
261 Config: nil, // No configuration because we are destroying
265 ProviderAddr: n.ResolvedProvider,
266 ProviderSchema: &providerSchema,
270 // Always write the resource back to the state deposed... if it
271 // was successfully destroyed it will be pruned. If it was not, it will
272 // be caught on the next run.
273 &EvalWriteStateDeposed{
276 ProviderAddr: n.ResolvedProvider,
277 ProviderSchema: &providerSchema,
288 &EvalUpdateStateHook{},
293 // GraphNodeDeposer is an optional interface implemented by graph nodes that
294 // might create a single new deposed object for a specific associated resource
295 // instance, allowing a caller to optionally pre-allocate a DeposedKey for
297 type GraphNodeDeposer interface {
298 // SetPreallocatedDeposedKey will be called during graph construction
299 // if a particular node must use a pre-allocated deposed key if/when it
300 // "deposes" the current object of its associated resource instance.
301 SetPreallocatedDeposedKey(key states.DeposedKey)
304 // graphNodeDeposer is an embeddable implementation of GraphNodeDeposer.
305 // Embed it in a node type to get automatic support for it, and then access
306 // the field PreallocatedDeposedKey to access any pre-allocated key.
307 type graphNodeDeposer struct {
308 PreallocatedDeposedKey states.DeposedKey
311 func (n *graphNodeDeposer) SetPreallocatedDeposedKey(key states.DeposedKey) {
312 n.PreallocatedDeposedKey = key