]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/hashicorp/terraform/terraform/transform_provider.go
deps: github.com/hashicorp/terraform@sdk-v0.11-with-go-modules
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / transform_provider.go
1 package terraform
2
3 import (
4 "errors"
5 "fmt"
6 "log"
7 "strings"
8
9 "github.com/hashicorp/go-multierror"
10 "github.com/hashicorp/terraform/config"
11 "github.com/hashicorp/terraform/config/module"
12 "github.com/hashicorp/terraform/dag"
13 )
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
37 // GraphNodeProvider is an interface that nodes that can be a provider
38 // must implement.
39 // ProviderName returns the name of the provider this satisfies.
40 // Name returns the full name of the provider in the config.
41 type GraphNodeProvider interface {
42 ProviderName() string
43 Name() string
44 }
45
46 // GraphNodeCloseProvider is an interface that nodes that can be a close
47 // provider must implement. The CloseProviderName returned is the name of
48 // the provider they satisfy.
49 type GraphNodeCloseProvider interface {
50 CloseProviderName() string
51 }
52
53 // GraphNodeProviderConsumer is an interface that nodes that require
54 // a provider must implement. ProvidedBy must return the name of the provider
55 // to use. This may be a provider by type, type.alias or a fully resolved
56 // provider name
57 type GraphNodeProviderConsumer interface {
58 ProvidedBy() string
59 // Set the resolved provider address for this resource.
60 SetProvider(string)
61 }
62
63 // ProviderTransformer is a GraphTransformer that maps resources to
64 // providers within the graph. This will error if there are any resources
65 // that don't map to proper resources.
66 type ProviderTransformer struct{}
67
68 func (t *ProviderTransformer) Transform(g *Graph) error {
69 // Go through the other nodes and match them to providers they need
70 var err error
71 m := providerVertexMap(g)
72 for _, v := range g.Vertices() {
73 if pv, ok := v.(GraphNodeProviderConsumer); ok {
74 p := pv.ProvidedBy()
75
76 key := providerMapKey(p, pv)
77 target := m[key]
78
79 sp, ok := pv.(GraphNodeSubPath)
80 if !ok && target == nil {
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
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 }
109
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()
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))
120 }
121 }
122
123 return err
124 }
125
126 // CloseProviderTransformer is a GraphTransformer that adds nodes to the
127 // graph that will close open provider connections that aren't needed anymore.
128 // A provider connection is not needed anymore once all depended resources
129 // in the graph are evaluated.
130 type CloseProviderTransformer struct{}
131
132 func (t *CloseProviderTransformer) Transform(g *Graph) error {
133 pm := providerVertexMap(g)
134 cpm := make(map[string]*graphNodeCloseProvider)
135 var err error
136
137 for _, v := range pm {
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))
160 }
161 }
162 }
163
164 return err
165 }
166
167 // MissingProviderTransformer is a GraphTransformer that adds nodes for all
168 // required providers into the graph. Specifically, it creates provider
169 // configuration nodes for all the providers that we support. These are pruned
170 // later during an optimization pass.
171 type MissingProviderTransformer struct {
172 // Providers is the list of providers we support.
173 Providers []string
174
175 // Concrete, if set, overrides how the providers are made.
176 Concrete ConcreteProviderNodeFunc
177 }
178
179 func (t *MissingProviderTransformer) Transform(g *Graph) error {
180 // Initialize factory
181 if t.Concrete == nil {
182 t.Concrete = func(a *NodeAbstractProvider) dag.Vertex {
183 return a
184 }
185 }
186
187 var err error
188 m := providerVertexMap(g)
189 for _, v := range g.Vertices() {
190 pv, ok := v.(GraphNodeProviderConsumer)
191 if !ok {
192 continue
193 }
194
195 p := pv.ProvidedBy()
196 // this may be the resolved provider from the state, so we need to get
197 // the base provider name.
198 parts := strings.SplitAfter(p, "provider.")
199 p = parts[len(parts)-1]
200
201 key := ResolveProviderName(p, nil)
202 provider := m[key]
203
204 // we already have it
205 if provider != nil {
206 continue
207 }
208
209 // we don't implicitly create aliased providers
210 if strings.Contains(p, ".") {
211 log.Println("[DEBUG] not adding missing provider alias:", p)
212 continue
213 }
214
215 log.Println("[DEBUG] adding missing provider:", p)
216
217 // create the misisng top-level provider
218 provider = t.Concrete(&NodeAbstractProvider{
219 NameValue: p,
220 }).(dag.Vertex)
221
222 m[key] = g.Add(provider)
223 }
224
225 return err
226 }
227
228 // ParentProviderTransformer connects provider nodes to their parents.
229 //
230 // This works by finding nodes that are both GraphNodeProviders and
231 // GraphNodeSubPath. It then connects the providers to their parent
232 // path. The parent provider is always at the root level.
233 type ParentProviderTransformer struct{}
234
235 func (t *ParentProviderTransformer) Transform(g *Graph) error {
236 pm := providerVertexMap(g)
237 for _, v := range g.Vertices() {
238 // Only care about providers
239 pn, ok := v.(GraphNodeProvider)
240 if !ok || pn.ProviderName() == "" {
241 continue
242 }
243
244 // Also require a subpath, if there is no subpath then we
245 // can't have a parent.
246 if pn, ok := v.(GraphNodeSubPath); ok {
247 if len(normalizeModulePath(pn.Path())) <= 1 {
248 continue
249 }
250 }
251
252 // this provider may be disabled, but we can only get it's name from
253 // the ProviderName string
254 name := ResolveProviderName(strings.SplitN(pn.ProviderName(), " ", 2)[0], nil)
255 parent := pm[name]
256 if parent != nil {
257 g.Connect(dag.BasicEdge(v, parent))
258 }
259
260 }
261 return nil
262 }
263
264 // PruneProviderTransformer removes any providers that are not actually used by
265 // anything, and provider proxies. This avoids the provider being initialized
266 // and configured. This both saves resources but also avoids errors since
267 // configuration may imply initialization which may require auth.
268 type PruneProviderTransformer struct{}
269
270 func (t *PruneProviderTransformer) Transform(g *Graph) error {
271 for _, v := range g.Vertices() {
272 // We only care about providers
273 pn, ok := v.(GraphNodeProvider)
274 if !ok || pn.ProviderName() == "" {
275 continue
276 }
277
278 // ProxyProviders will have up edges, but we're now done with them in the graph
279 if _, ok := v.(*graphNodeProxyProvider); ok {
280 log.Printf("[DEBUG] pruning proxy provider %s", dag.VertexName(v))
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))
287 g.Remove(v)
288 }
289 }
290
291 return nil
292 }
293
294 // providerMapKey is a helper that gives us the key to use for the
295 // maps returned by things such as providerVertexMap.
296 func providerMapKey(k string, v dag.Vertex) string {
297 if strings.Contains(k, "provider.") {
298 // this is already resolved
299 return k
300 }
301
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)
308 }
309
310 func providerVertexMap(g *Graph) map[string]dag.Vertex {
311 m := make(map[string]dag.Vertex)
312 for _, v := range g.Vertices() {
313 if pv, ok := v.(GraphNodeProvider); ok {
314 // TODO: The Name may have meta info, like " (disabled)"
315 name := strings.SplitN(pv.Name(), " ", 2)[0]
316 m[name] = v
317 }
318 }
319
320 return m
321 }
322
323 func closeProviderVertexMap(g *Graph) map[string]dag.Vertex {
324 m := make(map[string]dag.Vertex)
325 for _, v := range g.Vertices() {
326 if pv, ok := v.(GraphNodeCloseProvider); ok {
327 m[pv.CloseProviderName()] = v
328 }
329 }
330
331 return m
332 }
333
334 type graphNodeCloseProvider struct {
335 ProviderNameValue string
336 }
337
338 func (n *graphNodeCloseProvider) Name() string {
339 return n.ProviderNameValue + " (close)"
340 }
341
342 // GraphNodeEvalable impl.
343 func (n *graphNodeCloseProvider) EvalTree() EvalNode {
344 return CloseProviderEvalTree(n.ProviderNameValue)
345 }
346
347 // GraphNodeDependable impl.
348 func (n *graphNodeCloseProvider) DependableName() []string {
349 return []string{n.Name()}
350 }
351
352 func (n *graphNodeCloseProvider) CloseProviderName() string {
353 return n.ProviderNameValue
354 }
355
356 // GraphNodeDotter impl.
357 func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
358 if !opts.Verbose {
359 return nil
360 }
361 return &dag.DotNode{
362 Name: name,
363 Attrs: map[string]string{
364 "label": n.Name(),
365 "shape": "diamond",
366 },
367 }
368 }
369
370 // RemovableIfNotTargeted
371 func (n *graphNodeCloseProvider) RemoveIfNotTargeted() bool {
372 // We need to add this so that this node will be removed if
373 // it isn't targeted or a dependency of a target.
374 return true
375 }
376
377 // graphNodeProxyProvider is a GraphNodeProvider implementation that is used to
378 // store the name and value of a provider node for inheritance between modules.
379 // These nodes are only used to store the data while loading the provider
380 // configurations, and are removed after all the resources have been connected
381 // to their providers.
382 type graphNodeProxyProvider struct {
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
420 }
421
422 func (t *ProviderConfigTransformer) Transform(g *Graph) error {
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)
443 }
444
445 func (t *ProviderConfigTransformer) transform(g *Graph, m *module.Tree) error {
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
606 }