github.com/leighwaller/terraform@v0.11.12-beta1/terraform/transform_provider.go (about) 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 }