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