github.com/markdia/terraform@v0.5.1-0.20150508012022-f1ae920aa970/terraform/transform_orphan.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/hashicorp/terraform/config" 8 "github.com/hashicorp/terraform/config/module" 9 "github.com/hashicorp/terraform/dag" 10 ) 11 12 // GraphNodeStateRepresentative is an interface that can be implemented by 13 // a node to say that it is representing a resource in the state. 14 type GraphNodeStateRepresentative interface { 15 StateId() []string 16 } 17 18 // OrphanTransformer is a GraphTransformer that adds orphans to the 19 // graph. This transformer adds both resource and module orphans. 20 type OrphanTransformer struct { 21 // State is the global state. We require the global state to 22 // properly find module orphans at our path. 23 State *State 24 25 // Module is the root module. We'll look up the proper configuration 26 // using the graph path. 27 Module *module.Tree 28 29 // Targets are user-specified resources to target. We need to be aware of 30 // these so we don't improperly identify orphans when they've just been 31 // filtered out of the graph via targeting. 32 Targeting bool 33 34 // View, if non-nil will set a view on the module state. 35 View string 36 } 37 38 func (t *OrphanTransformer) Transform(g *Graph) error { 39 if t.State == nil { 40 // If the entire state is nil, there can't be any orphans 41 return nil 42 } 43 44 if t.Targeting { 45 log.Printf("Skipping orphan transformer because we have targets.") 46 // If we are in a run where we are targeting nodes, we won't process 47 // orphans for this run. 48 return nil 49 } 50 51 // Build up all our state representatives 52 resourceRep := make(map[string]struct{}) 53 for _, v := range g.Vertices() { 54 if sr, ok := v.(GraphNodeStateRepresentative); ok { 55 for _, k := range sr.StateId() { 56 resourceRep[k] = struct{}{} 57 } 58 } 59 } 60 61 var config *config.Config 62 if t.Module != nil { 63 if module := t.Module.Child(g.Path[1:]); module != nil { 64 config = module.Config() 65 } 66 } 67 68 var resourceVertexes []dag.Vertex 69 if state := t.State.ModuleByPath(g.Path); state != nil { 70 // If we have state, then we can have orphan resources 71 72 // If we have a view, get the view 73 if t.View != "" { 74 state = state.View(t.View) 75 } 76 77 // Go over each resource orphan and add it to the graph. 78 resourceOrphans := state.Orphans(config) 79 resourceVertexes = make([]dag.Vertex, len(resourceOrphans)) 80 for i, k := range resourceOrphans { 81 // If this orphan is represented by some other node somehow, 82 // then ignore it. 83 if _, ok := resourceRep[k]; ok { 84 continue 85 } 86 87 rs := state.Resources[k] 88 89 resourceVertexes[i] = g.Add(&graphNodeOrphanResource{ 90 ResourceName: k, 91 ResourceType: rs.Type, 92 Provider: rs.Provider, 93 dependentOn: rs.Dependencies, 94 }) 95 } 96 } 97 98 // Go over each module orphan and add it to the graph. We store the 99 // vertexes and states outside so that we can connect dependencies later. 100 moduleOrphans := t.State.ModuleOrphans(g.Path, config) 101 moduleVertexes := make([]dag.Vertex, len(moduleOrphans)) 102 for i, path := range moduleOrphans { 103 moduleVertexes[i] = g.Add(&graphNodeOrphanModule{ 104 Path: path, 105 dependentOn: t.State.ModuleByPath(path).Dependencies, 106 }) 107 } 108 109 // Now do the dependencies. We do this _after_ adding all the orphan 110 // nodes above because there are cases in which the orphans themselves 111 // depend on other orphans. 112 113 // Resource dependencies 114 for _, v := range resourceVertexes { 115 g.ConnectDependent(v) 116 } 117 118 // Module dependencies 119 for _, v := range moduleVertexes { 120 g.ConnectDependent(v) 121 } 122 123 return nil 124 } 125 126 // graphNodeOrphanModule is the graph vertex representing an orphan resource.. 127 type graphNodeOrphanModule struct { 128 Path []string 129 130 dependentOn []string 131 } 132 133 func (n *graphNodeOrphanModule) DependableName() []string { 134 return []string{n.dependableName()} 135 } 136 137 func (n *graphNodeOrphanModule) DependentOn() []string { 138 return n.dependentOn 139 } 140 141 func (n *graphNodeOrphanModule) Name() string { 142 return fmt.Sprintf("%s (orphan)", n.dependableName()) 143 } 144 145 func (n *graphNodeOrphanModule) dependableName() string { 146 return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1]) 147 } 148 149 // GraphNodeExpandable 150 func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) { 151 g, err := b.Build(n.Path) 152 if err != nil { 153 return nil, err 154 } 155 156 return &GraphNodeBasicSubgraph{ 157 NameValue: n.Name(), 158 Graph: g, 159 }, nil 160 } 161 162 // graphNodeOrphanResource is the graph vertex representing an orphan resource.. 163 type graphNodeOrphanResource struct { 164 ResourceName string 165 ResourceType string 166 Provider string 167 168 dependentOn []string 169 } 170 171 func (n *graphNodeOrphanResource) DependableName() []string { 172 return []string{n.dependableName()} 173 } 174 175 func (n *graphNodeOrphanResource) DependentOn() []string { 176 return n.dependentOn 177 } 178 179 func (n *graphNodeOrphanResource) Name() string { 180 return fmt.Sprintf("%s (orphan)", n.ResourceName) 181 } 182 183 func (n *graphNodeOrphanResource) ProvidedBy() []string { 184 return []string{resourceProvider(n.ResourceName, n.Provider)} 185 } 186 187 // GraphNodeEvalable impl. 188 func (n *graphNodeOrphanResource) EvalTree() EvalNode { 189 var provider ResourceProvider 190 var state *InstanceState 191 192 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 193 194 // Build instance info 195 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 196 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 197 198 // Refresh the resource 199 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 200 Ops: []walkOperation{walkRefresh}, 201 Node: &EvalSequence{ 202 Nodes: []EvalNode{ 203 &EvalGetProvider{ 204 Name: n.ProvidedBy()[0], 205 Output: &provider, 206 }, 207 &EvalReadState{ 208 Name: n.ResourceName, 209 Output: &state, 210 }, 211 &EvalRefresh{ 212 Info: info, 213 Provider: &provider, 214 State: &state, 215 Output: &state, 216 }, 217 &EvalWriteState{ 218 Name: n.ResourceName, 219 ResourceType: n.ResourceType, 220 Provider: n.Provider, 221 Dependencies: n.DependentOn(), 222 State: &state, 223 }, 224 }, 225 }, 226 }) 227 228 // Diff the resource 229 var diff *InstanceDiff 230 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 231 Ops: []walkOperation{walkPlan, walkPlanDestroy}, 232 Node: &EvalSequence{ 233 Nodes: []EvalNode{ 234 &EvalReadState{ 235 Name: n.ResourceName, 236 Output: &state, 237 }, 238 &EvalDiffDestroy{ 239 Info: info, 240 State: &state, 241 Output: &diff, 242 }, 243 &EvalWriteDiff{ 244 Name: n.ResourceName, 245 Diff: &diff, 246 }, 247 }, 248 }, 249 }) 250 251 // Apply 252 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 253 Ops: []walkOperation{walkApply}, 254 Node: &EvalSequence{ 255 Nodes: []EvalNode{ 256 &EvalReadDiff{ 257 Name: n.ResourceName, 258 Diff: &diff, 259 }, 260 &EvalGetProvider{ 261 Name: n.ProvidedBy()[0], 262 Output: &provider, 263 }, 264 &EvalReadState{ 265 Name: n.ResourceName, 266 Output: &state, 267 }, 268 &EvalApply{ 269 Info: info, 270 State: &state, 271 Diff: &diff, 272 Provider: &provider, 273 Output: &state, 274 }, 275 &EvalWriteState{ 276 Name: n.ResourceName, 277 ResourceType: n.ResourceType, 278 Provider: n.Provider, 279 Dependencies: n.DependentOn(), 280 State: &state, 281 }, 282 &EvalUpdateStateHook{}, 283 }, 284 }, 285 }) 286 287 return seq 288 } 289 290 func (n *graphNodeOrphanResource) dependableName() string { 291 return n.ResourceName 292 }