github.com/tarrant/terraform@v0.3.8-0.20150402012457-f68c9eee638e/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 dependentOn: rs.Dependencies, 93 }) 94 } 95 } 96 97 // Go over each module orphan and add it to the graph. We store the 98 // vertexes and states outside so that we can connect dependencies later. 99 moduleOrphans := t.State.ModuleOrphans(g.Path, config) 100 moduleVertexes := make([]dag.Vertex, len(moduleOrphans)) 101 for i, path := range moduleOrphans { 102 moduleVertexes[i] = g.Add(&graphNodeOrphanModule{ 103 Path: path, 104 dependentOn: t.State.ModuleByPath(path).Dependencies, 105 }) 106 } 107 108 // Now do the dependencies. We do this _after_ adding all the orphan 109 // nodes above because there are cases in which the orphans themselves 110 // depend on other orphans. 111 112 // Resource dependencies 113 for _, v := range resourceVertexes { 114 g.ConnectDependent(v) 115 } 116 117 // Module dependencies 118 for _, v := range moduleVertexes { 119 g.ConnectDependent(v) 120 } 121 122 return nil 123 } 124 125 // graphNodeOrphanModule is the graph vertex representing an orphan resource.. 126 type graphNodeOrphanModule struct { 127 Path []string 128 129 dependentOn []string 130 } 131 132 func (n *graphNodeOrphanModule) DependableName() []string { 133 return []string{n.dependableName()} 134 } 135 136 func (n *graphNodeOrphanModule) DependentOn() []string { 137 return n.dependentOn 138 } 139 140 func (n *graphNodeOrphanModule) Name() string { 141 return fmt.Sprintf("%s (orphan)", n.dependableName()) 142 } 143 144 func (n *graphNodeOrphanModule) dependableName() string { 145 return fmt.Sprintf("module.%s", n.Path[len(n.Path)-1]) 146 } 147 148 // GraphNodeExpandable 149 func (n *graphNodeOrphanModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error) { 150 g, err := b.Build(n.Path) 151 if err != nil { 152 return nil, err 153 } 154 155 return &GraphNodeBasicSubgraph{ 156 NameValue: n.Name(), 157 Graph: g, 158 }, nil 159 } 160 161 // graphNodeOrphanResource is the graph vertex representing an orphan resource.. 162 type graphNodeOrphanResource struct { 163 ResourceName string 164 ResourceType string 165 166 dependentOn []string 167 } 168 169 func (n *graphNodeOrphanResource) DependableName() []string { 170 return []string{n.dependableName()} 171 } 172 173 func (n *graphNodeOrphanResource) DependentOn() []string { 174 return n.dependentOn 175 } 176 177 func (n *graphNodeOrphanResource) Name() string { 178 return fmt.Sprintf("%s (orphan)", n.ResourceName) 179 } 180 181 func (n *graphNodeOrphanResource) ProvidedBy() []string { 182 return []string{resourceProvider(n.ResourceName)} 183 } 184 185 // GraphNodeEvalable impl. 186 func (n *graphNodeOrphanResource) EvalTree() EvalNode { 187 var provider ResourceProvider 188 var state *InstanceState 189 190 seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)} 191 192 // Build instance info 193 info := &InstanceInfo{Id: n.ResourceName, Type: n.ResourceType} 194 seq.Nodes = append(seq.Nodes, &EvalInstanceInfo{Info: info}) 195 196 // Refresh the resource 197 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 198 Ops: []walkOperation{walkRefresh}, 199 Node: &EvalSequence{ 200 Nodes: []EvalNode{ 201 &EvalGetProvider{ 202 Name: n.ProvidedBy()[0], 203 Output: &provider, 204 }, 205 &EvalReadState{ 206 Name: n.ResourceName, 207 Output: &state, 208 }, 209 &EvalRefresh{ 210 Info: info, 211 Provider: &provider, 212 State: &state, 213 Output: &state, 214 }, 215 &EvalWriteState{ 216 Name: n.ResourceName, 217 ResourceType: n.ResourceType, 218 Dependencies: n.DependentOn(), 219 State: &state, 220 }, 221 }, 222 }, 223 }) 224 225 // Diff the resource 226 var diff *InstanceDiff 227 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 228 Ops: []walkOperation{walkPlan, walkPlanDestroy}, 229 Node: &EvalSequence{ 230 Nodes: []EvalNode{ 231 &EvalReadState{ 232 Name: n.ResourceName, 233 Output: &state, 234 }, 235 &EvalDiffDestroy{ 236 Info: info, 237 State: &state, 238 Output: &diff, 239 }, 240 &EvalWriteDiff{ 241 Name: n.ResourceName, 242 Diff: &diff, 243 }, 244 }, 245 }, 246 }) 247 248 // Apply 249 seq.Nodes = append(seq.Nodes, &EvalOpFilter{ 250 Ops: []walkOperation{walkApply}, 251 Node: &EvalSequence{ 252 Nodes: []EvalNode{ 253 &EvalReadDiff{ 254 Name: n.ResourceName, 255 Diff: &diff, 256 }, 257 &EvalGetProvider{ 258 Name: n.ProvidedBy()[0], 259 Output: &provider, 260 }, 261 &EvalReadState{ 262 Name: n.ResourceName, 263 Output: &state, 264 }, 265 &EvalApply{ 266 Info: info, 267 State: &state, 268 Diff: &diff, 269 Provider: &provider, 270 Output: &state, 271 }, 272 &EvalWriteState{ 273 Name: n.ResourceName, 274 ResourceType: n.ResourceType, 275 Dependencies: n.DependentOn(), 276 State: &state, 277 }, 278 &EvalUpdateStateHook{}, 279 }, 280 }, 281 }) 282 283 return seq 284 } 285 286 func (n *graphNodeOrphanResource) dependableName() string { 287 return n.ResourceName 288 }