github.com/nov1n/terraform@v0.7.9-0.20161103151050-bf6852f38e28/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 // GraphNodeReferenceable, overriding NodeAbstractResource 34 func (n *NodeDestroyResource) ReferenceableName() []string { 35 result := n.NodeAbstractResource.ReferenceableName() 36 for i, v := range result { 37 result[i] = v + ".destroy" 38 } 39 40 return result 41 } 42 43 // GraphNodeReferencer, overriding NodeAbstractResource 44 func (n *NodeDestroyResource) References() []string { 45 return nil 46 } 47 48 // GraphNodeDynamicExpandable 49 func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) { 50 // If we have no config we do nothing 51 if n.Config == nil { 52 return nil, nil 53 } 54 55 state, lock := ctx.State() 56 lock.RLock() 57 defer lock.RUnlock() 58 59 // Start creating the steps 60 steps := make([]GraphTransformer, 0, 5) 61 62 // We want deposed resources in the state to be destroyed 63 steps = append(steps, &DeposedTransformer{ 64 State: state, 65 View: n.Config.Id(), 66 }) 67 68 // Target 69 steps = append(steps, &TargetsTransformer{ 70 ParsedTargets: n.Targets, 71 }) 72 73 // Always end with the root being added 74 steps = append(steps, &RootTransformer{}) 75 76 // Build the graph 77 b := &BasicGraphBuilder{Steps: steps} 78 return b.Build(ctx.Path()) 79 } 80 81 // GraphNodeEvalable 82 func (n *NodeDestroyResource) EvalTree() EvalNode { 83 // stateId is the ID to put into the state 84 stateId := n.Addr.stateId() 85 if n.Addr.Index > -1 { 86 stateId = fmt.Sprintf("%s.%d", stateId, n.Addr.Index) 87 } 88 89 // Build the instance info. More of this will be populated during eval 90 info := &InstanceInfo{ 91 Id: stateId, 92 Type: n.Addr.Type, 93 uniqueExtra: "destroy", 94 } 95 96 // Get our state 97 rs := n.ResourceState 98 if rs == nil { 99 rs = &ResourceState{} 100 } 101 102 var diffApply *InstanceDiff 103 var provider ResourceProvider 104 var state *InstanceState 105 var err error 106 return &EvalOpFilter{ 107 Ops: []walkOperation{walkApply, walkDestroy}, 108 Node: &EvalSequence{ 109 Nodes: []EvalNode{ 110 // Get the saved diff for apply 111 &EvalReadDiff{ 112 Name: stateId, 113 Diff: &diffApply, 114 }, 115 116 // Filter the diff so we only get the destroy 117 &EvalFilterDiff{ 118 Diff: &diffApply, 119 Output: &diffApply, 120 Destroy: true, 121 }, 122 123 // If we're not destroying, then compare diffs 124 &EvalIf{ 125 If: func(ctx EvalContext) (bool, error) { 126 if diffApply != nil && diffApply.GetDestroy() { 127 return true, nil 128 } 129 130 return true, EvalEarlyExitError{} 131 }, 132 Then: EvalNoop{}, 133 }, 134 135 // Load the instance info so we have the module path set 136 &EvalInstanceInfo{Info: info}, 137 138 &EvalGetProvider{ 139 Name: n.ProvidedBy()[0], 140 Output: &provider, 141 }, 142 &EvalReadState{ 143 Name: stateId, 144 Output: &state, 145 }, 146 &EvalRequireState{ 147 State: &state, 148 }, 149 // Make sure we handle data sources properly. 150 &EvalIf{ 151 If: func(ctx EvalContext) (bool, error) { 152 if n.Addr == nil { 153 return false, fmt.Errorf("nil address") 154 } 155 156 if n.Addr.Mode == config.DataResourceMode { 157 return true, nil 158 } 159 160 return false, nil 161 }, 162 163 Then: &EvalReadDataApply{ 164 Info: info, 165 Diff: &diffApply, 166 Provider: &provider, 167 Output: &state, 168 }, 169 Else: &EvalApply{ 170 Info: info, 171 State: &state, 172 Diff: &diffApply, 173 Provider: &provider, 174 Output: &state, 175 Error: &err, 176 }, 177 }, 178 &EvalWriteState{ 179 Name: stateId, 180 ResourceType: n.Addr.Type, 181 Provider: rs.Provider, 182 Dependencies: rs.Dependencies, 183 State: &state, 184 }, 185 &EvalApplyPost{ 186 Info: info, 187 State: &state, 188 Error: &err, 189 }, 190 &EvalUpdateStateHook{}, 191 }, 192 }, 193 } 194 }