github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/terraform/transform_config.go (about) 1 package terraform 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "sync" 8 9 "github.com/hashicorp/terraform/config" 10 "github.com/hashicorp/terraform/config/module" 11 "github.com/hashicorp/terraform/dag" 12 ) 13 14 // ConfigTransformer is a GraphTransformer that adds all the resources 15 // from the configuration to the graph. 16 // 17 // The module used to configure this transformer must be the root module. 18 // 19 // Only resources are added to the graph. Variables, outputs, and 20 // providers must be added via other transforms. 21 // 22 // Unlike ConfigTransformerOld, this transformer creates a graph with 23 // all resources including module resources, rather than creating module 24 // nodes that are then "flattened". 25 type ConfigTransformer struct { 26 Concrete ConcreteResourceNodeFunc 27 28 // Module is the module to add resources from. 29 Module *module.Tree 30 31 // Unique will only add resources that aren't already present in the graph. 32 Unique bool 33 34 // Mode will only add resources that match the given mode 35 ModeFilter bool 36 Mode config.ResourceMode 37 38 l sync.Mutex 39 uniqueMap map[string]struct{} 40 } 41 42 func (t *ConfigTransformer) Transform(g *Graph) error { 43 // Lock since we use some internal state 44 t.l.Lock() 45 defer t.l.Unlock() 46 47 // If no module is given, we don't do anything 48 if t.Module == nil { 49 return nil 50 } 51 52 // If the module isn't loaded, that is simply an error 53 if !t.Module.Loaded() { 54 return errors.New("module must be loaded for ConfigTransformer") 55 } 56 57 // Reset the uniqueness map. If we're tracking uniques, then populate 58 // it with addresses. 59 t.uniqueMap = make(map[string]struct{}) 60 defer func() { t.uniqueMap = nil }() 61 if t.Unique { 62 for _, v := range g.Vertices() { 63 if rn, ok := v.(GraphNodeResource); ok { 64 t.uniqueMap[rn.ResourceAddr().String()] = struct{}{} 65 } 66 } 67 } 68 69 // Start the transformation process 70 return t.transform(g, t.Module) 71 } 72 73 func (t *ConfigTransformer) transform(g *Graph, m *module.Tree) error { 74 // If no config, do nothing 75 if m == nil { 76 return nil 77 } 78 79 // Add our resources 80 if err := t.transformSingle(g, m); err != nil { 81 return err 82 } 83 84 // Transform all the children. 85 for _, c := range m.Children() { 86 if err := t.transform(g, c); err != nil { 87 return err 88 } 89 } 90 91 return nil 92 } 93 94 func (t *ConfigTransformer) transformSingle(g *Graph, m *module.Tree) error { 95 log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", m.Path()) 96 97 // Get the configuration for this module 98 conf := m.Config() 99 100 // Build the path we're at 101 path := m.Path() 102 103 // Write all the resources out 104 for _, r := range conf.Resources { 105 // Build the resource address 106 addr, err := parseResourceAddressConfig(r) 107 if err != nil { 108 panic(fmt.Sprintf( 109 "Error parsing config address, this is a bug: %#v", r)) 110 } 111 addr.Path = path 112 113 // If this is already in our uniqueness map, don't add it again 114 if _, ok := t.uniqueMap[addr.String()]; ok { 115 continue 116 } 117 118 // Remove non-matching modes 119 if t.ModeFilter && addr.Mode != t.Mode { 120 continue 121 } 122 123 // Build the abstract node and the concrete one 124 abstract := &NodeAbstractResource{Addr: addr} 125 var node dag.Vertex = abstract 126 if f := t.Concrete; f != nil { 127 node = f(abstract) 128 } 129 130 // Add it to the graph 131 g.Add(node) 132 } 133 134 return nil 135 }