github.com/atsaki/terraform@v0.4.3-0.20150919165407-25bba5967654/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 var deps []string 104 if s := t.State.ModuleByPath(path); s != nil { 105 deps = s.Dependencies 106 } 107 108 moduleVertexes[i] = g.Add(&graphNodeOrphanModule{ 109 Path: path, 110 dependentOn: deps, 111 }) 112 } 113 114 // Now do the dependencies. We do this _after_ adding all the orphan 115 // nodes above because there are cases in which the orphans themselves 116 // depend on other orphans. 117 118 // Resource dependencies 119 for _, v := range resourceVertexes { 120 g.ConnectDependent(v) 121 } 122 123 // Module dependencies 124 for _, v := range moduleVertexes { 125 g.ConnectDependent(v) 126 } 127 128 return nil 129 } 130 131 // graphNodeOrphanModule is the graph vertex representing an orphan resource.. 132 type graphNodeOrphanModule struct { 133 Path []string 134 135 dependentOn []string 136 } 137 138 func (n *graphNodeOrphanModule) DependableName() []string { 139 return []string{n.dependableName()} 140 } 141 142 func (n *graphNodeOrphanModule) DependentOn() []string { 143 return n.dependentOn 144 } 145 146 func (n *graphNodeOrphanModule) Name() string { 147 return fmt.Sprintf("%s (orphan)", n.dependableName()) 148 } 149 150 func (n *graphNodeOrphanModule) dependableName() string { 151 return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1]) 152 } 153 154 // GraphNodeExpandable 155 func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) { 156 g, err := b.Build(n.Path) 157 if err != nil { 158 return nil, err 159 } 160 161 return &GraphNodeBasicSubgraph{ 162 NameValue: n.Name(), 163 Graph: g, 164 }, nil 165 } 166 167 // graphNodeOrphanResource is the graph vertex representing an orphan resource.. 168 type graphNodeOrphanResource struct { 169 ResourceName string 170 ResourceType string 171 Provider string 172 173 dependentOn []string 174 } 175 176 func (n *graphNodeOrphanResource) DependableName() []string { 177 return []string{n.dependableName()} 178 } 179 180 func (n *graphNodeOrphanResource) DependentOn() []string { 181 return n.dependentOn 182 } 183 184 func (n *graphNodeOrphanResource) Flatten(p []string) (dag.Vertex, error) { 185 return &graphNodeOrphanResourceFlat{ 186 graphNodeOrphanResource: n, 187 PathValue: p, 188 }, nil 189 } 190 191 func (n *graphNodeOrphanResource) Name() string { 192 return fmt.Sprintf("%s (orphan)", n.ResourceName) 193 } 194 195 func (n *graphNodeOrphanResource) ProvidedBy() []string { 196 return []string{resourceProvider(n.ResourceName, n.Provider)} 197 } 198 199 // GraphNodeEvalable impl. 200 func (n *graphNodeOrphanResource) EvalTree() EvalNode { 201 var provider ResourceProvider 202 var state *InstanceState 203 204 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 205 206 // Build instance info 207 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 208 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 209 210 // Refresh the resource 211 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 212 Ops: []walkOperation{walkRefresh}, 213 Node: &EvalSequence{ 214 Nodes: []EvalNode{ 215 &EvalGetProvider{ 216 Name: n.ProvidedBy()[0], 217 Output: &provider, 218 }, 219 &EvalReadState{ 220 Name: n.ResourceName, 221 Output: &state, 222 }, 223 &EvalRefresh{ 224 Info: info, 225 Provider: &provider, 226 State: &state, 227 Output: &state, 228 }, 229 &EvalWriteState{ 230 Name: n.ResourceName, 231 ResourceType: n.ResourceType, 232 Provider: n.Provider, 233 Dependencies: n.DependentOn(), 234 State: &state, 235 }, 236 }, 237 }, 238 }) 239 240 // Diff the resource 241 var diff *InstanceDiff 242 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 243 Ops: []walkOperation{walkPlan, walkPlanDestroy}, 244 Node: &EvalSequence{ 245 Nodes: []EvalNode{ 246 &EvalReadState{ 247 Name: n.ResourceName, 248 Output: &state, 249 }, 250 &EvalDiffDestroy{ 251 Info: info, 252 State: &state, 253 Output: &diff, 254 }, 255 &EvalWriteDiff{ 256 Name: n.ResourceName, 257 Diff: &diff, 258 }, 259 }, 260 }, 261 }) 262 263 // Apply 264 var err error 265 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 266 Ops: []walkOperation{walkApply}, 267 Node: &EvalSequence{ 268 Nodes: []EvalNode{ 269 &EvalReadDiff{ 270 Name: n.ResourceName, 271 Diff: &diff, 272 }, 273 &EvalGetProvider{ 274 Name: n.ProvidedBy()[0], 275 Output: &provider, 276 }, 277 &EvalReadState{ 278 Name: n.ResourceName, 279 Output: &state, 280 }, 281 &EvalApply{ 282 Info: info, 283 State: &state, 284 Diff: &diff, 285 Provider: &provider, 286 Output: &state, 287 Error: &err, 288 }, 289 &EvalWriteState{ 290 Name: n.ResourceName, 291 ResourceType: n.ResourceType, 292 Provider: n.Provider, 293 Dependencies: n.DependentOn(), 294 State: &state, 295 }, 296 &EvalApplyPost{ 297 Info: info, 298 State: &state, 299 Error: &err, 300 }, 301 &EvalUpdateStateHook{}, 302 }, 303 }, 304 }) 305 306 return seq 307 } 308 309 func (n *graphNodeOrphanResource) dependableName() string { 310 return n.ResourceName 311 } 312 313 // GraphNodeDestroyable impl. 314 func (n *graphNodeOrphanResource) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy { 315 if mode != DestroyPrimary { 316 return nil 317 } 318 319 return n 320 } 321 322 // GraphNodeDestroy impl. 323 func (n *graphNodeOrphanResource) CreateBeforeDestroy() bool { 324 return false 325 } 326 327 func (n *graphNodeOrphanResource) CreateNode() dag.Vertex { 328 return n 329 } 330 331 // Same as graphNodeOrphanResource, but for flattening 332 type graphNodeOrphanResourceFlat struct { 333 *graphNodeOrphanResource 334 335 PathValue []string 336 } 337 338 func (n *graphNodeOrphanResourceFlat) Name() string { 339 return fmt.Sprintf( 340 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeOrphanResource.Name()) 341 } 342 343 func (n *graphNodeOrphanResourceFlat) Path() []string { 344 return n.PathValue 345 } 346 347 // GraphNodeDestroyable impl. 348 func (n *graphNodeOrphanResourceFlat) DestroyNode(mode GraphNodeDestroyMode) GraphNodeDestroy { 349 if mode != DestroyPrimary { 350 return nil 351 } 352 353 return n 354 } 355 356 // GraphNodeDestroy impl. 357 func (n *graphNodeOrphanResourceFlat) CreateBeforeDestroy() bool { 358 return false 359 } 360 361 func (n *graphNodeOrphanResourceFlat) CreateNode() dag.Vertex { 362 return n 363 } 364 365 func (n *graphNodeOrphanResourceFlat) ProvidedBy() []string { 366 return modulePrefixList( 367 n.graphNodeOrphanResource.ProvidedBy(), 368 modulePrefixStr(n.PathValue)) 369 }