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