diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/transform_provider.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/transform_provider.go | 574 |
1 files changed, 400 insertions, 174 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go b/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go index b9695d5..c4772b4 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go +++ b/vendor/github.com/hashicorp/terraform/terraform/transform_provider.go | |||
@@ -1,19 +1,46 @@ | |||
1 | package terraform | 1 | package terraform |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "errors" | ||
4 | "fmt" | 5 | "fmt" |
5 | "log" | 6 | "log" |
6 | "strings" | 7 | "strings" |
7 | 8 | ||
8 | "github.com/hashicorp/go-multierror" | 9 | "github.com/hashicorp/go-multierror" |
10 | "github.com/hashicorp/terraform/config" | ||
11 | "github.com/hashicorp/terraform/config/module" | ||
9 | "github.com/hashicorp/terraform/dag" | 12 | "github.com/hashicorp/terraform/dag" |
10 | ) | 13 | ) |
11 | 14 | ||
15 | func TransformProviders(providers []string, concrete ConcreteProviderNodeFunc, mod *module.Tree) GraphTransformer { | ||
16 | return GraphTransformMulti( | ||
17 | // Add providers from the config | ||
18 | &ProviderConfigTransformer{ | ||
19 | Module: mod, | ||
20 | Providers: providers, | ||
21 | Concrete: concrete, | ||
22 | }, | ||
23 | // Add any remaining missing providers | ||
24 | &MissingProviderTransformer{ | ||
25 | Providers: providers, | ||
26 | Concrete: concrete, | ||
27 | }, | ||
28 | // Connect the providers | ||
29 | &ProviderTransformer{}, | ||
30 | // Remove unused providers and proxies | ||
31 | &PruneProviderTransformer{}, | ||
32 | // Connect provider to their parent provider nodes | ||
33 | &ParentProviderTransformer{}, | ||
34 | ) | ||
35 | } | ||
36 | |||
12 | // GraphNodeProvider is an interface that nodes that can be a provider | 37 | // GraphNodeProvider is an interface that nodes that can be a provider |
13 | // must implement. The ProviderName returned is the name of the provider | 38 | // must implement. |
14 | // they satisfy. | 39 | // ProviderName returns the name of the provider this satisfies. |
40 | // Name returns the full name of the provider in the config. | ||
15 | type GraphNodeProvider interface { | 41 | type GraphNodeProvider interface { |
16 | ProviderName() string | 42 | ProviderName() string |
43 | Name() string | ||
17 | } | 44 | } |
18 | 45 | ||
19 | // GraphNodeCloseProvider is an interface that nodes that can be a close | 46 | // GraphNodeCloseProvider is an interface that nodes that can be a close |
@@ -25,9 +52,12 @@ type GraphNodeCloseProvider interface { | |||
25 | 52 | ||
26 | // GraphNodeProviderConsumer is an interface that nodes that require | 53 | // GraphNodeProviderConsumer is an interface that nodes that require |
27 | // a provider must implement. ProvidedBy must return the name of the provider | 54 | // a provider must implement. ProvidedBy must return the name of the provider |
28 | // to use. | 55 | // to use. This may be a provider by type, type.alias or a fully resolved |
56 | // provider name | ||
29 | type GraphNodeProviderConsumer interface { | 57 | type GraphNodeProviderConsumer interface { |
30 | ProvidedBy() []string | 58 | ProvidedBy() string |
59 | // Set the resolved provider address for this resource. | ||
60 | SetProvider(string) | ||
31 | } | 61 | } |
32 | 62 | ||
33 | // ProviderTransformer is a GraphTransformer that maps resources to | 63 | // ProviderTransformer is a GraphTransformer that maps resources to |
@@ -41,18 +71,52 @@ func (t *ProviderTransformer) Transform(g *Graph) error { | |||
41 | m := providerVertexMap(g) | 71 | m := providerVertexMap(g) |
42 | for _, v := range g.Vertices() { | 72 | for _, v := range g.Vertices() { |
43 | if pv, ok := v.(GraphNodeProviderConsumer); ok { | 73 | if pv, ok := v.(GraphNodeProviderConsumer); ok { |
44 | for _, p := range pv.ProvidedBy() { | 74 | p := pv.ProvidedBy() |
45 | target := m[providerMapKey(p, pv)] | 75 | |
46 | if target == nil { | 76 | key := providerMapKey(p, pv) |
47 | println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv))) | 77 | target := m[key] |
48 | err = multierror.Append(err, fmt.Errorf( | 78 | |
49 | "%s: provider %s couldn't be found", | 79 | sp, ok := pv.(GraphNodeSubPath) |
50 | dag.VertexName(v), p)) | 80 | if !ok && target == nil { |
51 | continue | 81 | // no target, and no path to walk up |
82 | err = multierror.Append(err, fmt.Errorf( | ||
83 | "%s: provider %s couldn't be found", | ||
84 | dag.VertexName(v), p)) | ||
85 | break | ||
86 | } | ||
87 | |||
88 | // if we don't have a provider at this level, walk up the path looking for one | ||
89 | for i := 1; target == nil; i++ { | ||
90 | path := normalizeModulePath(sp.Path()) | ||
91 | if len(path) < i { | ||
92 | break | ||
93 | } | ||
94 | |||
95 | key = ResolveProviderName(p, path[:len(path)-i]) | ||
96 | target = m[key] | ||
97 | if target != nil { | ||
98 | break | ||
52 | } | 99 | } |
100 | } | ||
101 | |||
102 | if target == nil { | ||
103 | err = multierror.Append(err, fmt.Errorf( | ||
104 | "%s: configuration for %s is not present; a provider configuration block is required for all operations", | ||
105 | dag.VertexName(v), p, | ||
106 | )) | ||
107 | break | ||
108 | } | ||
53 | 109 | ||
54 | g.Connect(dag.BasicEdge(v, target)) | 110 | // see if this in an inherited provider |
111 | if p, ok := target.(*graphNodeProxyProvider); ok { | ||
112 | g.Remove(p) | ||
113 | target = p.Target() | ||
114 | key = target.(GraphNodeProvider).Name() | ||
55 | } | 115 | } |
116 | |||
117 | log.Printf("[DEBUG] resource %s using provider %s", dag.VertexName(pv), key) | ||
118 | pv.SetProvider(key) | ||
119 | g.Connect(dag.BasicEdge(v, target)) | ||
56 | } | 120 | } |
57 | } | 121 | } |
58 | 122 | ||
@@ -67,36 +131,32 @@ type CloseProviderTransformer struct{} | |||
67 | 131 | ||
68 | func (t *CloseProviderTransformer) Transform(g *Graph) error { | 132 | func (t *CloseProviderTransformer) Transform(g *Graph) error { |
69 | pm := providerVertexMap(g) | 133 | pm := providerVertexMap(g) |
70 | cpm := closeProviderVertexMap(g) | 134 | cpm := make(map[string]*graphNodeCloseProvider) |
71 | var err error | 135 | var err error |
72 | for _, v := range g.Vertices() { | ||
73 | if pv, ok := v.(GraphNodeProviderConsumer); ok { | ||
74 | for _, p := range pv.ProvidedBy() { | ||
75 | key := p | ||
76 | source := cpm[key] | ||
77 | |||
78 | if source == nil { | ||
79 | // Create a new graphNodeCloseProvider and add it to the graph | ||
80 | source = &graphNodeCloseProvider{ProviderNameValue: p} | ||
81 | g.Add(source) | ||
82 | |||
83 | // Close node needs to depend on provider | ||
84 | provider, ok := pm[key] | ||
85 | if !ok { | ||
86 | err = multierror.Append(err, fmt.Errorf( | ||
87 | "%s: provider %s couldn't be found for closing", | ||
88 | dag.VertexName(v), p)) | ||
89 | continue | ||
90 | } | ||
91 | g.Connect(dag.BasicEdge(source, provider)) | ||
92 | |||
93 | // Make sure we also add the new graphNodeCloseProvider to the map | ||
94 | // so we don't create and add any duplicate graphNodeCloseProviders. | ||
95 | cpm[key] = source | ||
96 | } | ||
97 | 136 | ||
98 | // Close node depends on all nodes provided by the provider | 137 | for _, v := range pm { |
99 | g.Connect(dag.BasicEdge(source, v)) | 138 | p := v.(GraphNodeProvider) |
139 | |||
140 | // get the close provider of this type if we alread created it | ||
141 | closer := cpm[p.Name()] | ||
142 | |||
143 | if closer == nil { | ||
144 | // create a closer for this provider type | ||
145 | closer = &graphNodeCloseProvider{ProviderNameValue: p.Name()} | ||
146 | g.Add(closer) | ||
147 | cpm[p.Name()] = closer | ||
148 | } | ||
149 | |||
150 | // Close node depends on the provider itself | ||
151 | // this is added unconditionally, so it will connect to all instances | ||
152 | // of the provider. Extra edges will be removed by transitive | ||
153 | // reduction. | ||
154 | g.Connect(dag.BasicEdge(closer, p)) | ||
155 | |||
156 | // connect all the provider's resources to the close node | ||
157 | for _, s := range g.UpEdges(p).List() { | ||
158 | if _, ok := s.(GraphNodeProviderConsumer); ok { | ||
159 | g.Connect(dag.BasicEdge(closer, s)) | ||
100 | } | 160 | } |
101 | } | 161 | } |
102 | } | 162 | } |
@@ -104,18 +164,14 @@ func (t *CloseProviderTransformer) Transform(g *Graph) error { | |||
104 | return err | 164 | return err |
105 | } | 165 | } |
106 | 166 | ||
107 | // MissingProviderTransformer is a GraphTransformer that adds nodes | 167 | // MissingProviderTransformer is a GraphTransformer that adds nodes for all |
108 | // for missing providers into the graph. Specifically, it creates provider | 168 | // required providers into the graph. Specifically, it creates provider |
109 | // configuration nodes for all the providers that we support. These are | 169 | // configuration nodes for all the providers that we support. These are pruned |
110 | // pruned later during an optimization pass. | 170 | // later during an optimization pass. |
111 | type MissingProviderTransformer struct { | 171 | type MissingProviderTransformer struct { |
112 | // Providers is the list of providers we support. | 172 | // Providers is the list of providers we support. |
113 | Providers []string | 173 | Providers []string |
114 | 174 | ||
115 | // AllowAny will not check that a provider is supported before adding | ||
116 | // it to the graph. | ||
117 | AllowAny bool | ||
118 | |||
119 | // Concrete, if set, overrides how the providers are made. | 175 | // Concrete, if set, overrides how the providers are made. |
120 | Concrete ConcreteProviderNodeFunc | 176 | Concrete ConcreteProviderNodeFunc |
121 | } | 177 | } |
@@ -128,99 +184,57 @@ func (t *MissingProviderTransformer) Transform(g *Graph) error { | |||
128 | } | 184 | } |
129 | } | 185 | } |
130 | 186 | ||
131 | // Create a set of our supported providers | 187 | var err error |
132 | supported := make(map[string]struct{}, len(t.Providers)) | ||
133 | for _, v := range t.Providers { | ||
134 | supported[v] = struct{}{} | ||
135 | } | ||
136 | |||
137 | // Get the map of providers we already have in our graph | ||
138 | m := providerVertexMap(g) | 188 | m := providerVertexMap(g) |
139 | 189 | for _, v := range g.Vertices() { | |
140 | // Go through all the provider consumers and make sure we add | ||
141 | // that provider if it is missing. We use a for loop here instead | ||
142 | // of "range" since we'll modify check as we go to add more to check. | ||
143 | check := g.Vertices() | ||
144 | for i := 0; i < len(check); i++ { | ||
145 | v := check[i] | ||
146 | |||
147 | pv, ok := v.(GraphNodeProviderConsumer) | 190 | pv, ok := v.(GraphNodeProviderConsumer) |
148 | if !ok { | 191 | if !ok { |
149 | continue | 192 | continue |
150 | } | 193 | } |
151 | 194 | ||
152 | // If this node has a subpath, then we use that as a prefix | 195 | p := pv.ProvidedBy() |
153 | // into our map to check for an existing provider. | 196 | // this may be the resolved provider from the state, so we need to get |
154 | var path []string | 197 | // the base provider name. |
155 | if sp, ok := pv.(GraphNodeSubPath); ok { | 198 | parts := strings.SplitAfter(p, "provider.") |
156 | raw := normalizeModulePath(sp.Path()) | 199 | p = parts[len(parts)-1] |
157 | if len(raw) > len(rootModulePath) { | ||
158 | path = raw | ||
159 | } | ||
160 | } | ||
161 | 200 | ||
162 | for _, p := range pv.ProvidedBy() { | 201 | key := ResolveProviderName(p, nil) |
163 | key := providerMapKey(p, pv) | 202 | provider := m[key] |
164 | if _, ok := m[key]; ok { | ||
165 | // This provider already exists as a configure node | ||
166 | continue | ||
167 | } | ||
168 | 203 | ||
169 | // If the provider has an alias in it, we just want the type | 204 | // we already have it |
170 | ptype := p | 205 | if provider != nil { |
171 | if idx := strings.IndexRune(p, '.'); idx != -1 { | 206 | continue |
172 | ptype = p[:idx] | 207 | } |
173 | } | ||
174 | 208 | ||
175 | if !t.AllowAny { | 209 | // we don't implicitly create aliased providers |
176 | if _, ok := supported[ptype]; !ok { | 210 | if strings.Contains(p, ".") { |
177 | // If we don't support the provider type, skip it. | 211 | log.Println("[DEBUG] not adding missing provider alias:", p) |
178 | // Validation later will catch this as an error. | 212 | continue |
179 | continue | 213 | } |
180 | } | ||
181 | } | ||
182 | 214 | ||
183 | // Add the missing provider node to the graph | 215 | log.Println("[DEBUG] adding missing provider:", p) |
184 | v := t.Concrete(&NodeAbstractProvider{ | ||
185 | NameValue: p, | ||
186 | PathValue: path, | ||
187 | }).(dag.Vertex) | ||
188 | if len(path) > 0 { | ||
189 | // We'll need the parent provider as well, so let's | ||
190 | // add a dummy node to check to make sure that we add | ||
191 | // that parent provider. | ||
192 | check = append(check, &graphNodeProviderConsumerDummy{ | ||
193 | ProviderValue: p, | ||
194 | PathValue: path[:len(path)-1], | ||
195 | }) | ||
196 | } | ||
197 | 216 | ||
198 | m[key] = g.Add(v) | 217 | // create the misisng top-level provider |
199 | } | 218 | provider = t.Concrete(&NodeAbstractProvider{ |
219 | NameValue: p, | ||
220 | }).(dag.Vertex) | ||
221 | |||
222 | m[key] = g.Add(provider) | ||
200 | } | 223 | } |
201 | 224 | ||
202 | return nil | 225 | return err |
203 | } | 226 | } |
204 | 227 | ||
205 | // ParentProviderTransformer connects provider nodes to their parents. | 228 | // ParentProviderTransformer connects provider nodes to their parents. |
206 | // | 229 | // |
207 | // This works by finding nodes that are both GraphNodeProviders and | 230 | // This works by finding nodes that are both GraphNodeProviders and |
208 | // GraphNodeSubPath. It then connects the providers to their parent | 231 | // GraphNodeSubPath. It then connects the providers to their parent |
209 | // path. | 232 | // path. The parent provider is always at the root level. |
210 | type ParentProviderTransformer struct{} | 233 | type ParentProviderTransformer struct{} |
211 | 234 | ||
212 | func (t *ParentProviderTransformer) Transform(g *Graph) error { | 235 | func (t *ParentProviderTransformer) Transform(g *Graph) error { |
213 | // Make a mapping of path to dag.Vertex, where path is: "path.name" | 236 | pm := providerVertexMap(g) |
214 | m := make(map[string]dag.Vertex) | 237 | for _, v := range g.Vertices() { |
215 | |||
216 | // Also create a map that maps a provider to its parent | ||
217 | parentMap := make(map[dag.Vertex]string) | ||
218 | for _, raw := range g.Vertices() { | ||
219 | // If it is the flat version, then make it the non-flat version. | ||
220 | // We eventually want to get rid of the flat version entirely so | ||
221 | // this is a stop-gap while it still exists. | ||
222 | var v dag.Vertex = raw | ||
223 | |||
224 | // Only care about providers | 238 | // Only care about providers |
225 | pn, ok := v.(GraphNodeProvider) | 239 | pn, ok := v.(GraphNodeProvider) |
226 | if !ok || pn.ProviderName() == "" { | 240 | if !ok || pn.ProviderName() == "" { |
@@ -228,53 +242,48 @@ func (t *ParentProviderTransformer) Transform(g *Graph) error { | |||
228 | } | 242 | } |
229 | 243 | ||
230 | // Also require a subpath, if there is no subpath then we | 244 | // Also require a subpath, if there is no subpath then we |
231 | // just totally ignore it. The expectation of this transform is | 245 | // can't have a parent. |
232 | // that it is used with a graph builder that is already flattened. | 246 | if pn, ok := v.(GraphNodeSubPath); ok { |
233 | var path []string | 247 | if len(normalizeModulePath(pn.Path())) <= 1 { |
234 | if pn, ok := raw.(GraphNodeSubPath); ok { | 248 | continue |
235 | path = pn.Path() | 249 | } |
236 | } | ||
237 | path = normalizeModulePath(path) | ||
238 | |||
239 | // Build the key with path.name i.e. "child.subchild.aws" | ||
240 | key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName()) | ||
241 | m[key] = raw | ||
242 | |||
243 | // Determine the parent if we're non-root. This is length 1 since | ||
244 | // the 0 index should be "root" since we normalize above. | ||
245 | if len(path) > 1 { | ||
246 | path = path[:len(path)-1] | ||
247 | key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName()) | ||
248 | parentMap[raw] = key | ||
249 | } | 250 | } |
250 | } | ||
251 | 251 | ||
252 | // Connect! | 252 | // this provider may be disabled, but we can only get it's name from |
253 | for v, key := range parentMap { | 253 | // the ProviderName string |
254 | if parent, ok := m[key]; ok { | 254 | name := ResolveProviderName(strings.SplitN(pn.ProviderName(), " ", 2)[0], nil) |
255 | parent := pm[name] | ||
256 | if parent != nil { | ||
255 | g.Connect(dag.BasicEdge(v, parent)) | 257 | g.Connect(dag.BasicEdge(v, parent)) |
256 | } | 258 | } |
257 | } | ||
258 | 259 | ||
260 | } | ||
259 | return nil | 261 | return nil |
260 | } | 262 | } |
261 | 263 | ||
262 | // PruneProviderTransformer is a GraphTransformer that prunes all the | 264 | // PruneProviderTransformer removes any providers that are not actually used by |
263 | // providers that aren't needed from the graph. A provider is unneeded if | 265 | // anything, and provider proxies. This avoids the provider being initialized |
264 | // no resource or module is using that provider. | 266 | // and configured. This both saves resources but also avoids errors since |
267 | // configuration may imply initialization which may require auth. | ||
265 | type PruneProviderTransformer struct{} | 268 | type PruneProviderTransformer struct{} |
266 | 269 | ||
267 | func (t *PruneProviderTransformer) Transform(g *Graph) error { | 270 | func (t *PruneProviderTransformer) Transform(g *Graph) error { |
268 | for _, v := range g.Vertices() { | 271 | for _, v := range g.Vertices() { |
269 | // We only care about the providers | 272 | // We only care about providers |
270 | if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" { | 273 | pn, ok := v.(GraphNodeProvider) |
274 | if !ok || pn.ProviderName() == "" { | ||
271 | continue | 275 | continue |
272 | } | 276 | } |
273 | // Does anything depend on this? If not, then prune it. | 277 | |
274 | if s := g.UpEdges(v); s.Len() == 0 { | 278 | // ProxyProviders will have up edges, but we're now done with them in the graph |
275 | if nv, ok := v.(dag.NamedVertex); ok { | 279 | if _, ok := v.(*graphNodeProxyProvider); ok { |
276 | log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name()) | 280 | log.Printf("[DEBUG] pruning proxy provider %s", dag.VertexName(v)) |
277 | } | 281 | g.Remove(v) |
282 | } | ||
283 | |||
284 | // Remove providers with no dependencies. | ||
285 | if g.UpEdges(v).Len() == 0 { | ||
286 | log.Printf("[DEBUG] pruning unused provider %s", dag.VertexName(v)) | ||
278 | g.Remove(v) | 287 | g.Remove(v) |
279 | } | 288 | } |
280 | } | 289 | } |
@@ -285,23 +294,26 @@ func (t *PruneProviderTransformer) Transform(g *Graph) error { | |||
285 | // providerMapKey is a helper that gives us the key to use for the | 294 | // providerMapKey is a helper that gives us the key to use for the |
286 | // maps returned by things such as providerVertexMap. | 295 | // maps returned by things such as providerVertexMap. |
287 | func providerMapKey(k string, v dag.Vertex) string { | 296 | func providerMapKey(k string, v dag.Vertex) string { |
288 | pathPrefix := "" | 297 | if strings.Contains(k, "provider.") { |
289 | if sp, ok := v.(GraphNodeSubPath); ok { | 298 | // this is already resolved |
290 | raw := normalizeModulePath(sp.Path()) | 299 | return k |
291 | if len(raw) > len(rootModulePath) { | ||
292 | pathPrefix = modulePrefixStr(raw) + "." | ||
293 | } | ||
294 | } | 300 | } |
295 | 301 | ||
296 | return pathPrefix + k | 302 | // we create a dummy provider to |
303 | var path []string | ||
304 | if sp, ok := v.(GraphNodeSubPath); ok { | ||
305 | path = normalizeModulePath(sp.Path()) | ||
306 | } | ||
307 | return ResolveProviderName(k, path) | ||
297 | } | 308 | } |
298 | 309 | ||
299 | func providerVertexMap(g *Graph) map[string]dag.Vertex { | 310 | func providerVertexMap(g *Graph) map[string]dag.Vertex { |
300 | m := make(map[string]dag.Vertex) | 311 | m := make(map[string]dag.Vertex) |
301 | for _, v := range g.Vertices() { | 312 | for _, v := range g.Vertices() { |
302 | if pv, ok := v.(GraphNodeProvider); ok { | 313 | if pv, ok := v.(GraphNodeProvider); ok { |
303 | key := providerMapKey(pv.ProviderName(), v) | 314 | // TODO: The Name may have meta info, like " (disabled)" |
304 | m[key] = v | 315 | name := strings.SplitN(pv.Name(), " ", 2)[0] |
316 | m[name] = v | ||
305 | } | 317 | } |
306 | } | 318 | } |
307 | 319 | ||
@@ -324,7 +336,7 @@ type graphNodeCloseProvider struct { | |||
324 | } | 336 | } |
325 | 337 | ||
326 | func (n *graphNodeCloseProvider) Name() string { | 338 | func (n *graphNodeCloseProvider) Name() string { |
327 | return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue) | 339 | return n.ProviderNameValue + " (close)" |
328 | } | 340 | } |
329 | 341 | ||
330 | // GraphNodeEvalable impl. | 342 | // GraphNodeEvalable impl. |
@@ -362,19 +374,233 @@ func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool { | |||
362 | return true | 374 | return true |
363 | } | 375 | } |
364 | 376 | ||
365 | // graphNodeProviderConsumerDummy is a struct that never enters the real | 377 | // graphNodeProxyProvider is a GraphNodeProvider implementation that is used to |
366 | // graph (though it could to no ill effect). It implements | 378 | // store the name and value of a provider node for inheritance between modules. |
367 | // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force | 379 | // These nodes are only used to store the data while loading the provider |
368 | // certain transformations. | 380 | // configurations, and are removed after all the resources have been connected |
369 | type graphNodeProviderConsumerDummy struct { | 381 | // to their providers. |
370 | ProviderValue string | 382 | type graphNodeProxyProvider struct { |
371 | PathValue []string | 383 | nameValue string |
384 | path []string | ||
385 | target GraphNodeProvider | ||
386 | } | ||
387 | |||
388 | func (n *graphNodeProxyProvider) ProviderName() string { | ||
389 | return n.Target().ProviderName() | ||
390 | } | ||
391 | |||
392 | func (n *graphNodeProxyProvider) Name() string { | ||
393 | return ResolveProviderName(n.nameValue, n.path) | ||
394 | } | ||
395 | |||
396 | // find the concrete provider instance | ||
397 | func (n *graphNodeProxyProvider) Target() GraphNodeProvider { | ||
398 | switch t := n.target.(type) { | ||
399 | case *graphNodeProxyProvider: | ||
400 | return t.Target() | ||
401 | default: | ||
402 | return n.target | ||
403 | } | ||
404 | } | ||
405 | |||
406 | // ProviderConfigTransformer adds all provider nodes from the configuration and | ||
407 | // attaches the configs. | ||
408 | type ProviderConfigTransformer struct { | ||
409 | Providers []string | ||
410 | Concrete ConcreteProviderNodeFunc | ||
411 | |||
412 | // each provider node is stored here so that the proxy nodes can look up | ||
413 | // their targets by name. | ||
414 | providers map[string]GraphNodeProvider | ||
415 | // record providers that can be overriden with a proxy | ||
416 | proxiable map[string]bool | ||
417 | |||
418 | // Module is the module to add resources from. | ||
419 | Module *module.Tree | ||
372 | } | 420 | } |
373 | 421 | ||
374 | func (n *graphNodeProviderConsumerDummy) Path() []string { | 422 | func (t *ProviderConfigTransformer) Transform(g *Graph) error { |
375 | return n.PathValue | 423 | // If no module is given, we don't do anything |
424 | if t.Module == nil { | ||
425 | return nil | ||
426 | } | ||
427 | |||
428 | // If the module isn't loaded, that is simply an error | ||
429 | if !t.Module.Loaded() { | ||
430 | return errors.New("module must be loaded for ProviderConfigTransformer") | ||
431 | } | ||
432 | |||
433 | t.providers = make(map[string]GraphNodeProvider) | ||
434 | t.proxiable = make(map[string]bool) | ||
435 | |||
436 | // Start the transformation process | ||
437 | if err := t.transform(g, t.Module); err != nil { | ||
438 | return err | ||
439 | } | ||
440 | |||
441 | // finally attach the configs to the new nodes | ||
442 | return t.attachProviderConfigs(g) | ||
376 | } | 443 | } |
377 | 444 | ||
378 | func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string { | 445 | func (t *ProviderConfigTransformer) transform(g *Graph, m *module.Tree) error { |
379 | return []string{n.ProviderValue} | 446 | // If no config, do nothing |
447 | if m == nil { | ||
448 | return nil | ||
449 | } | ||
450 | |||
451 | // Add our resources | ||
452 | if err := t.transformSingle(g, m); err != nil { | ||
453 | return err | ||
454 | } | ||
455 | |||
456 | // Transform all the children. | ||
457 | for _, c := range m.Children() { | ||
458 | if err := t.transform(g, c); err != nil { | ||
459 | return err | ||
460 | } | ||
461 | } | ||
462 | return nil | ||
463 | } | ||
464 | |||
465 | func (t *ProviderConfigTransformer) transformSingle(g *Graph, m *module.Tree) error { | ||
466 | log.Printf("[TRACE] ProviderConfigTransformer: Starting for path: %v", m.Path()) | ||
467 | |||
468 | // Get the configuration for this module | ||
469 | conf := m.Config() | ||
470 | |||
471 | // Build the path we're at | ||
472 | path := m.Path() | ||
473 | if len(path) > 0 { | ||
474 | path = append([]string{RootModuleName}, path...) | ||
475 | } | ||
476 | |||
477 | // add all providers from the configuration | ||
478 | for _, p := range conf.ProviderConfigs { | ||
479 | name := p.Name | ||
480 | if p.Alias != "" { | ||
481 | name += "." + p.Alias | ||
482 | } | ||
483 | |||
484 | v := t.Concrete(&NodeAbstractProvider{ | ||
485 | NameValue: name, | ||
486 | PathValue: path, | ||
487 | }) | ||
488 | |||
489 | // Add it to the graph | ||
490 | g.Add(v) | ||
491 | fullName := ResolveProviderName(name, path) | ||
492 | t.providers[fullName] = v.(GraphNodeProvider) | ||
493 | t.proxiable[fullName] = len(p.RawConfig.RawMap()) == 0 | ||
494 | } | ||
495 | |||
496 | // Now replace the provider nodes with proxy nodes if a provider was being | ||
497 | // passed in, and create implicit proxies if there was no config. Any extra | ||
498 | // proxies will be removed in the prune step. | ||
499 | return t.addProxyProviders(g, m) | ||
500 | } | ||
501 | |||
502 | func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, m *module.Tree) error { | ||
503 | path := m.Path() | ||
504 | |||
505 | // can't add proxies at the root | ||
506 | if len(path) == 0 { | ||
507 | return nil | ||
508 | } | ||
509 | |||
510 | parentPath := path[:len(path)-1] | ||
511 | parent := t.Module.Child(parentPath) | ||
512 | if parent == nil { | ||
513 | return nil | ||
514 | } | ||
515 | |||
516 | var parentCfg *config.Module | ||
517 | for _, mod := range parent.Config().Modules { | ||
518 | if mod.Name == m.Name() { | ||
519 | parentCfg = mod | ||
520 | break | ||
521 | } | ||
522 | } | ||
523 | |||
524 | if parentCfg == nil { | ||
525 | // this can't really happen during normal execution. | ||
526 | return fmt.Errorf("parent module config not found for %s", m.Name()) | ||
527 | } | ||
528 | |||
529 | // Go through all the providers the parent is passing in, and add proxies to | ||
530 | // the parent provider nodes. | ||
531 | for name, parentName := range parentCfg.Providers { | ||
532 | fullName := ResolveProviderName(name, path) | ||
533 | fullParentName := ResolveProviderName(parentName, parentPath) | ||
534 | |||
535 | parentProvider := t.providers[fullParentName] | ||
536 | |||
537 | if parentProvider == nil { | ||
538 | return fmt.Errorf("missing provider %s", fullParentName) | ||
539 | } | ||
540 | |||
541 | proxy := &graphNodeProxyProvider{ | ||
542 | nameValue: name, | ||
543 | path: path, | ||
544 | target: parentProvider, | ||
545 | } | ||
546 | |||
547 | concreteProvider := t.providers[fullName] | ||
548 | |||
549 | // replace the concrete node with the provider passed in | ||
550 | if concreteProvider != nil && t.proxiable[fullName] { | ||
551 | g.Replace(concreteProvider, proxy) | ||
552 | t.providers[fullName] = proxy | ||
553 | continue | ||
554 | } | ||
555 | |||
556 | // aliased providers can't be implicitly passed in | ||
557 | if strings.Contains(name, ".") { | ||
558 | continue | ||
559 | } | ||
560 | |||
561 | // There was no concrete provider, so add this as an implicit provider. | ||
562 | // The extra proxy will be pruned later if it's unused. | ||
563 | g.Add(proxy) | ||
564 | t.providers[fullName] = proxy | ||
565 | } | ||
566 | return nil | ||
567 | } | ||
568 | |||
569 | func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error { | ||
570 | for _, v := range g.Vertices() { | ||
571 | // Only care about GraphNodeAttachProvider implementations | ||
572 | apn, ok := v.(GraphNodeAttachProvider) | ||
573 | if !ok { | ||
574 | continue | ||
575 | } | ||
576 | |||
577 | // Determine what we're looking for | ||
578 | path := normalizeModulePath(apn.Path())[1:] | ||
579 | name := apn.ProviderName() | ||
580 | log.Printf("[TRACE] Attach provider request: %#v %s", path, name) | ||
581 | |||
582 | // Get the configuration. | ||
583 | tree := t.Module.Child(path) | ||
584 | if tree == nil { | ||
585 | continue | ||
586 | } | ||
587 | |||
588 | // Go through the provider configs to find the matching config | ||
589 | for _, p := range tree.Config().ProviderConfigs { | ||
590 | // Build the name, which is "name.alias" if an alias exists | ||
591 | current := p.Name | ||
592 | if p.Alias != "" { | ||
593 | current += "." + p.Alias | ||
594 | } | ||
595 | |||
596 | // If the configs match then attach! | ||
597 | if current == name { | ||
598 | log.Printf("[TRACE] Attaching provider config: %#v", p) | ||
599 | apn.AttachProvider(p) | ||
600 | break | ||
601 | } | ||
602 | } | ||
603 | } | ||
604 | |||
605 | return nil | ||
380 | } | 606 | } |