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