github.com/jrasell/terraform@v0.6.17-0.20160523115548-2652f5232949/terraform/transform_provider.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/go-multierror" 9 "github.com/hashicorp/terraform/config" 10 "github.com/hashicorp/terraform/dag" 11 "github.com/hashicorp/terraform/dot" 12 ) 13 14 // GraphNodeProvider is an interface that nodes that can be a provider 15 // must implement. The ProviderName returned is the name of the provider 16 // they satisfy. 17 type GraphNodeProvider interface { 18 ProviderName() string 19 ProviderConfig() *config.RawConfig 20 } 21 22 // GraphNodeCloseProvider is an interface that nodes that can be a close 23 // provider must implement. The CloseProviderName returned is the name of 24 // the provider they satisfy. 25 type GraphNodeCloseProvider interface { 26 CloseProviderName() string 27 } 28 29 // GraphNodeProviderConsumer is an interface that nodes that require 30 // a provider must implement. ProvidedBy must return the name of the provider 31 // to use. 32 type GraphNodeProviderConsumer interface { 33 ProvidedBy() []string 34 } 35 36 // DisableProviderTransformer "disables" any providers that are only 37 // depended on by modules. 38 type DisableProviderTransformer struct{} 39 40 func (t *DisableProviderTransformer) Transform(g *Graph) error { 41 // Since we're comparing against edges, we need to make sure we connect 42 g.ConnectDependents() 43 44 for _, v := range g.Vertices() { 45 // We only care about providers 46 pn, ok := v.(GraphNodeProvider) 47 if !ok || pn.ProviderName() == "" { 48 continue 49 } 50 51 // Go through all the up-edges (things that depend on this 52 // provider) and if any is not a module, then ignore this node. 53 nonModule := false 54 for _, sourceRaw := range g.UpEdges(v).List() { 55 source := sourceRaw.(dag.Vertex) 56 cn, ok := source.(graphNodeConfig) 57 if !ok { 58 nonModule = true 59 break 60 } 61 62 if cn.ConfigType() != GraphNodeConfigTypeModule { 63 nonModule = true 64 break 65 } 66 } 67 if nonModule { 68 // We found something that depends on this provider that 69 // isn't a module, so skip it. 70 continue 71 } 72 73 // Disable the provider by replacing it with a "disabled" provider 74 disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn} 75 if !g.Replace(v, disabled) { 76 panic(fmt.Sprintf( 77 "vertex disappeared from under us: %s", 78 dag.VertexName(v))) 79 } 80 } 81 82 return nil 83 } 84 85 // ProviderTransformer is a GraphTransformer that maps resources to 86 // providers within the graph. This will error if there are any resources 87 // that don't map to proper resources. 88 type ProviderTransformer struct{} 89 90 func (t *ProviderTransformer) Transform(g *Graph) error { 91 // Go through the other nodes and match them to providers they need 92 var err error 93 m := providerVertexMap(g) 94 for _, v := range g.Vertices() { 95 if pv, ok := v.(GraphNodeProviderConsumer); ok { 96 for _, p := range pv.ProvidedBy() { 97 target := m[providerMapKey(p, pv)] 98 if target == nil { 99 println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv))) 100 err = multierror.Append(err, fmt.Errorf( 101 "%s: provider %s couldn't be found", 102 dag.VertexName(v), p)) 103 continue 104 } 105 106 g.Connect(dag.BasicEdge(v, target)) 107 } 108 } 109 } 110 111 return err 112 } 113 114 // CloseProviderTransformer is a GraphTransformer that adds nodes to the 115 // graph that will close open provider connections that aren't needed anymore. 116 // A provider connection is not needed anymore once all depended resources 117 // in the graph are evaluated. 118 type CloseProviderTransformer struct{} 119 120 func (t *CloseProviderTransformer) Transform(g *Graph) error { 121 pm := providerVertexMap(g) 122 cpm := closeProviderVertexMap(g) 123 var err error 124 for _, v := range g.Vertices() { 125 if pv, ok := v.(GraphNodeProviderConsumer); ok { 126 for _, p := range pv.ProvidedBy() { 127 key := p 128 source := cpm[key] 129 130 if source == nil { 131 // Create a new graphNodeCloseProvider and add it to the graph 132 source = &graphNodeCloseProvider{ProviderNameValue: p} 133 g.Add(source) 134 135 // Close node needs to depend on provider 136 provider, ok := pm[key] 137 if !ok { 138 err = multierror.Append(err, fmt.Errorf( 139 "%s: provider %s couldn't be found for closing", 140 dag.VertexName(v), p)) 141 continue 142 } 143 g.Connect(dag.BasicEdge(source, provider)) 144 145 // Make sure we also add the new graphNodeCloseProvider to the map 146 // so we don't create and add any duplicate graphNodeCloseProviders. 147 cpm[key] = source 148 } 149 150 // Close node depends on all nodes provided by the provider 151 g.Connect(dag.BasicEdge(source, v)) 152 } 153 } 154 } 155 156 return err 157 } 158 159 // MissingProviderTransformer is a GraphTransformer that adds nodes 160 // for missing providers into the graph. Specifically, it creates provider 161 // configuration nodes for all the providers that we support. These are 162 // pruned later during an optimization pass. 163 type MissingProviderTransformer struct { 164 // Providers is the list of providers we support. 165 Providers []string 166 } 167 168 func (t *MissingProviderTransformer) Transform(g *Graph) error { 169 // Create a set of our supported providers 170 supported := make(map[string]struct{}, len(t.Providers)) 171 for _, v := range t.Providers { 172 supported[v] = struct{}{} 173 } 174 175 // Get the map of providers we already have in our graph 176 m := providerVertexMap(g) 177 178 // Go through all the provider consumers and make sure we add 179 // that provider if it is missing. We use a for loop here instead 180 // of "range" since we'll modify check as we go to add more to check. 181 check := g.Vertices() 182 for i := 0; i < len(check); i++ { 183 v := check[i] 184 185 pv, ok := v.(GraphNodeProviderConsumer) 186 if !ok { 187 continue 188 } 189 190 // If this node has a subpath, then we use that as a prefix 191 // into our map to check for an existing provider. 192 var path []string 193 if sp, ok := pv.(GraphNodeSubPath); ok { 194 raw := normalizeModulePath(sp.Path()) 195 if len(raw) > len(rootModulePath) { 196 path = raw 197 } 198 } 199 200 for _, p := range pv.ProvidedBy() { 201 key := providerMapKey(p, pv) 202 if _, ok := m[key]; ok { 203 // This provider already exists as a configure node 204 continue 205 } 206 207 // If the provider has an alias in it, we just want the type 208 ptype := p 209 if idx := strings.IndexRune(p, '.'); idx != -1 { 210 ptype = p[:idx] 211 } 212 213 if _, ok := supported[ptype]; !ok { 214 // If we don't support the provider type, skip it. 215 // Validation later will catch this as an error. 216 continue 217 } 218 219 // Add the missing provider node to the graph 220 raw := &graphNodeProvider{ProviderNameValue: p} 221 var v dag.Vertex = raw 222 if len(path) > 0 { 223 var err error 224 v, err = raw.Flatten(path) 225 if err != nil { 226 return err 227 } 228 229 // We'll need the parent provider as well, so let's 230 // add a dummy node to check to make sure that we add 231 // that parent provider. 232 check = append(check, &graphNodeProviderConsumerDummy{ 233 ProviderValue: p, 234 PathValue: path[:len(path)-1], 235 }) 236 } 237 238 m[key] = g.Add(v) 239 } 240 } 241 242 return nil 243 } 244 245 // PruneProviderTransformer is a GraphTransformer that prunes all the 246 // providers that aren't needed from the graph. A provider is unneeded if 247 // no resource or module is using that provider. 248 type PruneProviderTransformer struct{} 249 250 func (t *PruneProviderTransformer) Transform(g *Graph) error { 251 for _, v := range g.Vertices() { 252 // We only care about the providers 253 if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" { 254 continue 255 } 256 // Does anything depend on this? If not, then prune it. 257 if s := g.UpEdges(v); s.Len() == 0 { 258 if nv, ok := v.(dag.NamedVertex); ok { 259 log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name()) 260 } 261 g.Remove(v) 262 } 263 } 264 265 return nil 266 } 267 268 // providerMapKey is a helper that gives us the key to use for the 269 // maps returned by things such as providerVertexMap. 270 func providerMapKey(k string, v dag.Vertex) string { 271 pathPrefix := "" 272 if sp, ok := v.(GraphNodeSubPath); ok { 273 raw := normalizeModulePath(sp.Path()) 274 if len(raw) > len(rootModulePath) { 275 pathPrefix = modulePrefixStr(raw) + "." 276 } 277 } 278 279 return pathPrefix + k 280 } 281 282 func providerVertexMap(g *Graph) map[string]dag.Vertex { 283 m := make(map[string]dag.Vertex) 284 for _, v := range g.Vertices() { 285 if pv, ok := v.(GraphNodeProvider); ok { 286 m[pv.ProviderName()] = v 287 } 288 } 289 290 return m 291 } 292 293 func closeProviderVertexMap(g *Graph) map[string]dag.Vertex { 294 m := make(map[string]dag.Vertex) 295 for _, v := range g.Vertices() { 296 if pv, ok := v.(GraphNodeCloseProvider); ok { 297 m[pv.CloseProviderName()] = v 298 } 299 } 300 301 return m 302 } 303 304 type graphNodeDisabledProvider struct { 305 GraphNodeProvider 306 } 307 308 // GraphNodeEvalable impl. 309 func (n *graphNodeDisabledProvider) EvalTree() EvalNode { 310 var resourceConfig *ResourceConfig 311 312 return &EvalOpFilter{ 313 Ops: []walkOperation{walkInput, walkValidate, walkRefresh, walkPlan, walkApply, walkDestroy}, 314 Node: &EvalSequence{ 315 Nodes: []EvalNode{ 316 &EvalInterpolate{ 317 Config: n.ProviderConfig(), 318 Output: &resourceConfig, 319 }, 320 &EvalBuildProviderConfig{ 321 Provider: n.ProviderName(), 322 Config: &resourceConfig, 323 Output: &resourceConfig, 324 }, 325 &EvalSetProviderConfig{ 326 Provider: n.ProviderName(), 327 Config: &resourceConfig, 328 }, 329 }, 330 }, 331 } 332 } 333 334 // GraphNodeFlattenable impl. 335 func (n *graphNodeDisabledProvider) Flatten(p []string) (dag.Vertex, error) { 336 return &graphNodeDisabledProviderFlat{ 337 graphNodeDisabledProvider: n, 338 PathValue: p, 339 }, nil 340 } 341 342 func (n *graphNodeDisabledProvider) Name() string { 343 return fmt.Sprintf("%s (disabled)", dag.VertexName(n.GraphNodeProvider)) 344 } 345 346 // GraphNodeDotter impl. 347 func (n *graphNodeDisabledProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 348 return dot.NewNode(name, map[string]string{ 349 "label": n.Name(), 350 "shape": "diamond", 351 }) 352 } 353 354 // GraphNodeDotterOrigin impl. 355 func (n *graphNodeDisabledProvider) DotOrigin() bool { 356 return true 357 } 358 359 // GraphNodeDependable impl. 360 func (n *graphNodeDisabledProvider) DependableName() []string { 361 return []string{"provider." + n.ProviderName()} 362 } 363 364 // GraphNodeProvider impl. 365 func (n *graphNodeDisabledProvider) ProviderName() string { 366 return n.GraphNodeProvider.ProviderName() 367 } 368 369 // GraphNodeProvider impl. 370 func (n *graphNodeDisabledProvider) ProviderConfig() *config.RawConfig { 371 return n.GraphNodeProvider.ProviderConfig() 372 } 373 374 // Same as graphNodeDisabledProvider, but for flattening 375 type graphNodeDisabledProviderFlat struct { 376 *graphNodeDisabledProvider 377 378 PathValue []string 379 } 380 381 func (n *graphNodeDisabledProviderFlat) Name() string { 382 return fmt.Sprintf( 383 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeDisabledProvider.Name()) 384 } 385 386 func (n *graphNodeDisabledProviderFlat) Path() []string { 387 return n.PathValue 388 } 389 390 func (n *graphNodeDisabledProviderFlat) ProviderName() string { 391 return fmt.Sprintf( 392 "%s.%s", modulePrefixStr(n.PathValue), 393 n.graphNodeDisabledProvider.ProviderName()) 394 } 395 396 // GraphNodeDependable impl. 397 func (n *graphNodeDisabledProviderFlat) DependableName() []string { 398 return modulePrefixList( 399 n.graphNodeDisabledProvider.DependableName(), 400 modulePrefixStr(n.PathValue)) 401 } 402 403 func (n *graphNodeDisabledProviderFlat) DependentOn() []string { 404 var result []string 405 406 // If we're in a module, then depend on our parent's provider 407 if len(n.PathValue) > 1 { 408 prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) 409 result = modulePrefixList( 410 n.graphNodeDisabledProvider.DependableName(), prefix) 411 } 412 413 return result 414 } 415 416 type graphNodeCloseProvider struct { 417 ProviderNameValue string 418 } 419 420 func (n *graphNodeCloseProvider) Name() string { 421 return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue) 422 } 423 424 // GraphNodeEvalable impl. 425 func (n *graphNodeCloseProvider) EvalTree() EvalNode { 426 return CloseProviderEvalTree(n.ProviderNameValue) 427 } 428 429 // GraphNodeDependable impl. 430 func (n *graphNodeCloseProvider) DependableName() []string { 431 return []string{n.Name()} 432 } 433 434 func (n *graphNodeCloseProvider) CloseProviderName() string { 435 return n.ProviderNameValue 436 } 437 438 // GraphNodeDotter impl. 439 func (n *graphNodeCloseProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 440 if !opts.Verbose { 441 return nil 442 } 443 return dot.NewNode(name, map[string]string{ 444 "label": n.Name(), 445 "shape": "diamond", 446 }) 447 } 448 449 type graphNodeProvider struct { 450 ProviderNameValue string 451 } 452 453 func (n *graphNodeProvider) Name() string { 454 return fmt.Sprintf("provider.%s", n.ProviderNameValue) 455 } 456 457 // GraphNodeEvalable impl. 458 func (n *graphNodeProvider) EvalTree() EvalNode { 459 return ProviderEvalTree(n.ProviderNameValue, nil) 460 } 461 462 // GraphNodeDependable impl. 463 func (n *graphNodeProvider) DependableName() []string { 464 return []string{n.Name()} 465 } 466 467 func (n *graphNodeProvider) ProviderName() string { 468 return n.ProviderNameValue 469 } 470 471 func (n *graphNodeProvider) ProviderConfig() *config.RawConfig { 472 return nil 473 } 474 475 // GraphNodeDotter impl. 476 func (n *graphNodeProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 477 return dot.NewNode(name, map[string]string{ 478 "label": n.Name(), 479 "shape": "diamond", 480 }) 481 } 482 483 // GraphNodeDotterOrigin impl. 484 func (n *graphNodeProvider) DotOrigin() bool { 485 return true 486 } 487 488 // GraphNodeFlattenable impl. 489 func (n *graphNodeProvider) Flatten(p []string) (dag.Vertex, error) { 490 return &graphNodeProviderFlat{ 491 graphNodeProvider: n, 492 PathValue: p, 493 }, nil 494 } 495 496 // Same as graphNodeMissingProvider, but for flattening 497 type graphNodeProviderFlat struct { 498 *graphNodeProvider 499 500 PathValue []string 501 } 502 503 func (n *graphNodeProviderFlat) Name() string { 504 return fmt.Sprintf( 505 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeProvider.Name()) 506 } 507 508 func (n *graphNodeProviderFlat) Path() []string { 509 return n.PathValue 510 } 511 512 func (n *graphNodeProviderFlat) ProviderName() string { 513 return fmt.Sprintf( 514 "%s.%s", modulePrefixStr(n.PathValue), 515 n.graphNodeProvider.ProviderName()) 516 } 517 518 // GraphNodeDependable impl. 519 func (n *graphNodeProviderFlat) DependableName() []string { 520 return []string{n.Name()} 521 } 522 523 func (n *graphNodeProviderFlat) DependentOn() []string { 524 var result []string 525 526 // If we're in a module, then depend on our parent's provider 527 if len(n.PathValue) > 1 { 528 prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) 529 result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix) 530 } 531 532 return result 533 } 534 535 // graphNodeProviderConsumerDummy is a struct that never enters the real 536 // graph (though it could to no ill effect). It implements 537 // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force 538 // certain transformations. 539 type graphNodeProviderConsumerDummy struct { 540 ProviderValue string 541 PathValue []string 542 } 543 544 func (n *graphNodeProviderConsumerDummy) Path() []string { 545 return n.PathValue 546 } 547 548 func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string { 549 return []string{n.ProviderValue} 550 }