github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/transform_deposed.go (about) 1 package terraform 2 3 import "fmt" 4 5 // DeposedTransformer is a GraphTransformer that adds deposed resources 6 // to the graph. 7 type DeposedTransformer struct { 8 // State is the global state. We'll automatically find the correct 9 // ModuleState based on the Graph.Path that is being transformed. 10 State *State 11 12 // View, if non-empty, is the ModuleState.View used around the state 13 // to find deposed resources. 14 View string 15 } 16 17 func (t *DeposedTransformer) Transform(g *Graph) error { 18 state := t.State.ModuleByPath(g.Path) 19 if state == nil { 20 // If there is no state for our module there can't be any deposed 21 // resources, since they live in the state. 22 return nil 23 } 24 25 // If we have a view, apply it now 26 if t.View != "" { 27 state = state.View(t.View) 28 } 29 30 // Go through all the resources in our state to look for deposed resources 31 for k, rs := range state.Resources { 32 // If we have no deposed resources, then move on 33 if len(rs.Deposed) == 0 { 34 continue 35 } 36 deposed := rs.Deposed 37 38 for i, _ := range deposed { 39 g.Add(&graphNodeDeposedResource{ 40 Index: i, 41 ResourceName: k, 42 ResourceType: rs.Type, 43 Provider: rs.Provider, 44 }) 45 } 46 } 47 48 return nil 49 } 50 51 // graphNodeDeposedResource is the graph vertex representing a deposed resource. 52 type graphNodeDeposedResource struct { 53 Index int 54 ResourceName string 55 ResourceType string 56 Provider string 57 } 58 59 func (n *graphNodeDeposedResource) Name() string { 60 return fmt.Sprintf("%s (deposed #%d)", n.ResourceName, n.Index) 61 } 62 63 func (n *graphNodeDeposedResource) ProvidedBy() []string { 64 return []string{resourceProvider(n.ResourceName, n.Provider)} 65 } 66 67 // GraphNodeEvalable impl. 68 func (n *graphNodeDeposedResource) EvalTree() EvalNode { 69 var provider ResourceProvider 70 var state *InstanceState 71 72 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 73 74 // Build instance info 75 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 76 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 77 78 // Refresh the resource 79 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 80 Ops: []walkOperation{walkRefresh}, 81 Node: &EvalSequence{ 82 Nodes: []EvalNode{ 83 &EvalGetProvider{ 84 Name: n.ProvidedBy()[0], 85 Output: &provider, 86 }, 87 &EvalReadStateDeposed{ 88 Name: n.ResourceName, 89 Output: &state, 90 Index: n.Index, 91 }, 92 &EvalRefresh{ 93 Info: info, 94 Provider: &provider, 95 State: &state, 96 Output: &state, 97 }, 98 &EvalWriteStateDeposed{ 99 Name: n.ResourceName, 100 ResourceType: n.ResourceType, 101 Provider: n.Provider, 102 State: &state, 103 Index: n.Index, 104 }, 105 }, 106 }, 107 }) 108 109 // Apply 110 var diff *InstanceDiff 111 var err error 112 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 113 Ops: []walkOperation{walkApply, walkDestroy}, 114 Node: &EvalSequence{ 115 Nodes: []EvalNode{ 116 &EvalGetProvider{ 117 Name: n.ProvidedBy()[0], 118 Output: &provider, 119 }, 120 &EvalReadStateDeposed{ 121 Name: n.ResourceName, 122 Output: &state, 123 Index: n.Index, 124 }, 125 &EvalDiffDestroy{ 126 Info: info, 127 State: &state, 128 Output: &diff, 129 }, 130 &EvalApply{ 131 Info: info, 132 State: &state, 133 Diff: &diff, 134 Provider: &provider, 135 Output: &state, 136 Error: &err, 137 }, 138 // Always write the resource back to the state deposed... if it 139 // was successfully destroyed it will be pruned. If it was not, it will 140 // be caught on the next run. 141 &EvalWriteStateDeposed{ 142 Name: n.ResourceName, 143 ResourceType: n.ResourceType, 144 Provider: n.Provider, 145 State: &state, 146 Index: n.Index, 147 }, 148 &EvalReturnError{ 149 Error: &err, 150 }, 151 &EvalUpdateStateHook{}, 152 }, 153 }, 154 }) 155 156 return seq 157 }