github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/terraform/graph.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "runtime/debug" 7 "strings" 8 "sync" 9 10 "github.com/hashicorp/terraform/dag" 11 ) 12 13 // RootModuleName is the name given to the root module implicitly. 14 const RootModuleName = "root" 15 16 // RootModulePath is the path for the root module. 17 var RootModulePath = []string{RootModuleName} 18 19 // Graph represents the graph that Terraform uses to represent resources 20 // and their dependencies. Each graph represents only one module, but it 21 // can contain further modules, which themselves have their own graph. 22 type Graph struct { 23 // Graph is the actual DAG. This is embedded so you can call the DAG 24 // methods directly. 25 dag.AcyclicGraph 26 27 // Path is the path in the module tree that this Graph represents. 28 // The root is represented by a single element list containing 29 // RootModuleName 30 Path []string 31 32 // annotations are the annotations that are added to vertices. Annotations 33 // are arbitrary metadata taht is used for various logic. Annotations 34 // should have unique keys that are referenced via constants. 35 annotations map[dag.Vertex]map[string]interface{} 36 37 // dependableMap is a lookaside table for fast lookups for connecting 38 // dependencies by their GraphNodeDependable value to avoid O(n^3)-like 39 // situations and turn them into O(1) with respect to the number of new 40 // edges. 41 dependableMap map[string]dag.Vertex 42 43 once sync.Once 44 } 45 46 // Annotations returns the annotations that are configured for the 47 // given vertex. The map is guaranteed to be non-nil but may be empty. 48 // 49 // The returned map may be modified to modify the annotations of the 50 // vertex. 51 func (g *Graph) Annotations(v dag.Vertex) map[string]interface{} { 52 g.once.Do(g.init) 53 54 // If this vertex isn't in the graph, then just return an empty map 55 if !g.HasVertex(v) { 56 return map[string]interface{}{} 57 } 58 59 // Get the map, if it doesn't exist yet then initialize it 60 m, ok := g.annotations[v] 61 if !ok { 62 m = make(map[string]interface{}) 63 g.annotations[v] = m 64 } 65 66 return m 67 } 68 69 // Add is the same as dag.Graph.Add. 70 func (g *Graph) Add(v dag.Vertex) dag.Vertex { 71 g.once.Do(g.init) 72 73 // Call upwards to add it to the actual graph 74 g.Graph.Add(v) 75 76 // If this is a depend-able node, then store the lookaside info 77 if dv, ok := v.(GraphNodeDependable); ok { 78 for _, n := range dv.DependableName() { 79 g.dependableMap[n] = v 80 } 81 } 82 83 // If this initializes annotations, then do that 84 if av, ok := v.(GraphNodeAnnotationInit); ok { 85 as := g.Annotations(v) 86 for k, v := range av.AnnotationInit() { 87 as[k] = v 88 } 89 } 90 91 return v 92 } 93 94 // Remove is the same as dag.Graph.Remove 95 func (g *Graph) Remove(v dag.Vertex) dag.Vertex { 96 g.once.Do(g.init) 97 98 // If this is a depend-able node, then remove the lookaside info 99 if dv, ok := v.(GraphNodeDependable); ok { 100 for _, n := range dv.DependableName() { 101 delete(g.dependableMap, n) 102 } 103 } 104 105 // Remove the annotations 106 delete(g.annotations, v) 107 108 // Call upwards to remove it from the actual graph 109 return g.Graph.Remove(v) 110 } 111 112 // Replace is the same as dag.Graph.Replace 113 func (g *Graph) Replace(o, n dag.Vertex) bool { 114 g.once.Do(g.init) 115 116 // Go through and update our lookaside to point to the new vertex 117 for k, v := range g.dependableMap { 118 if v == o { 119 if _, ok := n.(GraphNodeDependable); ok { 120 g.dependableMap[k] = n 121 } else { 122 delete(g.dependableMap, k) 123 } 124 } 125 } 126 127 // Move the annotation if it exists 128 if m, ok := g.annotations[o]; ok { 129 g.annotations[n] = m 130 delete(g.annotations, o) 131 } 132 133 return g.Graph.Replace(o, n) 134 } 135 136 // ConnectDependent connects a GraphNodeDependent to all of its 137 // GraphNodeDependables. It returns the list of dependents it was 138 // unable to connect to. 139 func (g *Graph) ConnectDependent(raw dag.Vertex) []string { 140 v, ok := raw.(GraphNodeDependent) 141 if !ok { 142 return nil 143 } 144 145 return g.ConnectTo(v, v.DependentOn()) 146 } 147 148 // ConnectDependents goes through the graph, connecting all the 149 // GraphNodeDependents to GraphNodeDependables. This is safe to call 150 // multiple times. 151 // 152 // To get details on whether dependencies could be found/made, the more 153 // specific ConnectDependent should be used. 154 func (g *Graph) ConnectDependents() { 155 for _, v := range g.Vertices() { 156 if dv, ok := v.(GraphNodeDependent); ok { 157 g.ConnectDependent(dv) 158 } 159 } 160 } 161 162 // ConnectFrom creates an edge by finding the source from a DependableName 163 // and connecting it to the specific vertex. 164 func (g *Graph) ConnectFrom(source string, target dag.Vertex) { 165 g.once.Do(g.init) 166 167 if source := g.dependableMap[source]; source != nil { 168 g.Connect(dag.BasicEdge(source, target)) 169 } 170 } 171 172 // ConnectTo connects a vertex to a raw string of targets that are the 173 // result of DependableName, and returns the list of targets that are missing. 174 func (g *Graph) ConnectTo(v dag.Vertex, targets []string) []string { 175 g.once.Do(g.init) 176 177 var missing []string 178 for _, t := range targets { 179 if dest := g.dependableMap[t]; dest != nil { 180 g.Connect(dag.BasicEdge(v, dest)) 181 } else { 182 missing = append(missing, t) 183 } 184 } 185 186 return missing 187 } 188 189 // Dependable finds the vertices in the graph that have the given dependable 190 // names and returns them. 191 func (g *Graph) Dependable(n string) dag.Vertex { 192 // TODO: do we need this? 193 return nil 194 } 195 196 // Walk walks the graph with the given walker for callbacks. The graph 197 // will be walked with full parallelism, so the walker should expect 198 // to be called in concurrently. 199 func (g *Graph) Walk(walker GraphWalker) error { 200 defer dbug.WriteGraph(walker.Debug()) 201 return g.walk(walker) 202 } 203 204 func (g *Graph) init() { 205 if g.annotations == nil { 206 g.annotations = make(map[dag.Vertex]map[string]interface{}) 207 } 208 209 if g.dependableMap == nil { 210 g.dependableMap = make(map[string]dag.Vertex) 211 } 212 } 213 214 func (g *Graph) walk(walker GraphWalker) error { 215 // The callbacks for enter/exiting a graph 216 ctx := walker.EnterPath(g.Path) 217 defer walker.ExitPath(g.Path) 218 219 // Get the path for logs 220 path := strings.Join(ctx.Path(), ".") 221 222 // Determine if our walker is a panic wrapper 223 panicwrap, ok := walker.(GraphWalkerPanicwrapper) 224 if !ok { 225 panicwrap = nil // just to be sure 226 } 227 228 // Walk the graph. 229 var walkFn dag.WalkFunc 230 walkFn = func(v dag.Vertex) (rerr error) { 231 log.Printf("[DEBUG] vertex '%s.%s': walking", path, dag.VertexName(v)) 232 233 // If we have a panic wrap GraphWalker and a panic occurs, recover 234 // and call that. We ensure the return value is an error, however, 235 // so that future nodes are not called. 236 defer func() { 237 // If no panicwrap, do nothing 238 if panicwrap == nil { 239 return 240 } 241 242 // If no panic, do nothing 243 err := recover() 244 if err == nil { 245 return 246 } 247 248 // Modify the return value to show the error 249 rerr = fmt.Errorf("vertex %q captured panic: %s\n\n%s", 250 dag.VertexName(v), err, debug.Stack()) 251 252 // Call the panic wrapper 253 panicwrap.Panic(v, err) 254 }() 255 256 walker.EnterVertex(v) 257 defer func() { 258 walker.Debug().DebugNode(v) 259 walker.ExitVertex(v, rerr) 260 }() 261 262 // vertexCtx is the context that we use when evaluating. This 263 // is normally the context of our graph but can be overridden 264 // with a GraphNodeSubPath impl. 265 vertexCtx := ctx 266 if pn, ok := v.(GraphNodeSubPath); ok && len(pn.Path()) > 0 { 267 vertexCtx = walker.EnterPath(normalizeModulePath(pn.Path())) 268 defer walker.ExitPath(pn.Path()) 269 } 270 271 // If the node is eval-able, then evaluate it. 272 if ev, ok := v.(GraphNodeEvalable); ok { 273 tree := ev.EvalTree() 274 if tree == nil { 275 panic(fmt.Sprintf( 276 "%s.%s (%T): nil eval tree", path, dag.VertexName(v), v)) 277 } 278 279 // Allow the walker to change our tree if needed. Eval, 280 // then callback with the output. 281 log.Printf("[DEBUG] vertex '%s.%s': evaluating", path, dag.VertexName(v)) 282 walker.Debug().Printf("[DEBUG] vertex %T(%s.%s): evaluating\n", v, path, dag.VertexName(v)) 283 tree = walker.EnterEvalTree(v, tree) 284 output, err := Eval(tree, vertexCtx) 285 if rerr = walker.ExitEvalTree(v, output, err); rerr != nil { 286 return 287 } 288 } 289 290 // If the node is dynamically expanded, then expand it 291 if ev, ok := v.(GraphNodeDynamicExpandable); ok { 292 log.Printf( 293 "[DEBUG] vertex '%s.%s': expanding/walking dynamic subgraph", 294 path, 295 dag.VertexName(v)) 296 walker.Debug().Printf("[DEBUG] vertex %T(%s.%s): expanding\n", v, path, dag.VertexName(v)) 297 g, err := ev.DynamicExpand(vertexCtx) 298 if err != nil { 299 rerr = err 300 return 301 } 302 if g != nil { 303 // Walk the subgraph 304 if rerr = g.walk(walker); rerr != nil { 305 return 306 } 307 } 308 } 309 310 // If the node has a subgraph, then walk the subgraph 311 if sn, ok := v.(GraphNodeSubgraph); ok { 312 log.Printf( 313 "[DEBUG] vertex '%s.%s': walking subgraph", 314 path, 315 dag.VertexName(v)) 316 317 walker.Debug().Printf( 318 "[DEBUG] vertex %T(%s.%s): subgraph\n", v, path, dag.VertexName(v)) 319 320 if rerr = sn.Subgraph().walk(walker); rerr != nil { 321 return 322 } 323 } 324 325 return nil 326 } 327 328 return g.AcyclicGraph.Walk(walkFn) 329 } 330 331 // GraphNodeAnnotationInit is an interface that allows a node to 332 // initialize it's annotations. 333 // 334 // AnnotationInit will be called _once_ when the node is added to a 335 // graph for the first time and is expected to return it's initial 336 // annotations. 337 type GraphNodeAnnotationInit interface { 338 AnnotationInit() map[string]interface{} 339 } 340 341 // GraphNodeDependable is an interface which says that a node can be 342 // depended on (an edge can be placed between this node and another) according 343 // to the well-known name returned by DependableName. 344 // 345 // DependableName can return multiple names it is known by. 346 type GraphNodeDependable interface { 347 DependableName() []string 348 } 349 350 // GraphNodeDependent is an interface which says that a node depends 351 // on another GraphNodeDependable by some name. By implementing this 352 // interface, Graph.ConnectDependents() can be called multiple times 353 // safely and efficiently. 354 type GraphNodeDependent interface { 355 DependentOn() []string 356 }