github.com/wikibal01/hashicorp-terraform@v0.11.12-beta1/terraform/node_resource_destroy.go (about) 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 }