github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/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 }) 44 } 45 } 46 47 return nil 48 } 49 50 // graphNodeDeposedResource is the graph vertex representing a deposed resource. 51 type graphNodeDeposedResource struct { 52 Index int 53 ResourceName string 54 ResourceType string 55 } 56 57 func (n *graphNodeDeposedResource) Name() string { 58 return fmt.Sprintf("%s (deposed #%d)", n.ResourceName, n.Index) 59 } 60 61 func (n *graphNodeDeposedResource) ProvidedBy() []string { 62 return []string{resourceProvider(n.ResourceName)} 63 } 64 65 // GraphNodeEvalable impl. 66 func (n *graphNodeDeposedResource) EvalTree() EvalNode { 67 var provider ResourceProvider 68 var state *InstanceState 69 70 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 71 72 // Build instance info 73 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 74 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 75 76 // Refresh the resource 77 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 78 Ops: []walkOperation{walkRefresh}, 79 Node: &EvalSequence{ 80 Nodes: []EvalNode{ 81 &EvalGetProvider{ 82 Name: n.ProvidedBy()[0], 83 Output: &provider, 84 }, 85 &EvalReadStateDeposed{ 86 Name: n.ResourceName, 87 Output: &state, 88 Index: n.Index, 89 }, 90 &EvalRefresh{ 91 Info: info, 92 Provider: &provider, 93 State: &state, 94 Output: &state, 95 }, 96 &EvalWriteStateDeposed{ 97 Name: n.ResourceName, 98 ResourceType: n.ResourceType, 99 State: &state, 100 Index: n.Index, 101 }, 102 }, 103 }, 104 }) 105 106 // Apply 107 var diff *InstanceDiff 108 var err error 109 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 110 Ops: []walkOperation{walkApply}, 111 Node: &EvalSequence{ 112 Nodes: []EvalNode{ 113 &EvalGetProvider{ 114 Name: n.ProvidedBy()[0], 115 Output: &provider, 116 }, 117 &EvalReadStateDeposed{ 118 Name: n.ResourceName, 119 Output: &state, 120 Index: n.Index, 121 }, 122 &EvalDiffDestroy{ 123 Info: info, 124 State: &state, 125 Output: &diff, 126 }, 127 &EvalApply{ 128 Info: info, 129 State: &state, 130 Diff: &diff, 131 Provider: &provider, 132 Output: &state, 133 Error: &err, 134 }, 135 // Always write the resource back to the state deposed... if it 136 // was successfully destroyed it will be pruned. If it was not, it will 137 // be caught on the next run. 138 &EvalWriteStateDeposed{ 139 Name: n.ResourceName, 140 ResourceType: n.ResourceType, 141 State: &state, 142 Index: n.Index, 143 }, 144 &EvalReturnError{ 145 Error: &err, 146 }, 147 &EvalUpdateStateHook{}, 148 }, 149 }, 150 }) 151 152 return seq 153 }