github.com/turtlemonvh/terraform@v0.6.9-0.20151204001754-8e40b6b855e8/terraform/transform_orphan.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "strings" 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 Targets []ResourceAddress 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 // Build up all our state representatives 45 resourceRep := make(map[string]struct{}) 46 for _, v := range g.Vertices() { 47 if sr, ok := v.(GraphNodeStateRepresentative); ok { 48 for _, k := range sr.StateId() { 49 resourceRep[k] = struct{}{} 50 } 51 } 52 } 53 54 var config *config.Config 55 if t.Module != nil { 56 if module := t.Module.Child(g.Path[1:]); module != nil { 57 config = module.Config() 58 } 59 } 60 61 var resourceVertexes []dag.Vertex 62 if state := t.State.ModuleByPath(g.Path); state != nil { 63 // If we have state, then we can have orphan resources 64 65 // If we have a view, get the view 66 if t.View != "" { 67 state = state.View(t.View) 68 } 69 70 resourceOrphans := state.Orphans(config) 71 if len(t.Targets) > 0 { 72 var targetedOrphans []string 73 for _, o := range resourceOrphans { 74 targeted := false 75 for _, t := range t.Targets { 76 prefix := fmt.Sprintf("%s.%s.%d", t.Type, t.Name, t.Index) 77 if strings.HasPrefix(o, prefix) { 78 targeted = true 79 } 80 } 81 if targeted { 82 targetedOrphans = append(targetedOrphans, o) 83 } 84 } 85 resourceOrphans = targetedOrphans 86 } 87 88 resourceVertexes = make([]dag.Vertex, len(resourceOrphans)) 89 for i, k := range resourceOrphans { 90 // If this orphan is represented by some other node somehow, 91 // then ignore it. 92 if _, ok := resourceRep[k]; ok { 93 continue 94 } 95 96 rs := state.Resources[k] 97 98 resourceVertexes[i] = g.Add(&graphNodeOrphanResource{ 99 ResourceName: k, 100 ResourceType: rs.Type, 101 Provider: rs.Provider, 102 dependentOn: rs.Dependencies, 103 }) 104 } 105 } 106 107 // Go over each module orphan and add it to the graph. We store the 108 // vertexes and states outside so that we can connect dependencies later. 109 moduleOrphans := t.State.ModuleOrphans(g.Path, config) 110 moduleVertexes := make([]dag.Vertex, len(moduleOrphans)) 111 for i, path := range moduleOrphans { 112 var deps []string 113 if s := t.State.ModuleByPath(path); s != nil { 114 deps = s.Dependencies 115 } 116 117 moduleVertexes[i] = g.Add(&graphNodeOrphanModule{ 118 Path: path, 119 dependentOn: deps, 120 }) 121 } 122 123 // Now do the dependencies. We do this _after_ adding all the orphan 124 // nodes above because there are cases in which the orphans themselves 125 // depend on other orphans. 126 127 // Resource dependencies 128 for _, v := range resourceVertexes { 129 g.ConnectDependent(v) 130 } 131 132 // Module dependencies 133 for _, v := range moduleVertexes { 134 g.ConnectDependent(v) 135 } 136 137 return nil 138 } 139 140 // graphNodeOrphanModule is the graph vertex representing an orphan resource.. 141 type graphNodeOrphanModule struct { 142 Path []string 143 144 dependentOn []string 145 } 146 147 func (n *graphNodeOrphanModule) DependableName() []string { 148 return []string{n.dependableName()} 149 } 150 151 func (n *graphNodeOrphanModule) DependentOn() []string { 152 return n.dependentOn 153 } 154 155 func (n *graphNodeOrphanModule) Name() string { 156 return fmt.Sprintf("%s (orphan)", n.dependableName()) 157 } 158 159 func (n *graphNodeOrphanModule) dependableName() string { 160 return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1]) 161 } 162 163 // GraphNodeExpandable 164 func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) { 165 g, err := b.Build(n.Path) 166 if err != nil { 167 return nil, err 168 } 169 170 return &GraphNodeBasicSubgraph{ 171 NameValue: n.Name(), 172 Graph: g, 173 }, nil 174 } 175 176 // graphNodeOrphanResource is the graph vertex representing an orphan resource.. 177 type graphNodeOrphanResource struct { 178 ResourceName string 179 ResourceType string 180 Provider string 181 182 dependentOn []string 183 } 184 185 func (n *graphNodeOrphanResource) ResourceAddress() *ResourceAddress { 186 return n.ResourceAddress() 187 } 188 189 func (n *graphNodeOrphanResource) DependableName() []string { 190 return []string{n.dependableName()} 191 } 192 193 func (n *graphNodeOrphanResource) DependentOn() []string { 194 return n.dependentOn 195 } 196 197 func (n *graphNodeOrphanResource) Flatten(p []string) (dag.Vertex, error) { 198 return &graphNodeOrphanResourceFlat{ 199 graphNodeOrphanResource: n, 200 PathValue: p, 201 }, nil 202 } 203 204 func (n *graphNodeOrphanResource) Name() string { 205 return fmt.Sprintf("%s (orphan)", n.ResourceName) 206 } 207 208 func (n *graphNodeOrphanResource) ProvidedBy() []string { 209 return []string{resourceProvider(n.ResourceName, n.Provider)} 210 } 211 212 // GraphNodeEvalable impl. 213 func (n *graphNodeOrphanResource) EvalTree() EvalNode { 214 var provider ResourceProvider 215 var state *InstanceState 216 217 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 218 219 // Build instance info 220 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 221 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 222 223 // Refresh the resource 224 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 225 Ops: []walkOperation{walkRefresh}, 226 Node: &EvalSequence{ 227 Nodes: []EvalNode{ 228 &EvalGetProvider{ 229 Name: n.ProvidedBy()[0], 230 Output: &provider, 231 }, 232 &EvalReadState{ 233 Name: n.ResourceName, 234 Output: &state, 235 }, 236 &EvalRefresh{ 237 Info: info, 238 Provider: &provider, 239 State: &state, 240 Output: &state, 241 }, 242 &EvalWriteState{ 243 Name: n.ResourceName, 244 ResourceType: n.ResourceType, 245 Provider: n.Provider, 246 Dependencies: n.DependentOn(), 247 State: &state, 248 }, 249 }, 250 }, 251 }) 252 253 // Diff the resource 254 var diff *InstanceDiff 255 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 256 Ops: []walkOperation{walkPlan, walkPlanDestroy}, 257 Node: &EvalSequence{ 258 Nodes: []EvalNode{ 259 &EvalReadState{ 260 Name: n.ResourceName, 261 Output: &state, 262 }, 263 &EvalDiffDestroy{ 264 Info: info, 265 State: &state, 266 Output: &diff, 267 }, 268 &EvalWriteDiff{ 269 Name: n.ResourceName, 270 Diff: &diff, 271 }, 272 }, 273 }, 274 }) 275 276 // Apply 277 var err error 278 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 279 Ops: []walkOperation{walkApply, walkDestroy}, 280 Node: &EvalSequence{ 281 Nodes: []EvalNode{ 282 &EvalReadDiff{ 283 Name: n.ResourceName, 284 Diff: &diff, 285 }, 286 &EvalGetProvider{ 287 Name: n.ProvidedBy()[0], 288 Output: &provider, 289 }, 290 &EvalReadState{ 291 Name: n.ResourceName, 292 Output: &state, 293 }, 294 &EvalApply{ 295 Info: info, 296 State: &state, 297 Diff: &diff, 298 Provider: &provider, 299 Output: &state, 300 Error: &err, 301 }, 302 &EvalWriteState{ 303 Name: n.ResourceName, 304 ResourceType: n.ResourceType, 305 Provider: n.Provider, 306 Dependencies: n.DependentOn(), 307 State: &state, 308 }, 309 &EvalApplyPost{ 310 Info: info, 311 State: &state, 312 Error: &err, 313 }, 314 &EvalUpdateStateHook{}, 315 }, 316 }, 317 }) 318 319 return seq 320 } 321 322 func (n *graphNodeOrphanResource) dependableName() string { 323 return n.ResourceName 324 } 325 326 // GraphNodeDestroyable impl. 327 func (n *graphNodeOrphanResource) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy { 328 if mode != DestroyPrimary { 329 return nil 330 } 331 332 return n 333 } 334 335 // GraphNodeDestroy impl. 336 func (n *graphNodeOrphanResource) CreateBeforeDestroy() bool { 337 return false 338 } 339 340 func (n *graphNodeOrphanResource) CreateNode() dag.Vertex { 341 return n 342 } 343 344 // Same as graphNodeOrphanResource, but for flattening 345 type graphNodeOrphanResourceFlat struct { 346 *graphNodeOrphanResource 347 348 PathValue []string 349 } 350 351 func (n *graphNodeOrphanResourceFlat) Name() string { 352 return fmt.Sprintf( 353 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeOrphanResource.Name()) 354 } 355 356 func (n *graphNodeOrphanResourceFlat) Path() []string { 357 return n.PathValue 358 } 359 360 // GraphNodeDestroyable impl. 361 func (n *graphNodeOrphanResourceFlat) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy { 362 if mode != DestroyPrimary { 363 return nil 364 } 365 366 return n 367 } 368 369 // GraphNodeDestroy impl. 370 func (n *graphNodeOrphanResourceFlat) CreateBeforeDestroy() bool { 371 return false 372 } 373 374 func (n *graphNodeOrphanResourceFlat) CreateNode() dag.Vertex { 375 return n 376 } 377 378 func (n *graphNodeOrphanResourceFlat) ProvidedBy() []string { 379 return modulePrefixList( 380 n.graphNodeOrphanResource.ProvidedBy(), 381 modulePrefixStr(n.PathValue)) 382 }