github.com/rhenning/terraform@v0.8.0-beta2/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 ) 12 13 // GraphNodeProvider is an interface that nodes that can be a provider 14 // must implement. The ProviderName returned is the name of the provider 15 // they satisfy. 16 type GraphNodeProvider interface { 17 ProviderName() string 18 ProviderConfig() *config.RawConfig 19 } 20 21 // GraphNodeCloseProvider is an interface that nodes that can be a close 22 // provider must implement. The CloseProviderName returned is the name of 23 // the provider they satisfy. 24 type GraphNodeCloseProvider interface { 25 CloseProviderName() string 26 } 27 28 // GraphNodeProviderConsumer is an interface that nodes that require 29 // a provider must implement. ProvidedBy must return the name of the provider 30 // to use. 31 type GraphNodeProviderConsumer interface { 32 ProvidedBy() []string 33 } 34 35 // ProviderTransformer is a GraphTransformer that maps resources to 36 // providers within the graph. This will error if there are any resources 37 // that don't map to proper resources. 38 type ProviderTransformer struct{} 39 40 func (t *ProviderTransformer) Transform(g *Graph) error { 41 // Go through the other nodes and match them to providers they need 42 var err error 43 m := providerVertexMap(g) 44 for _, v := range g.Vertices() { 45 if pv, ok := v.(GraphNodeProviderConsumer); ok { 46 for _, p := range pv.ProvidedBy() { 47 target := m[providerMapKey(p, pv)] 48 if target == nil { 49 println(fmt.Sprintf("%#v\n\n%#v", m, providerMapKey(p, pv))) 50 err = multierror.Append(err, fmt.Errorf( 51 "%s: provider %s couldn't be found", 52 dag.VertexName(v), p)) 53 continue 54 } 55 56 g.Connect(dag.BasicEdge(v, target)) 57 } 58 } 59 } 60 61 return err 62 } 63 64 // CloseProviderTransformer is a GraphTransformer that adds nodes to the 65 // graph that will close open provider connections that aren't needed anymore. 66 // A provider connection is not needed anymore once all depended resources 67 // in the graph are evaluated. 68 type CloseProviderTransformer struct{} 69 70 func (t *CloseProviderTransformer) Transform(g *Graph) error { 71 pm := providerVertexMap(g) 72 cpm := closeProviderVertexMap(g) 73 var err error 74 for _, v := range g.Vertices() { 75 if pv, ok := v.(GraphNodeProviderConsumer); ok { 76 for _, p := range pv.ProvidedBy() { 77 key := p 78 source := cpm[key] 79 80 if source == nil { 81 // Create a new graphNodeCloseProvider and add it to the graph 82 source = &graphNodeCloseProvider{ProviderNameValue: p} 83 g.Add(source) 84 85 // Close node needs to depend on provider 86 provider, ok := pm[key] 87 if !ok { 88 err = multierror.Append(err, fmt.Errorf( 89 "%s: provider %s couldn't be found for closing", 90 dag.VertexName(v), p)) 91 continue 92 } 93 g.Connect(dag.BasicEdge(source, provider)) 94 95 // Make sure we also add the new graphNodeCloseProvider to the map 96 // so we don't create and add any duplicate graphNodeCloseProviders. 97 cpm[key] = source 98 } 99 100 // Close node depends on all nodes provided by the provider 101 g.Connect(dag.BasicEdge(source, v)) 102 } 103 } 104 } 105 106 return err 107 } 108 109 // MissingProviderTransformer is a GraphTransformer that adds nodes 110 // for missing providers into the graph. Specifically, it creates provider 111 // configuration nodes for all the providers that we support. These are 112 // pruned later during an optimization pass. 113 type MissingProviderTransformer struct { 114 // Providers is the list of providers we support. 115 Providers []string 116 117 // Factory, if set, overrides how the providers are made. 118 Factory func(name string, path []string) GraphNodeProvider 119 } 120 121 func (t *MissingProviderTransformer) Transform(g *Graph) error { 122 // Initialize factory 123 if t.Factory == nil { 124 t.Factory = func(name string, path []string) GraphNodeProvider { 125 return &graphNodeProvider{ProviderNameValue: name} 126 } 127 } 128 129 // Create a set of our supported providers 130 supported := make(map[string]struct{}, len(t.Providers)) 131 for _, v := range t.Providers { 132 supported[v] = struct{}{} 133 } 134 135 // Get the map of providers we already have in our graph 136 m := providerVertexMap(g) 137 138 // Go through all the provider consumers and make sure we add 139 // that provider if it is missing. We use a for loop here instead 140 // of "range" since we'll modify check as we go to add more to check. 141 check := g.Vertices() 142 for i := 0; i < len(check); i++ { 143 v := check[i] 144 145 pv, ok := v.(GraphNodeProviderConsumer) 146 if !ok { 147 continue 148 } 149 150 // If this node has a subpath, then we use that as a prefix 151 // into our map to check for an existing provider. 152 var path []string 153 if sp, ok := pv.(GraphNodeSubPath); ok { 154 raw := normalizeModulePath(sp.Path()) 155 if len(raw) > len(rootModulePath) { 156 path = raw 157 } 158 } 159 160 for _, p := range pv.ProvidedBy() { 161 key := providerMapKey(p, pv) 162 if _, ok := m[key]; ok { 163 // This provider already exists as a configure node 164 continue 165 } 166 167 // If the provider has an alias in it, we just want the type 168 ptype := p 169 if idx := strings.IndexRune(p, '.'); idx != -1 { 170 ptype = p[:idx] 171 } 172 173 if _, ok := supported[ptype]; !ok { 174 // If we don't support the provider type, skip it. 175 // Validation later will catch this as an error. 176 continue 177 } 178 179 // Add the missing provider node to the graph 180 v := t.Factory(p, path).(dag.Vertex) 181 if len(path) > 0 { 182 if fn, ok := v.(GraphNodeFlattenable); ok { 183 var err error 184 v, err = fn.Flatten(path) 185 if err != nil { 186 return err 187 } 188 } 189 190 // We'll need the parent provider as well, so let's 191 // add a dummy node to check to make sure that we add 192 // that parent provider. 193 check = append(check, &graphNodeProviderConsumerDummy{ 194 ProviderValue: p, 195 PathValue: path[:len(path)-1], 196 }) 197 } 198 199 m[key] = g.Add(v) 200 } 201 } 202 203 return nil 204 } 205 206 // ParentProviderTransformer connects provider nodes to their parents. 207 // 208 // This works by finding nodes that are both GraphNodeProviders and 209 // GraphNodeSubPath. It then connects the providers to their parent 210 // path. 211 type ParentProviderTransformer struct{} 212 213 func (t *ParentProviderTransformer) Transform(g *Graph) error { 214 // Make a mapping of path to dag.Vertex, where path is: "path.name" 215 m := make(map[string]dag.Vertex) 216 217 // Also create a map that maps a provider to its parent 218 parentMap := make(map[dag.Vertex]string) 219 for _, raw := range g.Vertices() { 220 // If it is the flat version, then make it the non-flat version. 221 // We eventually want to get rid of the flat version entirely so 222 // this is a stop-gap while it still exists. 223 var v dag.Vertex = raw 224 if f, ok := v.(*graphNodeProviderFlat); ok { 225 v = f.graphNodeProvider 226 } 227 228 // Only care about providers 229 pn, ok := v.(GraphNodeProvider) 230 if !ok || pn.ProviderName() == "" { 231 continue 232 } 233 234 // Also require a subpath, if there is no subpath then we 235 // just totally ignore it. The expectation of this transform is 236 // that it is used with a graph builder that is already flattened. 237 var path []string 238 if pn, ok := raw.(GraphNodeSubPath); ok { 239 path = pn.Path() 240 } 241 path = normalizeModulePath(path) 242 243 // Build the key with path.name i.e. "child.subchild.aws" 244 key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName()) 245 m[key] = raw 246 247 // Determine the parent if we're non-root. This is length 1 since 248 // the 0 index should be "root" since we normalize above. 249 if len(path) > 1 { 250 path = path[:len(path)-1] 251 key := fmt.Sprintf("%s.%s", strings.Join(path, "."), pn.ProviderName()) 252 parentMap[raw] = key 253 } 254 } 255 256 // Connect! 257 for v, key := range parentMap { 258 if parent, ok := m[key]; ok { 259 g.Connect(dag.BasicEdge(v, parent)) 260 } 261 } 262 263 return nil 264 } 265 266 // PruneProviderTransformer is a GraphTransformer that prunes all the 267 // providers that aren't needed from the graph. A provider is unneeded if 268 // no resource or module is using that provider. 269 type PruneProviderTransformer struct{} 270 271 func (t *PruneProviderTransformer) Transform(g *Graph) error { 272 for _, v := range g.Vertices() { 273 // We only care about the providers 274 if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" { 275 continue 276 } 277 // Does anything depend on this? If not, then prune it. 278 if s := g.UpEdges(v); s.Len() == 0 { 279 if nv, ok := v.(dag.NamedVertex); ok { 280 log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name()) 281 } 282 g.Remove(v) 283 } 284 } 285 286 return nil 287 } 288 289 // providerMapKey is a helper that gives us the key to use for the 290 // maps returned by things such as providerVertexMap. 291 func providerMapKey(k string, v dag.Vertex) string { 292 pathPrefix := "" 293 if sp, ok := v.(GraphNodeSubPath); ok { 294 raw := normalizeModulePath(sp.Path()) 295 if len(raw) > len(rootModulePath) { 296 pathPrefix = modulePrefixStr(raw) + "." 297 } 298 } 299 300 return pathPrefix + k 301 } 302 303 func providerVertexMap(g *Graph) map[string]dag.Vertex { 304 m := make(map[string]dag.Vertex) 305 for _, v := range g.Vertices() { 306 if pv, ok := v.(GraphNodeProvider); ok { 307 key := pv.ProviderName() 308 309 // This special case is because the new world view of providers 310 // is that they should return only their pure name (not the full 311 // module path with ProviderName). Working towards this future. 312 if _, ok := v.(*NodeApplyableProvider); ok { 313 key = providerMapKey(pv.ProviderName(), v) 314 } 315 316 m[key] = 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 fmt.Sprintf("provider.%s (close)", n.ProviderNameValue) 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 type graphNodeProvider struct { 371 ProviderNameValue string 372 } 373 374 func (n *graphNodeProvider) Name() string { 375 return fmt.Sprintf("provider.%s", n.ProviderNameValue) 376 } 377 378 // GraphNodeEvalable impl. 379 func (n *graphNodeProvider) EvalTree() EvalNode { 380 return ProviderEvalTree(n.ProviderNameValue, nil) 381 } 382 383 // GraphNodeDependable impl. 384 func (n *graphNodeProvider) DependableName() []string { 385 return []string{n.Name()} 386 } 387 388 // GraphNodeProvider 389 func (n *graphNodeProvider) ProviderName() string { 390 return n.ProviderNameValue 391 } 392 393 func (n *graphNodeProvider) ProviderConfig() *config.RawConfig { 394 return nil 395 } 396 397 // GraphNodeDotter impl. 398 func (n *graphNodeProvider) DotNode(name string, opts *dag.DotOpts) *dag.DotNode { 399 return &dag.DotNode{ 400 Name: name, 401 Attrs: map[string]string{ 402 "label": n.Name(), 403 "shape": "diamond", 404 }, 405 } 406 } 407 408 // GraphNodeDotterOrigin impl. 409 func (n *graphNodeProvider) DotOrigin() bool { 410 return true 411 } 412 413 // GraphNodeFlattenable impl. 414 func (n *graphNodeProvider) Flatten(p []string) (dag.Vertex, error) { 415 return &graphNodeProviderFlat{ 416 graphNodeProvider: n, 417 PathValue: p, 418 }, nil 419 } 420 421 // Same as graphNodeMissingProvider, but for flattening 422 type graphNodeProviderFlat struct { 423 *graphNodeProvider 424 425 PathValue []string 426 } 427 428 func (n *graphNodeProviderFlat) Name() string { 429 return fmt.Sprintf( 430 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeProvider.Name()) 431 } 432 433 func (n *graphNodeProviderFlat) Path() []string { 434 return n.PathValue 435 } 436 437 func (n *graphNodeProviderFlat) ProviderName() string { 438 return fmt.Sprintf( 439 "%s.%s", modulePrefixStr(n.PathValue), 440 n.graphNodeProvider.ProviderName()) 441 } 442 443 // GraphNodeDependable impl. 444 func (n *graphNodeProviderFlat) DependableName() []string { 445 return []string{n.Name()} 446 } 447 448 func (n *graphNodeProviderFlat) DependentOn() []string { 449 var result []string 450 451 // If we're in a module, then depend on all parent providers. Some of 452 // these may not exist, hence we depend on all of them. 453 for i := len(n.PathValue); i > 1; i-- { 454 prefix := modulePrefixStr(n.PathValue[:i-1]) 455 result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix) 456 } 457 458 return result 459 } 460 461 // graphNodeProviderConsumerDummy is a struct that never enters the real 462 // graph (though it could to no ill effect). It implements 463 // GraphNodeProviderConsumer and GraphNodeSubpath as a way to force 464 // certain transformations. 465 type graphNodeProviderConsumerDummy struct { 466 ProviderValue string 467 PathValue []string 468 } 469 470 func (n *graphNodeProviderConsumerDummy) Path() []string { 471 return n.PathValue 472 } 473 474 func (n *graphNodeProviderConsumerDummy) ProvidedBy() []string { 475 return []string{n.ProviderValue} 476 }