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