]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / node_resource_destroy.go
1 package terraform
2
3 import (
4 "fmt"
5
6 "github.com/hashicorp/terraform/config"
7 )
8
9 // NodeDestroyResource represents a resource that is to be destroyed.
10 type NodeDestroyResource struct {
11 *NodeAbstractResource
12 }
13
14 func (n *NodeDestroyResource) Name() string {
15 return n.NodeAbstractResource.Name() + " (destroy)"
16 }
17
18 // GraphNodeDestroyer
19 func (n *NodeDestroyResource) DestroyAddr() *ResourceAddress {
20 return n.Addr
21 }
22
23 // GraphNodeDestroyerCBD
24 func (n *NodeDestroyResource) CreateBeforeDestroy() bool {
25 // If we have no config, we just assume no
26 if n.Config == nil {
27 return false
28 }
29
30 return n.Config.Lifecycle.CreateBeforeDestroy
31 }
32
33 // GraphNodeDestroyerCBD
34 func (n *NodeDestroyResource) ModifyCreateBeforeDestroy(v bool) error {
35 // If we have no config, do nothing since it won't affect the
36 // create step anyways.
37 if n.Config == nil {
38 return nil
39 }
40
41 // Set CBD to true
42 n.Config.Lifecycle.CreateBeforeDestroy = true
43
44 return nil
45 }
46
47 // GraphNodeReferenceable, overriding NodeAbstractResource
48 func (n *NodeDestroyResource) ReferenceableName() []string {
49 // We modify our referenceable name to have the suffix of ".destroy"
50 // since depending on the creation side doesn't necessarilly mean
51 // depending on destruction.
52 suffix := ".destroy"
53
54 // If we're CBD, we also append "-cbd". This is because CBD will setup
55 // its own edges (in CBDEdgeTransformer). Depending on the "destroy"
56 // side generally doesn't mean depending on CBD as well. See GH-11349
57 if n.CreateBeforeDestroy() {
58 suffix += "-cbd"
59 }
60
61 result := n.NodeAbstractResource.ReferenceableName()
62 for i, v := range result {
63 result[i] = v + suffix
64 }
65
66 return result
67 }
68
69 // GraphNodeReferencer, overriding NodeAbstractResource
70 func (n *NodeDestroyResource) References() []string {
71 // If we have a config, then we need to include destroy-time dependencies
72 if c := n.Config; c != nil {
73 var result []string
74 for _, p := range c.Provisioners {
75 // We include conn info and config for destroy time provisioners
76 // as dependencies that we have.
77 if p.When == config.ProvisionerWhenDestroy {
78 result = append(result, ReferencesFromConfig(p.ConnInfo)...)
79 result = append(result, ReferencesFromConfig(p.RawConfig)...)
80 }
81 }
82
83 return result
84 }
85
86 return nil
87 }
88
89 // GraphNodeDynamicExpandable
90 func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
91 // If we have no config we do nothing
92 if n.Addr == nil {
93 return nil, nil
94 }
95
96 state, lock := ctx.State()
97 lock.RLock()
98 defer lock.RUnlock()
99
100 // Start creating the steps
101 steps := make([]GraphTransformer, 0, 5)
102
103 // We want deposed resources in the state to be destroyed
104 steps = append(steps, &DeposedTransformer{
105 State: state,
106 View: n.Addr.stateId(),
107 ResolvedProvider: n.ResolvedProvider,
108 })
109
110 // Target
111 steps = append(steps, &TargetsTransformer{
112 ParsedTargets: n.Targets,
113 })
114
115 // Always end with the root being added
116 steps = append(steps, &RootTransformer{})
117
118 // Build the graph
119 b := &BasicGraphBuilder{
120 Steps: steps,
121 Name: "NodeResourceDestroy",
122 }
123 return b.Build(ctx.Path())
124 }
125
126 // GraphNodeEvalable
127 func (n *NodeDestroyResource) EvalTree() EvalNode {
128 // stateId is the ID to put into the state
129 stateId := n.Addr.stateId()
130
131 // Build the instance info. More of this will be populated during eval
132 info := &InstanceInfo{
133 Id: stateId,
134 Type: n.Addr.Type,
135 uniqueExtra: "destroy",
136 }
137
138 // Build the resource for eval
139 addr := n.Addr
140 resource := &Resource{
141 Name: addr.Name,
142 Type: addr.Type,
143 CountIndex: addr.Index,
144 }
145 if resource.CountIndex < 0 {
146 resource.CountIndex = 0
147 }
148
149 // Get our state
150 rs := n.ResourceState
151 if rs == nil {
152 rs = &ResourceState{
153 Provider: n.ResolvedProvider,
154 }
155 }
156
157 var diffApply *InstanceDiff
158 var provider ResourceProvider
159 var state *InstanceState
160 var err error
161 return &EvalOpFilter{
162 Ops: []walkOperation{walkApply, walkDestroy},
163 Node: &EvalSequence{
164 Nodes: []EvalNode{
165 // Get the saved diff for apply
166 &EvalReadDiff{
167 Name: stateId,
168 Diff: &diffApply,
169 },
170
171 // Filter the diff so we only get the destroy
172 &EvalFilterDiff{
173 Diff: &diffApply,
174 Output: &diffApply,
175 Destroy: true,
176 },
177
178 // If we're not destroying, then compare diffs
179 &EvalIf{
180 If: func(ctx EvalContext) (bool, error) {
181 if diffApply != nil && diffApply.GetDestroy() {
182 return true, nil
183 }
184
185 return true, EvalEarlyExitError{}
186 },
187 Then: EvalNoop{},
188 },
189
190 // Load the instance info so we have the module path set
191 &EvalInstanceInfo{Info: info},
192
193 &EvalGetProvider{
194 Name: n.ResolvedProvider,
195 Output: &provider,
196 },
197 &EvalReadState{
198 Name: stateId,
199 Output: &state,
200 },
201 &EvalRequireState{
202 State: &state,
203 },
204
205 // Call pre-apply hook
206 &EvalApplyPre{
207 Info: info,
208 State: &state,
209 Diff: &diffApply,
210 },
211
212 // Run destroy provisioners if not tainted
213 &EvalIf{
214 If: func(ctx EvalContext) (bool, error) {
215 if state != nil && state.Tainted {
216 return false, nil
217 }
218
219 return true, nil
220 },
221
222 Then: &EvalApplyProvisioners{
223 Info: info,
224 State: &state,
225 Resource: n.Config,
226 InterpResource: resource,
227 Error: &err,
228 When: config.ProvisionerWhenDestroy,
229 },
230 },
231
232 // If we have a provisioning error, then we just call
233 // the post-apply hook now.
234 &EvalIf{
235 If: func(ctx EvalContext) (bool, error) {
236 return err != nil, nil
237 },
238
239 Then: &EvalApplyPost{
240 Info: info,
241 State: &state,
242 Error: &err,
243 },
244 },
245
246 // Make sure we handle data sources properly.
247 &EvalIf{
248 If: func(ctx EvalContext) (bool, error) {
249 if n.Addr == nil {
250 return false, fmt.Errorf("nil address")
251 }
252
253 if n.Addr.Mode == config.DataResourceMode {
254 return true, nil
255 }
256
257 return false, nil
258 },
259
260 Then: &EvalReadDataApply{
261 Info: info,
262 Diff: &diffApply,
263 Provider: &provider,
264 Output: &state,
265 },
266 Else: &EvalApply{
267 Info: info,
268 State: &state,
269 Diff: &diffApply,
270 Provider: &provider,
271 Output: &state,
272 Error: &err,
273 },
274 },
275 &EvalWriteState{
276 Name: stateId,
277 ResourceType: n.Addr.Type,
278 Provider: n.ResolvedProvider,
279 Dependencies: rs.Dependencies,
280 State: &state,
281 },
282 &EvalApplyPost{
283 Info: info,
284 State: &state,
285 Error: &err,
286 },
287 &EvalUpdateStateHook{},
288 },
289 },
290 }
291 }