7 "github.com/hashicorp/terraform/plans"
8 "github.com/hashicorp/terraform/providers"
10 "github.com/hashicorp/terraform/addrs"
11 "github.com/hashicorp/terraform/configs"
12 "github.com/hashicorp/terraform/states"
15 // NodeDestroyResourceInstance represents a resource instance that is to be
17 type NodeDestroyResourceInstance struct {
18 *NodeAbstractResourceInstance
20 // If DeposedKey is set to anything other than states.NotDeposed then
21 // this node destroys a deposed object of the associated instance
22 // rather than its current object.
23 DeposedKey states.DeposedKey
25 CreateBeforeDestroyOverride *bool
29 _ GraphNodeResource = (*NodeDestroyResourceInstance)(nil)
30 _ GraphNodeResourceInstance = (*NodeDestroyResourceInstance)(nil)
31 _ GraphNodeDestroyer = (*NodeDestroyResourceInstance)(nil)
32 _ GraphNodeDestroyerCBD = (*NodeDestroyResourceInstance)(nil)
33 _ GraphNodeReferenceable = (*NodeDestroyResourceInstance)(nil)
34 _ GraphNodeReferencer = (*NodeDestroyResourceInstance)(nil)
35 _ GraphNodeEvalable = (*NodeDestroyResourceInstance)(nil)
36 _ GraphNodeProviderConsumer = (*NodeDestroyResourceInstance)(nil)
37 _ GraphNodeProvisionerConsumer = (*NodeDestroyResourceInstance)(nil)
40 func (n *NodeDestroyResourceInstance) Name() string {
41 if n.DeposedKey != states.NotDeposed {
42 return fmt.Sprintf("%s (destroy deposed %s)", n.ResourceInstanceAddr(), n.DeposedKey)
44 return n.ResourceInstanceAddr().String() + " (destroy)"
48 func (n *NodeDestroyResourceInstance) DestroyAddr() *addrs.AbsResourceInstance {
49 addr := n.ResourceInstanceAddr()
53 // GraphNodeDestroyerCBD
54 func (n *NodeDestroyResourceInstance) CreateBeforeDestroy() bool {
55 if n.CreateBeforeDestroyOverride != nil {
56 return *n.CreateBeforeDestroyOverride
59 // If we have no config, we just assume no
60 if n.Config == nil || n.Config.Managed == nil {
64 return n.Config.Managed.CreateBeforeDestroy
67 // GraphNodeDestroyerCBD
68 func (n *NodeDestroyResourceInstance) ModifyCreateBeforeDestroy(v bool) error {
69 n.CreateBeforeDestroyOverride = &v
73 // GraphNodeReferenceable, overriding NodeAbstractResource
74 func (n *NodeDestroyResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
75 normalAddrs := n.NodeAbstractResourceInstance.ReferenceableAddrs()
76 destroyAddrs := make([]addrs.Referenceable, len(normalAddrs))
78 phaseType := addrs.ResourceInstancePhaseDestroy
79 if n.CreateBeforeDestroy() {
80 phaseType = addrs.ResourceInstancePhaseDestroyCBD
83 for i, normalAddr := range normalAddrs {
84 switch ta := normalAddr.(type) {
86 destroyAddrs[i] = ta.Phase(phaseType)
87 case addrs.ResourceInstance:
88 destroyAddrs[i] = ta.Phase(phaseType)
90 destroyAddrs[i] = normalAddr
97 // GraphNodeReferencer, overriding NodeAbstractResource
98 func (n *NodeDestroyResourceInstance) References() []*addrs.Reference {
99 // If we have a config, then we need to include destroy-time dependencies
100 if c := n.Config; c != nil && c.Managed != nil {
101 var result []*addrs.Reference
103 // We include conn info and config for destroy time provisioners
104 // as dependencies that we have.
105 for _, p := range c.Managed.Provisioners {
106 schema := n.ProvisionerSchemas[p.Type]
108 if p.When == configs.ProvisionerWhenDestroy {
109 if p.Connection != nil {
110 result = append(result, ReferencesFromConfig(p.Connection.Config, connectionBlockSupersetSchema)...)
112 result = append(result, ReferencesFromConfig(p.Config, schema)...)
123 func (n *NodeDestroyResourceInstance) EvalTree() EvalNode {
124 addr := n.ResourceInstanceAddr()
127 rs := n.ResourceState
128 var is *states.ResourceInstance
130 is = rs.Instance(n.InstanceKey)
133 log.Printf("[WARN] NodeDestroyResourceInstance for %s with no state", addr)
136 var changeApply *plans.ResourceInstanceChange
137 var provider providers.Interface
138 var providerSchema *ProviderSchema
139 var state *states.ResourceInstanceObject
141 return &EvalOpFilter{
142 Ops: []walkOperation{walkApply, walkDestroy},
146 Addr: n.ResolvedProvider,
148 Schema: &providerSchema,
151 // Get the saved diff for apply
154 ProviderSchema: &providerSchema,
155 Change: &changeApply,
160 InChange: &changeApply,
162 OutChange: &changeApply,
165 // EvalReduceDiff may have simplified our planned change
166 // into a NoOp if it does not require destroying.
168 If: func(ctx EvalContext) (bool, error) {
169 if changeApply == nil || changeApply.Action == plans.NoOp {
170 return true, EvalEarlyExitError{}
181 ProviderSchema: &providerSchema,
187 // Call pre-apply hook
191 Change: &changeApply,
194 // Run destroy provisioners if not tainted
196 If: func(ctx EvalContext) (bool, error) {
197 if state != nil && state.Status == states.ObjectTainted {
204 Then: &EvalApplyProvisioners{
207 ResourceConfig: n.Config,
209 When: configs.ProvisionerWhenDestroy,
213 // If we have a provisioning error, then we just call
214 // the post-apply hook now.
216 If: func(ctx EvalContext) (bool, error) {
217 return err != nil, nil
220 Then: &EvalApplyPost{
227 // Make sure we handle data sources properly.
229 If: func(ctx EvalContext) (bool, error) {
230 return addr.Resource.Resource.Mode == addrs.DataResourceMode, nil
233 Then: &EvalReadDataApply{
236 Change: &changeApply,
238 ProviderAddr: n.ResolvedProvider,
239 ProviderSchema: &providerSchema,
244 Config: nil, // No configuration because we are destroying
246 Change: &changeApply,
248 ProviderAddr: n.ResolvedProvider,
249 ProviderSchema: &providerSchema,
256 ProviderAddr: n.ResolvedProvider,
257 ProviderSchema: &providerSchema,
265 &EvalUpdateStateHook{},
271 // NodeDestroyResourceInstance represents a resource that is to be destroyed.
273 // Destroying a resource is a state-only operation: it is the individual
274 // instances being destroyed that affects remote objects. During graph
275 // construction, NodeDestroyResource should always depend on any other node
276 // related to the given resource, since it's just a final cleanup to avoid
277 // leaving skeleton resource objects in state after their instances have
278 // all been destroyed.
279 type NodeDestroyResource struct {
280 *NodeAbstractResource
284 _ GraphNodeResource = (*NodeDestroyResource)(nil)
285 _ GraphNodeReferenceable = (*NodeDestroyResource)(nil)
286 _ GraphNodeReferencer = (*NodeDestroyResource)(nil)
287 _ GraphNodeEvalable = (*NodeDestroyResource)(nil)
290 func (n *NodeDestroyResource) Name() string {
291 return n.ResourceAddr().String() + " (clean up state)"
294 // GraphNodeReferenceable, overriding NodeAbstractResource
295 func (n *NodeDestroyResource) ReferenceableAddrs() []addrs.Referenceable {
296 // NodeDestroyResource doesn't participate in references: the graph
297 // builder that created it should ensure directly that it already depends
298 // on every other node related to its resource, without relying on
303 // GraphNodeReferencer, overriding NodeAbstractResource
304 func (n *NodeDestroyResource) References() []*addrs.Reference {
305 // NodeDestroyResource doesn't participate in references: the graph
306 // builder that created it should ensure directly that it already depends
307 // on every other node related to its resource, without relying on
313 func (n *NodeDestroyResource) EvalTree() EvalNode {
314 // This EvalNode will produce an error if the resource isn't already
315 // empty by the time it is called, since it should just be pruning the
316 // leftover husk of a resource in state after all of the child instances
317 // and their objects were destroyed.
318 return &EvalForgetResourceState{
319 Addr: n.ResourceAddr().Resource,