github.com/anfernee/terraform@v0.6.16-0.20160430000239-06e5085a92f2/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 for _, v := range g.Vertices() { 42 // We only care about providers 43 pn, ok := v.(GraphNodeProvider) 44 if !ok || pn.ProviderName() == "" { 45 continue 46 } 47 48 // Go through all the up-edges (things that depend on this 49 // provider) and if any is not a module, then ignore this node. 50 nonModule := false 51 for _, sourceRaw := range g.UpEdges(v).List() { 52 source := sourceRaw.(dag.Vertex) 53 cn, ok := source.(graphNodeConfig) 54 if !ok { 55 nonModule = true 56 break 57 } 58 59 if cn.ConfigType() != GraphNodeConfigTypeModule { 60 nonModule = true 61 break 62 } 63 } 64 if nonModule { 65 // We found something that depends on this provider that 66 // isn't a module, so skip it. 67 continue 68 } 69 70 // Disable the provider by replacing it with a "disabled" provider 71 disabled := &graphNodeDisabledProvider{GraphNodeProvider: pn} 72 if !g.Replace(v, disabled) { 73 panic(fmt.Sprintf( 74 "vertex disappeared from under us: %s", 75 dag.VertexName(v))) 76 } 77 } 78 79 return nil 80 } 81 82 // ProviderTransformer is a GraphTransformer that maps resources to 83 // providers within the graph. This will error if there are any resources 84 // that don't map to proper resources. 85 type ProviderTransformer struct{} 86 87 func (t *ProviderTransformer) Transform(g *Graph) error { 88 // Go through the other nodes and match them to providers they need 89 var err error 90 m := providerVertexMap(g) 91 for _, v := range g.Vertices() { 92 if pv, ok := v.(GraphNodeProviderConsumer); ok { 93 for _, p := range pv.ProvidedBy() { 94 target := m[p] 95 if target == nil { 96 err = multierror.Append(err, fmt.Errorf( 97 "%s: provider %s couldn't be found", 98 dag.VertexName(v), p)) 99 continue 100 } 101 102 g.Connect(dag.BasicEdge(v, target)) 103 } 104 } 105 } 106 107 return err 108 } 109 110 // CloseProviderTransformer is a GraphTransformer that adds nodes to the 111 // graph that will close open provider connections that aren't needed anymore. 112 // A provider connection is not needed anymore once all depended resources 113 // in the graph are evaluated. 114 type CloseProviderTransformer struct{} 115 116 func (t *CloseProviderTransformer) Transform(g *Graph) error { 117 pm := providerVertexMap(g) 118 cpm := closeProviderVertexMap(g) 119 var err error 120 for _, v := range g.Vertices() { 121 if pv, ok := v.(GraphNodeProviderConsumer); ok { 122 for _, p := range pv.ProvidedBy() { 123 source := cpm[p] 124 125 if source == nil { 126 // Create a new graphNodeCloseProvider and add it to the graph 127 source = &graphNodeCloseProvider{ProviderNameValue: p} 128 g.Add(source) 129 130 // Close node needs to depend on provider 131 provider, ok := pm[p] 132 if !ok { 133 err = multierror.Append(err, fmt.Errorf( 134 "%s: provider %s couldn't be found for closing", 135 dag.VertexName(v), p)) 136 continue 137 } 138 g.Connect(dag.BasicEdge(source, provider)) 139 140 // Make sure we also add the new graphNodeCloseProvider to the map 141 // so we don't create and add any duplicate graphNodeCloseProviders. 142 cpm[p] = source 143 } 144 145 // Close node depends on all nodes provided by the provider 146 g.Connect(dag.BasicEdge(source, v)) 147 } 148 } 149 } 150 151 return err 152 } 153 154 // MissingProviderTransformer is a GraphTransformer that adds nodes 155 // for missing providers into the graph. Specifically, it creates provider 156 // configuration nodes for all the providers that we support. These are 157 // pruned later during an optimization pass. 158 type MissingProviderTransformer struct { 159 // Providers is the list of providers we support. 160 Providers []string 161 } 162 163 func (t *MissingProviderTransformer) Transform(g *Graph) error { 164 // Create a set of our supported providers 165 supported := make(map[string]struct{}, len(t.Providers)) 166 for _, v := range t.Providers { 167 supported[v] = struct{}{} 168 } 169 170 // Get the map of providers we already have in our graph 171 m := providerVertexMap(g) 172 173 // Go through all the provider consumers and make sure we add 174 // that provider if it is missing. 175 for _, v := range g.Vertices() { 176 pv, ok := v.(GraphNodeProviderConsumer) 177 if !ok { 178 continue 179 } 180 181 for _, p := range pv.ProvidedBy() { 182 if _, ok := m[p]; ok { 183 // This provider already exists as a configure node 184 continue 185 } 186 187 // If the provider has an alias in it, we just want the type 188 ptype := p 189 if idx := strings.IndexRune(p, '.'); idx != -1 { 190 ptype = p[:idx] 191 } 192 193 if _, ok := supported[ptype]; !ok { 194 // If we don't support the provider type, skip it. 195 // Validation later will catch this as an error. 196 continue 197 } 198 199 // Add the missing provider node to the graph 200 m[p] = g.Add(&graphNodeProvider{ProviderNameValue: p}) 201 } 202 } 203 204 return nil 205 } 206 207 // PruneProviderTransformer is a GraphTransformer that prunes all the 208 // providers that aren't needed from the graph. A provider is unneeded if 209 // no resource or module is using that provider. 210 type PruneProviderTransformer struct{} 211 212 func (t *PruneProviderTransformer) Transform(g *Graph) error { 213 for _, v := range g.Vertices() { 214 // We only care about the providers 215 if pn, ok := v.(GraphNodeProvider); !ok || pn.ProviderName() == "" { 216 continue 217 } 218 // Does anything depend on this? If not, then prune it. 219 if s := g.UpEdges(v); s.Len() == 0 { 220 if nv, ok := v.(dag.NamedVertex); ok { 221 log.Printf("[DEBUG] Pruning provider with no dependencies: %s", nv.Name()) 222 } 223 g.Remove(v) 224 } 225 } 226 227 return nil 228 } 229 230 func providerVertexMap(g *Graph) map[string]dag.Vertex { 231 m := make(map[string]dag.Vertex) 232 for _, v := range g.Vertices() { 233 if pv, ok := v.(GraphNodeProvider); ok { 234 m[pv.ProviderName()] = v 235 } 236 } 237 238 return m 239 } 240 241 func closeProviderVertexMap(g *Graph) map[string]dag.Vertex { 242 m := make(map[string]dag.Vertex) 243 for _, v := range g.Vertices() { 244 if pv, ok := v.(GraphNodeCloseProvider); ok { 245 m[pv.CloseProviderName()] = v 246 } 247 } 248 249 return m 250 } 251 252 type graphNodeDisabledProvider struct { 253 GraphNodeProvider 254 } 255 256 // GraphNodeEvalable impl. 257 func (n *graphNodeDisabledProvider) EvalTree() EvalNode { 258 var resourceConfig *ResourceConfig 259 260 return &EvalOpFilter{ 261 Ops: []walkOperation{walkInput, walkValidate, walkRefresh, walkPlan, walkApply, walkDestroy}, 262 Node: &EvalSequence{ 263 Nodes: []EvalNode{ 264 &EvalInterpolate{ 265 Config: n.ProviderConfig(), 266 Output: &resourceConfig, 267 }, 268 &EvalBuildProviderConfig{ 269 Provider: n.ProviderName(), 270 Config: &resourceConfig, 271 Output: &resourceConfig, 272 }, 273 &EvalSetProviderConfig{ 274 Provider: n.ProviderName(), 275 Config: &resourceConfig, 276 }, 277 }, 278 }, 279 } 280 } 281 282 // GraphNodeFlattenable impl. 283 func (n *graphNodeDisabledProvider) Flatten(p []string) (dag.Vertex, error) { 284 return &graphNodeDisabledProviderFlat{ 285 graphNodeDisabledProvider: n, 286 PathValue: p, 287 }, nil 288 } 289 290 func (n *graphNodeDisabledProvider) Name() string { 291 return fmt.Sprintf("%s (disabled)", dag.VertexName(n.GraphNodeProvider)) 292 } 293 294 // GraphNodeDotter impl. 295 func (n *graphNodeDisabledProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 296 return dot.NewNode(name, map[string]string{ 297 "label": n.Name(), 298 "shape": "diamond", 299 }) 300 } 301 302 // GraphNodeDotterOrigin impl. 303 func (n *graphNodeDisabledProvider) DotOrigin() bool { 304 return true 305 } 306 307 // GraphNodeDependable impl. 308 func (n *graphNodeDisabledProvider) DependableName() []string { 309 return []string{"provider." + n.ProviderName()} 310 } 311 312 // GraphNodeProvider impl. 313 func (n *graphNodeDisabledProvider) ProviderName() string { 314 return n.GraphNodeProvider.ProviderName() 315 } 316 317 // GraphNodeProvider impl. 318 func (n *graphNodeDisabledProvider) ProviderConfig() *config.RawConfig { 319 return n.GraphNodeProvider.ProviderConfig() 320 } 321 322 // Same as graphNodeDisabledProvider, but for flattening 323 type graphNodeDisabledProviderFlat struct { 324 *graphNodeDisabledProvider 325 326 PathValue []string 327 } 328 329 func (n *graphNodeDisabledProviderFlat) Name() string { 330 return fmt.Sprintf( 331 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeDisabledProvider.Name()) 332 } 333 334 func (n *graphNodeDisabledProviderFlat) Path() []string { 335 return n.PathValue 336 } 337 338 func (n *graphNodeDisabledProviderFlat) ProviderName() string { 339 return fmt.Sprintf( 340 "%s.%s", modulePrefixStr(n.PathValue), 341 n.graphNodeDisabledProvider.ProviderName()) 342 } 343 344 // GraphNodeDependable impl. 345 func (n *graphNodeDisabledProviderFlat) DependableName() []string { 346 return modulePrefixList( 347 n.graphNodeDisabledProvider.DependableName(), 348 modulePrefixStr(n.PathValue)) 349 } 350 351 func (n *graphNodeDisabledProviderFlat) DependentOn() []string { 352 var result []string 353 354 // If we're in a module, then depend on our parent's provider 355 if len(n.PathValue) > 1 { 356 prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) 357 result = modulePrefixList( 358 n.graphNodeDisabledProvider.DependableName(), prefix) 359 } 360 361 return result 362 } 363 364 type graphNodeCloseProvider struct { 365 ProviderNameValue string 366 } 367 368 func (n *graphNodeCloseProvider) Name() string { 369 return fmt.Sprintf("provider.%s (close)", n.ProviderNameValue) 370 } 371 372 // GraphNodeEvalable impl. 373 func (n *graphNodeCloseProvider) EvalTree() EvalNode { 374 return CloseProviderEvalTree(n.ProviderNameValue) 375 } 376 377 // GraphNodeDependable impl. 378 func (n *graphNodeCloseProvider) DependableName() []string { 379 return []string{n.Name()} 380 } 381 382 func (n *graphNodeCloseProvider) CloseProviderName() string { 383 return n.ProviderNameValue 384 } 385 386 // GraphNodeDotter impl. 387 func (n *graphNodeCloseProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 388 if !opts.Verbose { 389 return nil 390 } 391 return dot.NewNode(name, map[string]string{ 392 "label": n.Name(), 393 "shape": "diamond", 394 }) 395 } 396 397 type graphNodeProvider struct { 398 ProviderNameValue string 399 } 400 401 func (n *graphNodeProvider) Name() string { 402 return fmt.Sprintf("provider.%s", n.ProviderNameValue) 403 } 404 405 // GraphNodeEvalable impl. 406 func (n *graphNodeProvider) EvalTree() EvalNode { 407 return ProviderEvalTree(n.ProviderNameValue, nil) 408 } 409 410 // GraphNodeDependable impl. 411 func (n *graphNodeProvider) DependableName() []string { 412 return []string{n.Name()} 413 } 414 415 func (n *graphNodeProvider) ProviderName() string { 416 return n.ProviderNameValue 417 } 418 419 func (n *graphNodeProvider) ProviderConfig() *config.RawConfig { 420 return nil 421 } 422 423 // GraphNodeDotter impl. 424 func (n *graphNodeProvider) DotNode(name string, opts *GraphDotOpts) *dot.Node { 425 return dot.NewNode(name, map[string]string{ 426 "label": n.Name(), 427 "shape": "diamond", 428 }) 429 } 430 431 // GraphNodeDotterOrigin impl. 432 func (n *graphNodeProvider) DotOrigin() bool { 433 return true 434 } 435 436 // GraphNodeFlattenable impl. 437 func (n *graphNodeProvider) Flatten(p []string) (dag.Vertex, error) { 438 return &graphNodeProviderFlat{ 439 graphNodeProvider: n, 440 PathValue: p, 441 }, nil 442 } 443 444 // Same as graphNodeMissingProvider, but for flattening 445 type graphNodeProviderFlat struct { 446 *graphNodeProvider 447 448 PathValue []string 449 } 450 451 func (n *graphNodeProviderFlat) Name() string { 452 return fmt.Sprintf( 453 "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeProvider.Name()) 454 } 455 456 func (n *graphNodeProviderFlat) Path() []string { 457 return n.PathValue 458 } 459 460 func (n *graphNodeProviderFlat) ProviderName() string { 461 return fmt.Sprintf( 462 "%s.%s", modulePrefixStr(n.PathValue), 463 n.graphNodeProvider.ProviderName()) 464 } 465 466 // GraphNodeDependable impl. 467 func (n *graphNodeProviderFlat) DependableName() []string { 468 return []string{n.Name()} 469 } 470 471 func (n *graphNodeProviderFlat) DependentOn() []string { 472 var result []string 473 474 // If we're in a module, then depend on our parent's provider 475 if len(n.PathValue) > 1 { 476 prefix := modulePrefixStr(n.PathValue[:len(n.PathValue)-1]) 477 result = modulePrefixList(n.graphNodeProvider.DependableName(), prefix) 478 } 479 480 return result 481 }