github.com/hugorut/terraform@v1.1.3/src/terraform/transform_module_expansion.go (about) 1 package terraform 2 3 import ( 4 "log" 5 6 "github.com/hugorut/terraform/src/addrs" 7 "github.com/hugorut/terraform/src/configs" 8 "github.com/hugorut/terraform/src/dag" 9 ) 10 11 // ModuleExpansionTransformer is a GraphTransformer that adds graph nodes 12 // representing the possible expansion of each module call in the configuration, 13 // and ensures that any nodes representing objects declared within a module 14 // are dependent on the expansion node so that they will be visited only 15 // after the module expansion has been decided. 16 // 17 // This transform must be applied only after all nodes representing objects 18 // that can be contained within modules have already been added. 19 type ModuleExpansionTransformer struct { 20 Config *configs.Config 21 22 // Concrete allows injection of a wrapped module node by the graph builder 23 // to alter the evaluation behavior. 24 Concrete ConcreteModuleNodeFunc 25 26 closers map[string]*nodeCloseModule 27 } 28 29 func (t *ModuleExpansionTransformer) Transform(g *Graph) error { 30 t.closers = make(map[string]*nodeCloseModule) 31 // The root module is always a singleton and so does not need expansion 32 // processing, but any descendent modules do. We'll process them 33 // recursively using t.transform. 34 for _, cfg := range t.Config.Children { 35 err := t.transform(g, cfg, nil) 36 if err != nil { 37 return err 38 } 39 } 40 41 // Now go through and connect all nodes to their respective module closers. 42 // This is done all at once here, because orphaned modules were already 43 // handled by the RemovedModuleTransformer, and those module closers are in 44 // the graph already, and need to be connected to their parent closers. 45 for _, v := range g.Vertices() { 46 switch v.(type) { 47 case GraphNodeDestroyer: 48 // Destroy nodes can only be ordered relative to other resource 49 // instances. 50 continue 51 case *nodeCloseModule: 52 // a module closer cannot connect to itself 53 continue 54 } 55 56 // any node that executes within the scope of a module should be a 57 // GraphNodeModulePath 58 pather, ok := v.(GraphNodeModulePath) 59 if !ok { 60 continue 61 } 62 if closer, ok := t.closers[pather.ModulePath().String()]; ok { 63 // The module closer depends on each child resource instance, since 64 // during apply the module expansion will complete before the 65 // individual instances are applied. 66 g.Connect(dag.BasicEdge(closer, v)) 67 } 68 } 69 70 // Modules implicitly depend on their child modules, so connect closers to 71 // other which contain their path. 72 for _, c := range t.closers { 73 for _, d := range t.closers { 74 if len(d.Addr) > len(c.Addr) && c.Addr.Equal(d.Addr[:len(c.Addr)]) { 75 g.Connect(dag.BasicEdge(c, d)) 76 } 77 } 78 } 79 80 return nil 81 } 82 83 func (t *ModuleExpansionTransformer) transform(g *Graph, c *configs.Config, parentNode dag.Vertex) error { 84 _, call := c.Path.Call() 85 modCall := c.Parent.Module.ModuleCalls[call.Name] 86 87 n := &nodeExpandModule{ 88 Addr: c.Path, 89 Config: c.Module, 90 ModuleCall: modCall, 91 } 92 var expander dag.Vertex = n 93 if t.Concrete != nil { 94 expander = t.Concrete(n) 95 } 96 97 g.Add(expander) 98 log.Printf("[TRACE] ModuleExpansionTransformer: Added %s as %T", c.Path, expander) 99 100 if parentNode != nil { 101 log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(expander), dag.VertexName(parentNode)) 102 g.Connect(dag.BasicEdge(expander, parentNode)) 103 } 104 105 // Add the closer (which acts as the root module node) to provide a 106 // single exit point for the expanded module. 107 closer := &nodeCloseModule{ 108 Addr: c.Path, 109 } 110 g.Add(closer) 111 g.Connect(dag.BasicEdge(closer, expander)) 112 t.closers[c.Path.String()] = closer 113 114 for _, childV := range g.Vertices() { 115 // don't connect a node to itself 116 if childV == expander { 117 continue 118 } 119 120 var path addrs.Module 121 switch t := childV.(type) { 122 case GraphNodeDestroyer: 123 // skip destroyers, as they can only depend on other resources. 124 continue 125 126 case GraphNodeModulePath: 127 path = t.ModulePath() 128 default: 129 continue 130 } 131 132 if path.Equal(c.Path) { 133 log.Printf("[TRACE] ModuleExpansionTransformer: %s must wait for expansion of %s", dag.VertexName(childV), c.Path) 134 g.Connect(dag.BasicEdge(childV, expander)) 135 } 136 } 137 138 // Also visit child modules, recursively. 139 for _, cc := range c.Children { 140 if err := t.transform(g, cc, expander); err != nil { 141 return err 142 } 143 } 144 145 return nil 146 }