]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/node_resource_destroy.go
Initial transfer of provider code
[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 })
108
109 // Target
110 steps = append(steps, &TargetsTransformer{
111 ParsedTargets: n.Targets,
112 })
113
114 // Always end with the root being added
115 steps = append(steps, &RootTransformer{})
116
117 // Build the graph
118 b := &BasicGraphBuilder{
119 Steps: steps,
120 Name: "NodeResourceDestroy",
121 }
122 return b.Build(ctx.Path())
123 }
124
125 // GraphNodeEvalable
126 func (n *NodeDestroyResource) EvalTree() EvalNode {
127 // stateId is the ID to put into the state
128 stateId := n.Addr.stateId()
129
130 // Build the instance info. More of this will be populated during eval
131 info := &InstanceInfo{
132 Id: stateId,
133 Type: n.Addr.Type,
134 uniqueExtra: "destroy",
135 }
136
137 // Build the resource for eval
138 addr := n.Addr
139 resource := &Resource{
140 Name: addr.Name,
141 Type: addr.Type,
142 CountIndex: addr.Index,
143 }
144 if resource.CountIndex < 0 {
145 resource.CountIndex = 0
146 }
147
148 // Get our state
149 rs := n.ResourceState
150 if rs == nil {
151 rs = &ResourceState{}
152 }
153
154 var diffApply *InstanceDiff
155 var provider ResourceProvider
156 var state *InstanceState
157 var err error
158 return &EvalOpFilter{
159 Ops: []walkOperation{walkApply, walkDestroy},
160 Node: &EvalSequence{
161 Nodes: []EvalNode{
162 // Get the saved diff for apply
163 &EvalReadDiff{
164 Name: stateId,
165 Diff: &diffApply,
166 },
167
168 // Filter the diff so we only get the destroy
169 &EvalFilterDiff{
170 Diff: &diffApply,
171 Output: &diffApply,
172 Destroy: true,
173 },
174
175 // If we're not destroying, then compare diffs
176 &EvalIf{
177 If: func(ctx EvalContext) (bool, error) {
178 if diffApply != nil && diffApply.GetDestroy() {
179 return true, nil
180 }
181
182 return true, EvalEarlyExitError{}
183 },
184 Then: EvalNoop{},
185 },
186
187 // Load the instance info so we have the module path set
188 &EvalInstanceInfo{Info: info},
189
190 &EvalGetProvider{
191 Name: n.ProvidedBy()[0],
192 Output: &provider,
193 },
194 &EvalReadState{
195 Name: stateId,
196 Output: &state,
197 },
198 &EvalRequireState{
199 State: &state,
200 },
201
202 // Call pre-apply hook
203 &EvalApplyPre{
204 Info: info,
205 State: &state,
206 Diff: &diffApply,
207 },
208
209 // Run destroy provisioners if not tainted
210 &EvalIf{
211 If: func(ctx EvalContext) (bool, error) {
212 if state != nil && state.Tainted {
213 return false, nil
214 }
215
216 return true, nil
217 },
218
219 Then: &EvalApplyProvisioners{
220 Info: info,
221 State: &state,
222 Resource: n.Config,
223 InterpResource: resource,
224 Error: &err,
225 When: config.ProvisionerWhenDestroy,
226 },
227 },
228
229 // If we have a provisioning error, then we just call
230 // the post-apply hook now.
231 &EvalIf{
232 If: func(ctx EvalContext) (bool, error) {
233 return err != nil, nil
234 },
235
236 Then: &EvalApplyPost{
237 Info: info,
238 State: &state,
239 Error: &err,
240 },
241 },
242
243 // Make sure we handle data sources properly.
244 &EvalIf{
245 If: func(ctx EvalContext) (bool, error) {
246 if n.Addr == nil {
247 return false, fmt.Errorf("nil address")
248 }
249
250 if n.Addr.Mode == config.DataResourceMode {
251 return true, nil
252 }
253
254 return false, nil
255 },
256
257 Then: &EvalReadDataApply{
258 Info: info,
259 Diff: &diffApply,
260 Provider: &provider,
261 Output: &state,
262 },
263 Else: &EvalApply{
264 Info: info,
265 State: &state,
266 Diff: &diffApply,
267 Provider: &provider,
268 Output: &state,
269 Error: &err,
270 },
271 },
272 &EvalWriteState{
273 Name: stateId,
274 ResourceType: n.Addr.Type,
275 Provider: rs.Provider,
276 Dependencies: rs.Dependencies,
277 State: &state,
278 },
279 &EvalApplyPost{
280 Info: info,
281 State: &state,
282 Error: &err,
283 },
284 &EvalUpdateStateHook{},
285 },
286 },
287 }
288 }