github.com/bendemaree/terraform@v0.5.4-0.20150613200311-f50d97d6eee6/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) Flatten(p []string) (dag.Vertex, error) { 180 return &graphNodeOrphanResourceFlat{ 181 graphNodeOrphanResource: n, 182 PathValue: p, 183 }, nil 184 } 185 186 func (n *graphNodeOrphanResource) Name() string { 187 return fmt.Sprintf("%s (orphan)", n.ResourceName) 188 } 189 190 func (n *graphNodeOrphanResource) ProvidedBy() []string { 191 return []string{resourceProvider(n.ResourceName, n.Provider)} 192 } 193 194 // GraphNodeEvalable impl. 195 func (n *graphNodeOrphanResource) EvalTree() EvalNode { 196 var provider ResourceProvider 197 var state *InstanceState 198 199 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 200 201 // Build instance info 202 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 203 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 204 205 // Refresh the resource 206 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 207 Ops: []walkOperation{walkRefresh}, 208 Node: &EvalSequence{ 209 Nodes: []EvalNode{ 210 &EvalGetProvider{ 211 Name: n.ProvidedBy()[0], 212 Output: &provider, 213 }, 214 &EvalReadState{ 215 Name: n.ResourceName, 216 Output: &state, 217 }, 218 &EvalRefresh{ 219 Info: info, 220 Provider: &provider, 221 State: &state, 222 Output: &state, 223 }, 224 &EvalWriteState{ 225 Name: n.ResourceName, 226 ResourceType: n.ResourceType, 227 Provider: n.Provider, 228 Dependencies: n.DependentOn(), 229 State: &state, 230 }, 231 }, 232 }, 233 }) 234 235 // Diff the resource 236 var diff *InstanceDiff 237 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 238 Ops: []walkOperation{walkPlan, walkPlanDestroy}, 239 Node: &EvalSequence{ 240 Nodes: []EvalNode{ 241 &EvalReadState{ 242 Name: n.ResourceName, 243 Output: &state, 244 }, 245 &EvalDiffDestroy{ 246 Info: info, 247 State: &state, 248 Output: &diff, 249 }, 250 &EvalWriteDiff{ 251 Name: n.ResourceName, 252 Diff: &diff, 253 }, 254 }, 255 }, 256 }) 257 258 // Apply 259 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 260 Ops: []walkOperation{walkApply}, 261 Node: &EvalSequence{ 262 Nodes: []EvalNode{ 263 &EvalReadDiff{ 264 Name: n.ResourceName, 265 Diff: &diff, 266 }, 267 &EvalGetProvider{ 268 Name: n.ProvidedBy()[0], 269 Output: &provider, 270 }, 271 &EvalReadState{ 272 Name: n.ResourceName, 273 Output: &state, 274 }, 275 &EvalApply{ 276 Info: info, 277 State: &state, 278 Diff: &diff, 279 Provider: &provider, 280 Output: &state, 281 }, 282 &EvalWriteState{ 283 Name: n.ResourceName, 284 ResourceType: n.ResourceType, 285 Provider: n.Provider, 286 Dependencies: n.DependentOn(), 287 State: &state, 288 }, 289 &EvalUpdateStateHook{}, 290 }, 291 }, 292 }) 293 294 return seq 295 } 296 297 func (n *graphNodeOrphanResource) dependableName() string { 298 return n.ResourceName 299 } 300 301 // Same as graphNodeOrphanResource, but for flattening 302 type graphNodeOrphanResourceFlat struct { 303 *graphNodeOrphanResource 304 305 PathValue []string 306 } 307 308 func (n *graphNodeOrphanResourceFlat) Name() string { 309 return fmt.Sprintf( 310 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeOrphanResource.Name()) 311 } 312 313 func (n *graphNodeOrphanResourceFlat) Path() []string { 314 return n.PathValue 315 }