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