7 "github.com/hashicorp/terraform/addrs"
8 "github.com/hashicorp/terraform/configs"
9 "github.com/hashicorp/terraform/dag"
12 // ConfigTransformer is a GraphTransformer that adds all the resources
13 // from the configuration to the graph.
15 // The module used to configure this transformer must be the root module.
17 // Only resources are added to the graph. Variables, outputs, and
18 // providers must be added via other transforms.
20 // Unlike ConfigTransformerOld, this transformer creates a graph with
21 // all resources including module resources, rather than creating module
22 // nodes that are then "flattened".
23 type ConfigTransformer struct {
24 Concrete ConcreteResourceNodeFunc
26 // Module is the module to add resources from.
27 Config *configs.Config
29 // Unique will only add resources that aren't already present in the graph.
32 // Mode will only add resources that match the given mode
34 Mode addrs.ResourceMode
37 uniqueMap map[string]struct{}
40 func (t *ConfigTransformer) Transform(g *Graph) error {
41 // Lock since we use some internal state
45 // If no configuration is available, we don't do anything
50 // Reset the uniqueness map. If we're tracking uniques, then populate
52 t.uniqueMap = make(map[string]struct{})
53 defer func() { t.uniqueMap = nil }()
55 for _, v := range g.Vertices() {
56 if rn, ok := v.(GraphNodeResource); ok {
57 t.uniqueMap[rn.ResourceAddr().String()] = struct{}{}
62 // Start the transformation process
63 return t.transform(g, t.Config)
66 func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error {
67 // If no config, do nothing
73 if err := t.transformSingle(g, config); err != nil {
77 // Transform all the children.
78 for _, c := range config.Children {
79 if err := t.transform(g, c); err != nil {
87 func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error {
89 module := config.Module
90 log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
92 // For now we assume that each module call produces only one module
93 // instance with no key, since we don't yet support "count" and "for_each"
95 // FIXME: As part of supporting "count" and "for_each" on modules, rework
96 // this so that we'll "expand" the module call first and then create graph
97 // nodes for each module instance separately.
98 instPath := path.UnkeyedInstanceShim()
100 allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources))
101 for _, r := range module.ManagedResources {
102 allResources = append(allResources, r)
104 for _, r := range module.DataResources {
105 allResources = append(allResources, r)
108 for _, r := range allResources {
111 if t.ModeFilter && relAddr.Mode != t.Mode {
112 // Skip non-matching modes
116 addr := relAddr.Absolute(instPath)
117 if _, ok := t.uniqueMap[addr.String()]; ok {
118 // We've already seen a resource with this address. This should
119 // never happen, because we enforce uniqueness in the config loader.
123 abstract := &NodeAbstractResource{Addr: addr}
124 var node dag.Vertex = abstract
125 if f := t.Concrete; f != nil {