]>
Commit | Line | Data |
---|---|---|
bae9f6d2 JC |
1 | package terraform |
2 | ||
3 | import ( | |
bae9f6d2 JC |
4 | "log" |
5 | "sync" | |
6 | ||
107c1cdb ND |
7 | "github.com/hashicorp/terraform/addrs" |
8 | "github.com/hashicorp/terraform/configs" | |
bae9f6d2 JC |
9 | "github.com/hashicorp/terraform/dag" |
10 | ) | |
11 | ||
12 | // ConfigTransformer is a GraphTransformer that adds all the resources | |
13 | // from the configuration to the graph. | |
14 | // | |
15 | // The module used to configure this transformer must be the root module. | |
16 | // | |
17 | // Only resources are added to the graph. Variables, outputs, and | |
18 | // providers must be added via other transforms. | |
19 | // | |
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 | |
25 | ||
26 | // Module is the module to add resources from. | |
107c1cdb | 27 | Config *configs.Config |
bae9f6d2 JC |
28 | |
29 | // Unique will only add resources that aren't already present in the graph. | |
30 | Unique bool | |
31 | ||
32 | // Mode will only add resources that match the given mode | |
33 | ModeFilter bool | |
107c1cdb | 34 | Mode addrs.ResourceMode |
bae9f6d2 JC |
35 | |
36 | l sync.Mutex | |
37 | uniqueMap map[string]struct{} | |
38 | } | |
39 | ||
40 | func (t *ConfigTransformer) Transform(g *Graph) error { | |
41 | // Lock since we use some internal state | |
42 | t.l.Lock() | |
43 | defer t.l.Unlock() | |
44 | ||
107c1cdb ND |
45 | // If no configuration is available, we don't do anything |
46 | if t.Config == nil { | |
bae9f6d2 JC |
47 | return nil |
48 | } | |
49 | ||
bae9f6d2 JC |
50 | // Reset the uniqueness map. If we're tracking uniques, then populate |
51 | // it with addresses. | |
52 | t.uniqueMap = make(map[string]struct{}) | |
53 | defer func() { t.uniqueMap = nil }() | |
54 | if t.Unique { | |
55 | for _, v := range g.Vertices() { | |
56 | if rn, ok := v.(GraphNodeResource); ok { | |
57 | t.uniqueMap[rn.ResourceAddr().String()] = struct{}{} | |
58 | } | |
59 | } | |
60 | } | |
61 | ||
62 | // Start the transformation process | |
107c1cdb | 63 | return t.transform(g, t.Config) |
bae9f6d2 JC |
64 | } |
65 | ||
107c1cdb | 66 | func (t *ConfigTransformer) transform(g *Graph, config *configs.Config) error { |
bae9f6d2 | 67 | // If no config, do nothing |
107c1cdb | 68 | if config == nil { |
bae9f6d2 JC |
69 | return nil |
70 | } | |
71 | ||
72 | // Add our resources | |
107c1cdb | 73 | if err := t.transformSingle(g, config); err != nil { |
bae9f6d2 JC |
74 | return err |
75 | } | |
76 | ||
77 | // Transform all the children. | |
107c1cdb | 78 | for _, c := range config.Children { |
bae9f6d2 JC |
79 | if err := t.transform(g, c); err != nil { |
80 | return err | |
81 | } | |
82 | } | |
83 | ||
84 | return nil | |
85 | } | |
86 | ||
107c1cdb ND |
87 | func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) error { |
88 | path := config.Path | |
89 | module := config.Module | |
90 | log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path) | |
91 | ||
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" | |
94 | // on modules. | |
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() | |
99 | ||
100 | allResources := make([]*configs.Resource, 0, len(module.ManagedResources)+len(module.DataResources)) | |
101 | for _, r := range module.ManagedResources { | |
102 | allResources = append(allResources, r) | |
103 | } | |
104 | for _, r := range module.DataResources { | |
105 | allResources = append(allResources, r) | |
106 | } | |
bae9f6d2 | 107 | |
107c1cdb ND |
108 | for _, r := range allResources { |
109 | relAddr := r.Addr() | |
bae9f6d2 | 110 | |
107c1cdb ND |
111 | if t.ModeFilter && relAddr.Mode != t.Mode { |
112 | // Skip non-matching modes | |
bae9f6d2 JC |
113 | continue |
114 | } | |
115 | ||
107c1cdb ND |
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. | |
bae9f6d2 JC |
120 | continue |
121 | } | |
122 | ||
bae9f6d2 JC |
123 | abstract := &NodeAbstractResource{Addr: addr} |
124 | var node dag.Vertex = abstract | |
125 | if f := t.Concrete; f != nil { | |
126 | node = f(abstract) | |
127 | } | |
128 | ||
bae9f6d2 JC |
129 | g.Add(node) |
130 | } | |
131 | ||
132 | return nil | |
133 | } |