github.com/bpineau/terraform@v0.8.0-rc1.0.20161126184705-a8886012d185/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{ 78 Steps: steps, 79 Name: "NodeResourceDestroy", 80 } 81 return b.Build(ctx.Path()) 82 } 83 84 // GraphNodeEvalable 85 func (n *NodeDestroyResource) EvalTree() EvalNode { 86 // stateId is the ID to put into the state 87 stateId := n.Addr.stateId() 88 if n.Addr.Index > -1 { 89 stateId = fmt.Sprintf("%s.%d", stateId, n.Addr.Index) 90 } 91 92 // Build the instance info. More of this will be populated during eval 93 info := &InstanceInfo{ 94 Id: stateId, 95 Type: n.Addr.Type, 96 uniqueExtra: "destroy", 97 } 98 99 // Get our state 100 rs := n.ResourceState 101 if rs == nil { 102 rs = &ResourceState{} 103 } 104 105 var diffApply *InstanceDiff 106 var provider ResourceProvider 107 var state *InstanceState 108 var err error 109 return &EvalOpFilter{ 110 Ops: []walkOperation{walkApply, walkDestroy}, 111 Node: &EvalSequence{ 112 Nodes: []EvalNode{ 113 // Get the saved diff for apply 114 &EvalReadDiff{ 115 Name: stateId, 116 Diff: &diffApply, 117 }, 118 119 // Filter the diff so we only get the destroy 120 &EvalFilterDiff{ 121 Diff: &diffApply, 122 Output: &diffApply, 123 Destroy: true, 124 }, 125 126 // If we're not destroying, then compare diffs 127 &EvalIf{ 128 If: func(ctx EvalContext) (bool, error) { 129 if diffApply != nil && diffApply.GetDestroy() { 130 return true, nil 131 } 132 133 return true, EvalEarlyExitError{} 134 }, 135 Then: EvalNoop{}, 136 }, 137 138 // Load the instance info so we have the module path set 139 &EvalInstanceInfo{Info: info}, 140 141 &EvalGetProvider{ 142 Name: n.ProvidedBy()[0], 143 Output: &provider, 144 }, 145 &EvalReadState{ 146 Name: stateId, 147 Output: &state, 148 }, 149 &EvalRequireState{ 150 State: &state, 151 }, 152 // Make sure we handle data sources properly. 153 &EvalIf{ 154 If: func(ctx EvalContext) (bool, error) { 155 if n.Addr == nil { 156 return false, fmt.Errorf("nil address") 157 } 158 159 if n.Addr.Mode == config.DataResourceMode { 160 return true, nil 161 } 162 163 return false, nil 164 }, 165 166 Then: &EvalReadDataApply{ 167 Info: info, 168 Diff: &diffApply, 169 Provider: &provider, 170 Output: &state, 171 }, 172 Else: &EvalApply{ 173 Info: info, 174 State: &state, 175 Diff: &diffApply, 176 Provider: &provider, 177 Output: &state, 178 Error: &err, 179 }, 180 }, 181 &EvalWriteState{ 182 Name: stateId, 183 ResourceType: n.Addr.Type, 184 Provider: rs.Provider, 185 Dependencies: rs.Dependencies, 186 State: &state, 187 }, 188 &EvalApplyPost{ 189 Info: info, 190 State: &state, 191 Error: &err, 192 }, 193 &EvalUpdateStateHook{}, 194 }, 195 }, 196 } 197 }