github.com/pulumi/terraform@v1.4.0/pkg/terraform/transform_provider.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 7 "github.com/hashicorp/hcl/v2" 8 "github.com/pulumi/terraform/pkg/addrs" 9 "github.com/pulumi/terraform/pkg/configs" 10 "github.com/pulumi/terraform/pkg/dag" 11 "github.com/pulumi/terraform/pkg/tfdiags" 12 ) 13 14 func transformProviders(concrete ConcreteProviderNodeFunc, config *configs.Config) GraphTransformer { 15 return GraphTransformMulti( 16 // Add providers from the config 17 &ProviderConfigTransformer{ 18 Config: config, 19 Concrete: concrete, 20 }, 21 // Add any remaining missing providers 22 &MissingProviderTransformer{ 23 Config: config, 24 Concrete: concrete, 25 }, 26 // Connect the providers 27 &ProviderTransformer{ 28 Config: config, 29 }, 30 // Remove unused providers and proxies 31 &PruneProviderTransformer{}, 32 ) 33 } 34 35 // GraphNodeProvider is an interface that nodes that can be a provider 36 // must implement. 37 // 38 // ProviderAddr returns the address of the provider configuration this 39 // satisfies, which is relative to the path returned by method Path(). 40 // 41 // Name returns the full name of the provider in the config. 42 type GraphNodeProvider interface { 43 GraphNodeModulePath 44 ProviderAddr() addrs.AbsProviderConfig 45 Name() string 46 } 47 48 // GraphNodeCloseProvider is an interface that nodes that can be a close 49 // provider must implement. The CloseProviderName returned is the name of 50 // the provider they satisfy. 51 type GraphNodeCloseProvider interface { 52 GraphNodeModulePath 53 CloseProviderAddr() addrs.AbsProviderConfig 54 } 55 56 // GraphNodeProviderConsumer is an interface that nodes that require 57 // a provider must implement. ProvidedBy must return the address of the provider 58 // to use, which will be resolved to a configuration either in the same module 59 // or in an ancestor module, with the resulting absolute address passed to 60 // SetProvider. 61 type GraphNodeProviderConsumer interface { 62 GraphNodeModulePath 63 // ProvidedBy returns the address of the provider configuration the node 64 // refers to, if available. The following value types may be returned: 65 // 66 // nil + exact true: the node does not require a provider 67 // * addrs.LocalProviderConfig: the provider was set in the resource config 68 // * addrs.AbsProviderConfig + exact true: the provider configuration was 69 // taken from the instance state. 70 // * addrs.AbsProviderConfig + exact false: no config or state; the returned 71 // value is a default provider configuration address for the resource's 72 // Provider 73 ProvidedBy() (addr addrs.ProviderConfig, exact bool) 74 75 // Provider() returns the Provider FQN for the node. 76 Provider() (provider addrs.Provider) 77 78 // Set the resolved provider address for this resource. 79 SetProvider(addrs.AbsProviderConfig) 80 } 81 82 // ProviderTransformer is a GraphTransformer that maps resources to providers 83 // within the graph. This will error if there are any resources that don't map 84 // to proper resources. 85 type ProviderTransformer struct { 86 Config *configs.Config 87 } 88 89 func (t *ProviderTransformer) Transform(g *Graph) error { 90 // We need to find a provider configuration address for each resource 91 // either directly represented by a node or referenced by a node in 92 // the graph, and then create graph edges from provider to provider user 93 // so that the providers will get initialized first. 94 95 var diags tfdiags.Diagnostics 96 97 // To start, we'll collect the _requested_ provider addresses for each 98 // node, which we'll then resolve (handling provider inheritence, etc) in 99 // the next step. 100 // Our "requested" map is from graph vertices to string representations of 101 // provider config addresses (for deduping) to requests. 102 type ProviderRequest struct { 103 Addr addrs.AbsProviderConfig 104 Exact bool // If true, inheritence from parent modules is not attempted 105 } 106 requested := map[dag.Vertex]map[string]ProviderRequest{} 107 needConfigured := map[string]addrs.AbsProviderConfig{} 108 for _, v := range g.Vertices() { 109 // Does the vertex _directly_ use a provider? 110 if pv, ok := v.(GraphNodeProviderConsumer); ok { 111 providerAddr, exact := pv.ProvidedBy() 112 if providerAddr == nil && exact { 113 // no provider is required 114 continue 115 } 116 117 requested[v] = make(map[string]ProviderRequest) 118 119 var absPc addrs.AbsProviderConfig 120 121 switch p := providerAddr.(type) { 122 case addrs.AbsProviderConfig: 123 // ProvidedBy() returns an AbsProviderConfig when the provider 124 // configuration is set in state, so we do not need to verify 125 // the FQN matches. 126 absPc = p 127 128 if exact { 129 log.Printf("[TRACE] ProviderTransformer: %s is provided by %s exactly", dag.VertexName(v), absPc) 130 } 131 132 case addrs.LocalProviderConfig: 133 // ProvidedBy() return a LocalProviderConfig when the resource 134 // contains a `provider` attribute 135 absPc.Provider = pv.Provider() 136 modPath := pv.ModulePath() 137 if t.Config == nil { 138 absPc.Module = modPath 139 absPc.Alias = p.Alias 140 break 141 } 142 143 absPc.Module = modPath 144 absPc.Alias = p.Alias 145 146 default: 147 // This should never happen; the case statements are meant to be exhaustive 148 panic(fmt.Sprintf("%s: provider for %s couldn't be determined", dag.VertexName(v), absPc)) 149 } 150 151 requested[v][absPc.String()] = ProviderRequest{ 152 Addr: absPc, 153 Exact: exact, 154 } 155 156 // Direct references need the provider configured as well as initialized 157 needConfigured[absPc.String()] = absPc 158 } 159 } 160 161 // Now we'll go through all the requested addresses we just collected and 162 // figure out which _actual_ config address each belongs to, after resolving 163 // for provider inheritance and passing. 164 m := providerVertexMap(g) 165 for v, reqs := range requested { 166 for key, req := range reqs { 167 p := req.Addr 168 target := m[key] 169 170 _, ok := v.(GraphNodeModulePath) 171 if !ok && target == nil { 172 // No target and no path to traverse up from 173 diags = diags.Append(fmt.Errorf("%s: provider %s couldn't be found", dag.VertexName(v), p)) 174 continue 175 } 176 177 if target != nil { 178 log.Printf("[TRACE] ProviderTransformer: exact match for %s serving %s", p, dag.VertexName(v)) 179 } 180 181 // if we don't have a provider at this level, walk up the path looking for one, 182 // unless we were told to be exact. 183 if target == nil && !req.Exact { 184 for pp, ok := p.Inherited(); ok; pp, ok = pp.Inherited() { 185 key := pp.String() 186 target = m[key] 187 if target != nil { 188 log.Printf("[TRACE] ProviderTransformer: %s uses inherited configuration %s", dag.VertexName(v), pp) 189 break 190 } 191 log.Printf("[TRACE] ProviderTransformer: looking for %s to serve %s", pp, dag.VertexName(v)) 192 } 193 } 194 195 // If this provider doesn't need to be configured then we can just 196 // stub it out with an init-only provider node, which will just 197 // start up the provider and fetch its schema. 198 if _, exists := needConfigured[key]; target == nil && !exists { 199 stubAddr := addrs.AbsProviderConfig{ 200 Module: addrs.RootModule, 201 Provider: p.Provider, 202 } 203 stub := &NodeEvalableProvider{ 204 &NodeAbstractProvider{ 205 Addr: stubAddr, 206 }, 207 } 208 m[stubAddr.String()] = stub 209 log.Printf("[TRACE] ProviderTransformer: creating init-only node for %s", stubAddr) 210 target = stub 211 g.Add(target) 212 } 213 214 if target == nil { 215 diags = diags.Append(tfdiags.Sourceless( 216 tfdiags.Error, 217 "Provider configuration not present", 218 fmt.Sprintf( 219 "To work with %s its original provider configuration at %s is required, but it has been removed. This occurs when a provider configuration is removed while objects created by that provider still exist in the state. Re-add the provider configuration to destroy %s, after which you can remove the provider configuration again.", 220 dag.VertexName(v), p, dag.VertexName(v), 221 ), 222 )) 223 break 224 } 225 226 // see if this is a proxy provider pointing to another concrete config 227 if p, ok := target.(*graphNodeProxyProvider); ok { 228 g.Remove(p) 229 target = p.Target() 230 } 231 232 log.Printf("[DEBUG] ProviderTransformer: %q (%T) needs %s", dag.VertexName(v), v, dag.VertexName(target)) 233 if pv, ok := v.(GraphNodeProviderConsumer); ok { 234 pv.SetProvider(target.ProviderAddr()) 235 } 236 g.Connect(dag.BasicEdge(v, target)) 237 } 238 } 239 240 return diags.Err() 241 } 242 243 // CloseProviderTransformer is a GraphTransformer that adds nodes to the 244 // graph that will close open provider connections that aren't needed anymore. 245 // A provider connection is not needed anymore once all depended resources 246 // in the graph are evaluated. 247 type CloseProviderTransformer struct{} 248 249 func (t *CloseProviderTransformer) Transform(g *Graph) error { 250 pm := providerVertexMap(g) 251 cpm := make(map[string]*graphNodeCloseProvider) 252 var err error 253 254 for _, p := range pm { 255 key := p.ProviderAddr().String() 256 257 // get the close provider of this type if we alread created it 258 closer := cpm[key] 259 260 if closer == nil { 261 // create a closer for this provider type 262 closer = &graphNodeCloseProvider{Addr: p.ProviderAddr()} 263 g.Add(closer) 264 cpm[key] = closer 265 } 266 267 // Close node depends on the provider itself 268 // this is added unconditionally, so it will connect to all instances 269 // of the provider. Extra edges will be removed by transitive 270 // reduction. 271 g.Connect(dag.BasicEdge(closer, p)) 272 273 // connect all the provider's resources to the close node 274 for _, s := range g.UpEdges(p) { 275 if _, ok := s.(GraphNodeProviderConsumer); ok { 276 g.Connect(dag.BasicEdge(closer, s)) 277 } 278 } 279 } 280 281 return err 282 } 283 284 // MissingProviderTransformer is a GraphTransformer that adds to the graph 285 // a node for each default provider configuration that is referenced by another 286 // node but not already present in the graph. 287 // 288 // These "default" nodes are always added to the root module, regardless of 289 // where they are requested. This is important because our inheritance 290 // resolution behavior in ProviderTransformer will then treat these as a 291 // last-ditch fallback after walking up the tree, rather than preferring them 292 // as it would if they were placed in the same module as the requester. 293 // 294 // This transformer may create extra nodes that are not needed in practice, 295 // due to overriding provider configurations in child modules. 296 // PruneProviderTransformer can then remove these once ProviderTransformer 297 // has resolved all of the inheritence, etc. 298 type MissingProviderTransformer struct { 299 // MissingProviderTransformer needs the config to rule out _implied_ default providers 300 Config *configs.Config 301 302 // Concrete, if set, overrides how the providers are made. 303 Concrete ConcreteProviderNodeFunc 304 } 305 306 func (t *MissingProviderTransformer) Transform(g *Graph) error { 307 // Initialize factory 308 if t.Concrete == nil { 309 t.Concrete = func(a *NodeAbstractProvider) dag.Vertex { 310 return a 311 } 312 } 313 314 var err error 315 m := providerVertexMap(g) 316 for _, v := range g.Vertices() { 317 pv, ok := v.(GraphNodeProviderConsumer) 318 if !ok { 319 continue 320 } 321 322 // For our work here we actually care only about the provider type and 323 // we plan to place all default providers in the root module. 324 providerFqn := pv.Provider() 325 326 // We're going to create an implicit _default_ configuration for the 327 // referenced provider type in the _root_ module, ignoring all other 328 // aspects of the resource's declared provider address. 329 defaultAddr := addrs.RootModuleInstance.ProviderConfigDefault(providerFqn) 330 key := defaultAddr.String() 331 provider := m[key] 332 333 if provider != nil { 334 // There's already an explicit default configuration for this 335 // provider type in the root module, so we have nothing to do. 336 continue 337 } 338 339 log.Printf("[DEBUG] adding implicit provider configuration %s, implied first by %s", defaultAddr, dag.VertexName(v)) 340 341 // create the missing top-level provider 342 provider = t.Concrete(&NodeAbstractProvider{ 343 Addr: defaultAddr, 344 }).(GraphNodeProvider) 345 346 g.Add(provider) 347 m[key] = provider 348 } 349 350 return err 351 } 352 353 // PruneProviderTransformer removes any providers that are not actually used by 354 // anything, and provider proxies. This avoids the provider being initialized 355 // and configured. This both saves resources but also avoids errors since 356 // configuration may imply initialization which may require auth. 357 type PruneProviderTransformer struct{} 358 359 func (t *PruneProviderTransformer) Transform(g *Graph) error { 360 for _, v := range g.Vertices() { 361 // We only care about providers 362 _, ok := v.(GraphNodeProvider) 363 if !ok { 364 continue 365 } 366 367 // ProxyProviders will have up edges, but we're now done with them in the graph 368 if _, ok := v.(*graphNodeProxyProvider); ok { 369 log.Printf("[DEBUG] pruning proxy %s", dag.VertexName(v)) 370 g.Remove(v) 371 } 372 373 // Remove providers with no dependencies. 374 if g.UpEdges(v).Len() == 0 { 375 log.Printf("[DEBUG] pruning unused %s", dag.VertexName(v)) 376 g.Remove(v) 377 } 378 } 379 380 return nil 381 } 382 383 func providerVertexMap(g *Graph) map[string]GraphNodeProvider { 384 m := make(map[string]GraphNodeProvider) 385 for _, v := range g.Vertices() { 386 if pv, ok := v.(GraphNodeProvider); ok { 387 addr := pv.ProviderAddr() 388 m[addr.String()] = pv 389 } 390 } 391 392 return m 393 } 394 395 type graphNodeCloseProvider struct { 396 Addr addrs.AbsProviderConfig 397 } 398 399 var ( 400 _ GraphNodeCloseProvider = (*graphNodeCloseProvider)(nil) 401 _ GraphNodeExecutable = (*graphNodeCloseProvider)(nil) 402 ) 403 404 func (n *graphNodeCloseProvider) Name() string { 405 return n.Addr.String() + " (close)" 406 } 407 408 // GraphNodeModulePath 409 func (n *graphNodeCloseProvider) ModulePath() addrs.Module { 410 return n.Addr.Module 411 } 412 413 // GraphNodeExecutable impl. 414 func (n *graphNodeCloseProvider) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) { 415 return diags.Append(ctx.CloseProvider(n.Addr)) 416 } 417 418 func (n *graphNodeCloseProvider) CloseProviderAddr() addrs.AbsProviderConfig { 419 return n.Addr 420 } 421 422 // GraphNodeDotter impl. 423 func (n *graphNodeCloseProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { 424 if !opts.Verbose { 425 return nil 426 } 427 return &dag.DotNode{ 428 Name: name, 429 Attrs: map[string]string{ 430 "label": n.Name(), 431 "shape": "diamond", 432 }, 433 } 434 } 435 436 // graphNodeProxyProvider is a GraphNodeProvider implementation that is used to 437 // store the name and value of a provider node for inheritance between modules. 438 // These nodes are only used to store the data while loading the provider 439 // configurations, and are removed after all the resources have been connected 440 // to their providers. 441 type graphNodeProxyProvider struct { 442 addr addrs.AbsProviderConfig 443 target GraphNodeProvider 444 } 445 446 var ( 447 _ GraphNodeModulePath = (*graphNodeProxyProvider)(nil) 448 _ GraphNodeProvider = (*graphNodeProxyProvider)(nil) 449 ) 450 451 func (n *graphNodeProxyProvider) ProviderAddr() addrs.AbsProviderConfig { 452 return n.addr 453 } 454 455 func (n *graphNodeProxyProvider) ModulePath() addrs.Module { 456 return n.addr.Module 457 } 458 459 func (n *graphNodeProxyProvider) Name() string { 460 return n.addr.String() + " (proxy)" 461 } 462 463 // find the concrete provider instance 464 func (n *graphNodeProxyProvider) Target() GraphNodeProvider { 465 switch t := n.target.(type) { 466 case *graphNodeProxyProvider: 467 return t.Target() 468 default: 469 return n.target 470 } 471 } 472 473 // ProviderConfigTransformer adds all provider nodes from the configuration and 474 // attaches the configs. 475 type ProviderConfigTransformer struct { 476 Concrete ConcreteProviderNodeFunc 477 478 // each provider node is stored here so that the proxy nodes can look up 479 // their targets by name. 480 providers map[string]GraphNodeProvider 481 // record providers that can be overriden with a proxy 482 proxiable map[string]bool 483 484 // Config is the root node of the configuration tree to add providers from. 485 Config *configs.Config 486 } 487 488 func (t *ProviderConfigTransformer) Transform(g *Graph) error { 489 // If no configuration is given, we don't do anything 490 if t.Config == nil { 491 return nil 492 } 493 494 t.providers = make(map[string]GraphNodeProvider) 495 t.proxiable = make(map[string]bool) 496 497 // Start the transformation process 498 if err := t.transform(g, t.Config); err != nil { 499 return err 500 } 501 502 // finally attach the configs to the new nodes 503 return t.attachProviderConfigs(g) 504 } 505 506 func (t *ProviderConfigTransformer) transform(g *Graph, c *configs.Config) error { 507 // If no config, do nothing 508 if c == nil { 509 return nil 510 } 511 512 // Add our resources 513 if err := t.transformSingle(g, c); err != nil { 514 return err 515 } 516 517 // Transform all the children. 518 for _, cc := range c.Children { 519 if err := t.transform(g, cc); err != nil { 520 return err 521 } 522 } 523 return nil 524 } 525 526 func (t *ProviderConfigTransformer) transformSingle(g *Graph, c *configs.Config) error { 527 // Get the module associated with this configuration tree node 528 mod := c.Module 529 path := c.Path 530 531 // If this is the root module, we can add nodes for required providers that 532 // have no configuration, equivalent to having an empty configuration 533 // block. This will ensure that a provider node exists for modules to 534 // access when passing around configuration and inheritance. 535 if path.IsRoot() && c.Module.ProviderRequirements != nil { 536 for name, p := range c.Module.ProviderRequirements.RequiredProviders { 537 if _, configured := mod.ProviderConfigs[name]; configured { 538 continue 539 } 540 541 addr := addrs.AbsProviderConfig{ 542 Provider: p.Type, 543 Module: path, 544 } 545 546 if _, ok := t.providers[addr.String()]; ok { 547 // The config validation warns about this too, but we can't 548 // completely prevent it in v1. 549 log.Printf("[WARN] ProviderConfigTransformer: duplicate required_providers entry for %s", addr) 550 continue 551 } 552 553 abstract := &NodeAbstractProvider{ 554 Addr: addr, 555 } 556 557 var v dag.Vertex 558 if t.Concrete != nil { 559 v = t.Concrete(abstract) 560 } else { 561 v = abstract 562 } 563 564 g.Add(v) 565 t.providers[addr.String()] = v.(GraphNodeProvider) 566 } 567 } 568 569 // add all providers from the configuration 570 for _, p := range mod.ProviderConfigs { 571 fqn := mod.ProviderForLocalConfig(p.Addr()) 572 addr := addrs.AbsProviderConfig{ 573 Provider: fqn, 574 Alias: p.Alias, 575 Module: path, 576 } 577 578 if _, ok := t.providers[addr.String()]; ok { 579 // The abstract provider node may already have been added from the 580 // provider requirements. 581 log.Printf("[WARN] ProviderConfigTransformer: provider node %s already added", addr) 582 continue 583 } 584 585 abstract := &NodeAbstractProvider{ 586 Addr: addr, 587 } 588 var v dag.Vertex 589 if t.Concrete != nil { 590 v = t.Concrete(abstract) 591 } else { 592 v = abstract 593 } 594 595 // Add it to the graph 596 g.Add(v) 597 key := addr.String() 598 t.providers[key] = v.(GraphNodeProvider) 599 600 // While deprecated, we still accept empty configuration blocks within 601 // modules as being a possible proxy for passed configuration. 602 if !path.IsRoot() { 603 // A provider configuration is "proxyable" if its configuration is 604 // entirely empty. This means it's standing in for a provider 605 // configuration that must be passed in from the parent module. 606 // We decide this by evaluating the config with an empty schema; 607 // if this succeeds, then we know there's nothing in the body. 608 _, diags := p.Config.Content(&hcl.BodySchema{}) 609 t.proxiable[key] = !diags.HasErrors() 610 } 611 } 612 613 // Now replace the provider nodes with proxy nodes if a provider was being 614 // passed in, and create implicit proxies if there was no config. Any extra 615 // proxies will be removed in the prune step. 616 return t.addProxyProviders(g, c) 617 } 618 619 func (t *ProviderConfigTransformer) addProxyProviders(g *Graph, c *configs.Config) error { 620 path := c.Path 621 622 // can't add proxies at the root 623 if path.IsRoot() { 624 return nil 625 } 626 627 parentPath, callAddr := path.Call() 628 parent := c.Parent 629 if parent == nil { 630 return nil 631 } 632 633 callName := callAddr.Name 634 var parentCfg *configs.ModuleCall 635 for name, mod := range parent.Module.ModuleCalls { 636 if name == callName { 637 parentCfg = mod 638 break 639 } 640 } 641 642 if parentCfg == nil { 643 // this can't really happen during normal execution. 644 return fmt.Errorf("parent module config not found for %s", c.Path.String()) 645 } 646 647 // Go through all the providers the parent is passing in, and add proxies to 648 // the parent provider nodes. 649 for _, pair := range parentCfg.Providers { 650 fqn := c.Module.ProviderForLocalConfig(pair.InChild.Addr()) 651 fullAddr := addrs.AbsProviderConfig{ 652 Provider: fqn, 653 Module: path, 654 Alias: pair.InChild.Addr().Alias, 655 } 656 657 fullParentAddr := addrs.AbsProviderConfig{ 658 Provider: fqn, 659 Module: parentPath, 660 Alias: pair.InParent.Addr().Alias, 661 } 662 663 fullName := fullAddr.String() 664 fullParentName := fullParentAddr.String() 665 666 parentProvider := t.providers[fullParentName] 667 668 if parentProvider == nil { 669 return fmt.Errorf("missing provider %s", fullParentName) 670 } 671 672 proxy := &graphNodeProxyProvider{ 673 addr: fullAddr, 674 target: parentProvider, 675 } 676 677 concreteProvider := t.providers[fullName] 678 679 // replace the concrete node with the provider passed in only if it is 680 // proxyable 681 if concreteProvider != nil { 682 if t.proxiable[fullName] { 683 g.Replace(concreteProvider, proxy) 684 t.providers[fullName] = proxy 685 } 686 continue 687 } 688 689 // There was no concrete provider, so add this as an implicit provider. 690 // The extra proxy will be pruned later if it's unused. 691 g.Add(proxy) 692 t.providers[fullName] = proxy 693 } 694 695 return nil 696 } 697 698 func (t *ProviderConfigTransformer) attachProviderConfigs(g *Graph) error { 699 for _, v := range g.Vertices() { 700 // Only care about GraphNodeAttachProvider implementations 701 apn, ok := v.(GraphNodeAttachProvider) 702 if !ok { 703 continue 704 } 705 706 // Determine what we're looking for 707 addr := apn.ProviderAddr() 708 709 // Get the configuration. 710 mc := t.Config.Descendent(addr.Module) 711 if mc == nil { 712 log.Printf("[TRACE] ProviderConfigTransformer: no configuration available for %s", addr.String()) 713 continue 714 } 715 716 // Find the localName for the provider fqn 717 localName := mc.Module.LocalNameForProvider(addr.Provider) 718 719 // Go through the provider configs to find the matching config 720 for _, p := range mc.Module.ProviderConfigs { 721 if p.Name == localName && p.Alias == addr.Alias { 722 log.Printf("[TRACE] ProviderConfigTransformer: attaching to %q provider configuration from %s", dag.VertexName(v), p.DeclRange) 723 apn.AttachProvider(p) 724 break 725 } 726 } 727 } 728 729 return nil 730 }