github.com/ezbercih/terraform@v0.1.1-0.20140729011846-3c33865e0839/terraform/graph.go (about) 1 package terraform 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "sort" 8 "strings" 9 10 "github.com/hashicorp/terraform/config" 11 "github.com/hashicorp/terraform/depgraph" 12 "github.com/hashicorp/terraform/helper/multierror" 13 ) 14 15 // GraphOpts are options used to create the resource graph that Terraform 16 // walks to make changes to infrastructure. 17 // 18 // Depending on what options are set, the resulting graph will come in 19 // varying degrees of completeness. 20 type GraphOpts struct { 21 // Config is the configuration from which to build the basic graph. 22 // This is the only required item. 23 Config *config.Config 24 25 // Diff of changes that will be applied to the given state. This will 26 // associate a ResourceDiff with applicable resources. Additionally, 27 // new resource nodes representing resource destruction may be inserted 28 // into the graph. 29 Diff *Diff 30 31 // State, if present, will make the ResourceState available on each 32 // resource node. Additionally, any orphans will be added automatically 33 // to the graph. 34 State *State 35 36 // Providers is a mapping of prefixes to a resource provider. If given, 37 // resource providers will be found, initialized, and associated to the 38 // resources in the graph. 39 // 40 // This will also potentially insert new nodes into the graph for 41 // the configuration of resource providers. 42 Providers map[string]ResourceProviderFactory 43 44 // Provisioners is a mapping of names to a resource provisioner. 45 // These must be provided to support resource provisioners. 46 Provisioners map[string]ResourceProvisionerFactory 47 } 48 49 // GraphRootNode is the name of the root node in the Terraform resource 50 // graph. This node is just a placemarker and has no associated functionality. 51 const GraphRootNode = "root" 52 53 // GraphNodeResource is a node type in the graph that represents a resource 54 // that will be created or managed. Unlike the GraphNodeResourceMeta node, 55 // this represents a _single_, _resource_ to be managed, not a set of resources 56 // or a component of a resource. 57 type GraphNodeResource struct { 58 Index int 59 Type string 60 Config *config.Resource 61 Orphan bool 62 Resource *Resource 63 ResourceProviderID string 64 } 65 66 // GraphNodeResourceMeta is a node type in the graph that represents the 67 // metadata for a resource. There will be one meta node for every resource 68 // in the configuration. 69 type GraphNodeResourceMeta struct { 70 ID string 71 Name string 72 Type string 73 Count int 74 } 75 76 // GraphNodeResourceProvider is a node type in the graph that represents 77 // the configuration for a resource provider. 78 type GraphNodeResourceProvider struct { 79 ID string 80 Providers map[string]ResourceProvider 81 ProviderKeys []string 82 Config *config.ProviderConfig 83 } 84 85 // Graph builds a dependency graph of all the resources for infrastructure 86 // change. 87 // 88 // This dependency graph shows the correct order that any resources need 89 // to be operated on. 90 // 91 // The Meta field of a graph Noun can contain one of the follow types. A 92 // description is next to each type to explain what it is. 93 // 94 // *GraphNodeResource - A resource. See the documentation of this 95 // struct for more details. 96 // *GraphNodeResourceProvider - A resource provider that needs to be 97 // configured at this point. 98 // 99 func Graph(opts *GraphOpts) (*depgraph.Graph, error) { 100 if opts.Config == nil { 101 return nil, errors.New("Config is required for Graph") 102 } 103 104 log.Printf("[DEBUG] Creating graph...") 105 106 g := new(depgraph.Graph) 107 108 // First, build the initial resource graph. This only has the resources 109 // and no dependencies. 110 graphAddConfigResources(g, opts.Config, opts.State) 111 112 // Add explicit dependsOn dependencies to the graph 113 graphAddExplicitDeps(g) 114 115 // Next, add the state orphans if we have any 116 if opts.State != nil { 117 graphAddOrphans(g, opts.Config, opts.State) 118 } 119 120 // Map the provider configurations to all of the resources 121 graphAddProviderConfigs(g, opts.Config) 122 123 // Setup the provisioners. These may have variable dependencies, 124 // and must be done before dependency setup 125 if err := graphMapResourceProvisioners(g, opts.Provisioners); err != nil { 126 return nil, err 127 } 128 129 // Add all the variable dependencies 130 graphAddVariableDeps(g) 131 132 // Build the root so that we have a single valid root 133 graphAddRoot(g) 134 135 // If providers were given, lets associate the proper providers and 136 // instantiate them. 137 if len(opts.Providers) > 0 { 138 // Add missing providers from the mapping 139 if err := graphAddMissingResourceProviders(g, opts.Providers); err != nil { 140 return nil, err 141 } 142 143 // Initialize all the providers 144 if err := graphInitResourceProviders(g, opts.Providers); err != nil { 145 return nil, err 146 } 147 148 // Map the providers to resources 149 if err := graphMapResourceProviders(g); err != nil { 150 return nil, err 151 } 152 } 153 154 // If we have a diff, then make sure to add that in 155 if opts.Diff != nil { 156 if err := graphAddDiff(g, opts.Diff); err != nil { 157 return nil, err 158 } 159 } 160 161 // Validate 162 if err := g.Validate(); err != nil { 163 return nil, err 164 } 165 166 log.Printf( 167 "[DEBUG] Graph created and valid. %d nouns.", 168 len(g.Nouns)) 169 170 return g, nil 171 } 172 173 // configGraph turns a configuration structure into a dependency graph. 174 func graphAddConfigResources( 175 g *depgraph.Graph, c *config.Config, s *State) { 176 // This tracks all the resource nouns 177 nouns := make(map[string]*depgraph.Noun) 178 for _, r := range c.Resources { 179 resourceNouns := make([]*depgraph.Noun, r.Count) 180 for i := 0; i < r.Count; i++ { 181 name := r.Id() 182 index := -1 183 184 // If we have a count that is more than one, then make sure 185 // we suffix with the number of the resource that this is. 186 if r.Count > 1 { 187 name = fmt.Sprintf("%s.%d", name, i) 188 index = i 189 } 190 191 // Determine if this resource is tainted 192 tainted := false 193 if s != nil && s.Tainted != nil { 194 _, tainted = s.Tainted[r.Id()] 195 } 196 197 var state *ResourceState 198 if s != nil { 199 state = s.Resources[name] 200 201 if state == nil { 202 if r.Count == 1 { 203 // If the count is one, check the state for ".0" 204 // appended, which might exist if we go from 205 // count > 1 to count == 1. 206 state = s.Resources[r.Id()+".0"] 207 } else if i == 0 { 208 // If count is greater than one, check for state 209 // with just the ID, which might exist if we go 210 // from count == 1 to count > 1 211 state = s.Resources[r.Id()] 212 } 213 } 214 } 215 if state == nil { 216 state = &ResourceState{ 217 Type: r.Type, 218 } 219 } 220 221 resourceNouns[i] = &depgraph.Noun{ 222 Name: name, 223 Meta: &GraphNodeResource{ 224 Index: index, 225 Type: r.Type, 226 Config: r, 227 Resource: &Resource{ 228 Id: name, 229 State: state, 230 Config: NewResourceConfig(r.RawConfig), 231 Tainted: tainted, 232 }, 233 }, 234 } 235 } 236 237 // If we have more than one, then create a meta node to track 238 // the resources. 239 if r.Count > 1 { 240 metaNoun := &depgraph.Noun{ 241 Name: r.Id(), 242 Meta: &GraphNodeResourceMeta{ 243 ID: r.Id(), 244 Name: r.Name, 245 Type: r.Type, 246 Count: r.Count, 247 }, 248 } 249 250 // Create the dependencies on this noun 251 for _, n := range resourceNouns { 252 metaNoun.Deps = append(metaNoun.Deps, &depgraph.Dependency{ 253 Name: n.Name, 254 Source: metaNoun, 255 Target: n, 256 }) 257 } 258 259 // Assign it to the map so that we have it 260 nouns[metaNoun.Name] = metaNoun 261 } 262 263 for _, n := range resourceNouns { 264 nouns[n.Name] = n 265 } 266 } 267 268 // Build the list of nouns that we iterate over 269 nounsList := make([]*depgraph.Noun, 0, len(nouns)) 270 for _, n := range nouns { 271 nounsList = append(nounsList, n) 272 } 273 274 g.Name = "terraform" 275 g.Nouns = append(g.Nouns, nounsList...) 276 } 277 278 // graphAddDiff takes an already-built graph of resources and adds the 279 // diffs to the resource nodes themselves. 280 // 281 // This may also introduces new graph elements. If there are diffs that 282 // require a destroy, new elements may be introduced since destroy order 283 // is different than create order. For example, destroying a VPC requires 284 // destroying the VPC's subnets first, whereas creating a VPC requires 285 // doing it before the subnets are created. This function handles inserting 286 // these nodes for you. 287 func graphAddDiff(g *depgraph.Graph, d *Diff) error { 288 var nlist []*depgraph.Noun 289 for _, n := range g.Nouns { 290 rn, ok := n.Meta.(*GraphNodeResource) 291 if !ok { 292 continue 293 } 294 295 rd, ok := d.Resources[rn.Resource.Id] 296 if !ok { 297 continue 298 } 299 if rd.Empty() { 300 continue 301 } 302 303 if rd.Destroy { 304 // If we're destroying, we create a new destroy node with 305 // the proper dependencies. Perform a dirty copy operation. 306 newNode := new(GraphNodeResource) 307 *newNode = *rn 308 newNode.Resource = new(Resource) 309 *newNode.Resource = *rn.Resource 310 311 // Make the diff _just_ the destroy. 312 newNode.Resource.Diff = &ResourceDiff{Destroy: true} 313 314 // Create the new node 315 newN := &depgraph.Noun{ 316 Name: fmt.Sprintf("%s (destroy)", newNode.Resource.Id), 317 Meta: newNode, 318 } 319 newN.Deps = make([]*depgraph.Dependency, 0, len(n.Deps)) 320 for _, d := range n.Deps { 321 // We don't want to copy any resource dependencies 322 if _, ok := d.Target.Meta.(*GraphNodeResource); ok { 323 continue 324 } 325 326 newN.Deps = append(newN.Deps, &depgraph.Dependency{ 327 Name: d.Name, 328 Source: newN, 329 Target: d.Target, 330 }) 331 } 332 333 // Append it to the list so we handle it later 334 nlist = append(nlist, newN) 335 336 // Mark the old diff to not destroy since we handle that in 337 // the dedicated node. 338 newDiff := new(ResourceDiff) 339 *newDiff = *rd 340 newDiff.Destroy = false 341 rd = newDiff 342 343 // Add to the new noun to our dependencies so that the destroy 344 // happens before the apply. 345 n.Deps = append(n.Deps, &depgraph.Dependency{ 346 Name: newN.Name, 347 Source: n, 348 Target: newN, 349 }) 350 351 // If the resource is tainted, mark the state as nil so 352 // that a fresh create is done. 353 if rn.Resource.Tainted { 354 rn.Resource.State = &ResourceState{ 355 Type: rn.Resource.State.Type, 356 } 357 rn.Resource.Tainted = false 358 } 359 } 360 361 rn.Resource.Diff = rd 362 } 363 364 // Go through each noun and make sure we calculate all the dependencies 365 // properly. 366 for _, n := range nlist { 367 rn := n.Meta.(*GraphNodeResource) 368 369 // If we have no dependencies, then just continue 370 deps := rn.Resource.State.Dependencies 371 if len(deps) == 0 { 372 continue 373 } 374 375 // We have dependencies. We must be destroyed BEFORE those 376 // dependencies. Look to see if they're managed. 377 for _, dep := range deps { 378 for _, n2 := range nlist { 379 rn2 := n2.Meta.(*GraphNodeResource) 380 if rn2.Resource.State.ID == dep.ID { 381 n2.Deps = append(n2.Deps, &depgraph.Dependency{ 382 Name: n.Name, 383 Source: n2, 384 Target: n, 385 }) 386 387 break 388 } 389 } 390 } 391 } 392 393 // Add the nouns to the graph 394 g.Nouns = append(g.Nouns, nlist...) 395 396 return nil 397 } 398 399 // graphAddExplicitDeps adds the dependencies to the graph for the explicit 400 // dependsOn configurations. 401 func graphAddExplicitDeps(g *depgraph.Graph) { 402 depends := false 403 404 rs := make(map[string]*depgraph.Noun) 405 for _, n := range g.Nouns { 406 rn, ok := n.Meta.(*GraphNodeResource) 407 if !ok { 408 continue 409 } 410 411 rs[rn.Config.Id()] = n 412 if len(rn.Config.DependsOn) > 0 { 413 depends = true 414 } 415 } 416 417 // If we didn't have any dependsOn, just return 418 if !depends { 419 return 420 } 421 422 for _, n1 := range rs { 423 rn1 := n1.Meta.(*GraphNodeResource) 424 for _, d := range rn1.Config.DependsOn { 425 for _, n2 := range rs { 426 rn2 := n2.Meta.(*GraphNodeResource) 427 if rn2.Config.Id() != d { 428 continue 429 } 430 431 n1.Deps = append(n1.Deps, &depgraph.Dependency{ 432 Name: d, 433 Source: n1, 434 Target: n2, 435 }) 436 } 437 } 438 } 439 } 440 441 // graphAddMissingResourceProviders adds GraphNodeResourceProvider nodes for 442 // the resources that do not have an explicit resource provider specified 443 // because no provider configuration was given. 444 func graphAddMissingResourceProviders( 445 g *depgraph.Graph, 446 ps map[string]ResourceProviderFactory) error { 447 var errs []error 448 449 for _, n := range g.Nouns { 450 rn, ok := n.Meta.(*GraphNodeResource) 451 if !ok { 452 continue 453 } 454 if rn.ResourceProviderID != "" { 455 continue 456 } 457 458 prefixes := matchingPrefixes(rn.Type, ps) 459 if len(prefixes) == 0 { 460 errs = append(errs, fmt.Errorf( 461 "No matching provider for type: %s", 462 rn.Type)) 463 continue 464 } 465 466 // The resource provider ID is simply the shortest matching 467 // prefix, since that'll give us the most resource providers 468 // to choose from. 469 rn.ResourceProviderID = prefixes[len(prefixes)-1] 470 471 // If we don't have a matching noun for this yet, insert it. 472 pn := g.Noun(fmt.Sprintf("provider.%s", rn.ResourceProviderID)) 473 if pn == nil { 474 pn = &depgraph.Noun{ 475 Name: fmt.Sprintf("provider.%s", rn.ResourceProviderID), 476 Meta: &GraphNodeResourceProvider{ 477 ID: rn.ResourceProviderID, 478 Config: nil, 479 }, 480 } 481 g.Nouns = append(g.Nouns, pn) 482 } 483 484 // Add the provider configuration noun as a dependency 485 dep := &depgraph.Dependency{ 486 Name: pn.Name, 487 Source: n, 488 Target: pn, 489 } 490 n.Deps = append(n.Deps, dep) 491 } 492 493 if len(errs) > 0 { 494 return &multierror.Error{Errors: errs} 495 } 496 497 return nil 498 } 499 500 // graphAddOrphans adds the orphans to the graph. 501 func graphAddOrphans(g *depgraph.Graph, c *config.Config, s *State) { 502 for _, k := range s.Orphans(c) { 503 rs := s.Resources[k] 504 noun := &depgraph.Noun{ 505 Name: k, 506 Meta: &GraphNodeResource{ 507 Index: -1, 508 Type: rs.Type, 509 Orphan: true, 510 Resource: &Resource{ 511 Id: k, 512 State: rs, 513 Config: NewResourceConfig(nil), 514 }, 515 }, 516 } 517 g.Nouns = append(g.Nouns, noun) 518 } 519 } 520 521 // graphAddProviderConfigs cycles through all the resource-like nodes 522 // and adds the provider configuration nouns into the tree. 523 func graphAddProviderConfigs(g *depgraph.Graph, c *config.Config) { 524 nounsList := make([]*depgraph.Noun, 0, 2) 525 pcNouns := make(map[string]*depgraph.Noun) 526 for _, noun := range g.Nouns { 527 resourceNode, ok := noun.Meta.(*GraphNodeResource) 528 if !ok { 529 continue 530 } 531 532 // Look up the provider config for this resource 533 pcName := config.ProviderConfigName( 534 resourceNode.Type, c.ProviderConfigs) 535 if pcName == "" { 536 continue 537 } 538 539 // We have one, so build the noun if it hasn't already been made 540 pcNoun, ok := pcNouns[pcName] 541 if !ok { 542 var pc *config.ProviderConfig 543 for _, v := range c.ProviderConfigs { 544 if v.Name == pcName { 545 pc = v 546 break 547 } 548 } 549 if pc == nil { 550 panic("pc not found") 551 } 552 553 pcNoun = &depgraph.Noun{ 554 Name: fmt.Sprintf("provider.%s", pcName), 555 Meta: &GraphNodeResourceProvider{ 556 ID: pcName, 557 Config: pc, 558 }, 559 } 560 pcNouns[pcName] = pcNoun 561 nounsList = append(nounsList, pcNoun) 562 } 563 564 // Set the resource provider ID for this noun so we can look it 565 // up later easily. 566 resourceNode.ResourceProviderID = pcName 567 568 // Add the provider configuration noun as a dependency 569 dep := &depgraph.Dependency{ 570 Name: pcName, 571 Source: noun, 572 Target: pcNoun, 573 } 574 noun.Deps = append(noun.Deps, dep) 575 } 576 577 // Add all the provider config nouns to the graph 578 g.Nouns = append(g.Nouns, nounsList...) 579 } 580 581 // graphAddRoot adds a root element to the graph so that there is a single 582 // root to point to all the dependencies. 583 func graphAddRoot(g *depgraph.Graph) { 584 root := &depgraph.Noun{Name: GraphRootNode} 585 for _, n := range g.Nouns { 586 switch m := n.Meta.(type) { 587 case *GraphNodeResource: 588 // If the resource is part of a group, we don't need to make a dep 589 if m.Index != -1 { 590 continue 591 } 592 case *GraphNodeResourceMeta: 593 // Always in the graph 594 case *GraphNodeResourceProvider: 595 // ResourceProviders don't need to be in the root deps because 596 // they're always pointed to by some resource. 597 continue 598 } 599 600 root.Deps = append(root.Deps, &depgraph.Dependency{ 601 Name: n.Name, 602 Source: root, 603 Target: n, 604 }) 605 } 606 g.Nouns = append(g.Nouns, root) 607 } 608 609 // graphAddVariableDeps inspects all the nouns and adds any dependencies 610 // based on variable values. 611 func graphAddVariableDeps(g *depgraph.Graph) { 612 for _, n := range g.Nouns { 613 var vars map[string]config.InterpolatedVariable 614 switch m := n.Meta.(type) { 615 case *GraphNodeResource: 616 // Ignore orphan nodes 617 if m.Orphan { 618 continue 619 } 620 621 // Handle the resource variables 622 vars = m.Config.RawConfig.Variables 623 nounAddVariableDeps(g, n, vars, false) 624 625 // Handle the variables of the resource provisioners 626 for _, p := range m.Resource.Provisioners { 627 vars = p.RawConfig.Variables 628 nounAddVariableDeps(g, n, vars, true) 629 630 vars = p.ConnInfo.Variables 631 nounAddVariableDeps(g, n, vars, true) 632 } 633 634 case *GraphNodeResourceProvider: 635 vars = m.Config.RawConfig.Variables 636 nounAddVariableDeps(g, n, vars, false) 637 638 default: 639 continue 640 } 641 } 642 } 643 644 // nounAddVariableDeps updates the dependencies of a noun given 645 // a set of associated variable values 646 func nounAddVariableDeps( 647 g *depgraph.Graph, 648 n *depgraph.Noun, 649 vars map[string]config.InterpolatedVariable, 650 removeSelf bool) { 651 for _, v := range vars { 652 // Only resource variables impose dependencies 653 rv, ok := v.(*config.ResourceVariable) 654 if !ok { 655 continue 656 } 657 658 // Find the target 659 target := g.Noun(rv.ResourceId()) 660 if target == nil { 661 continue 662 } 663 664 // If we're ignoring self-references, then don't add that 665 // dependency. 666 if removeSelf && n == target { 667 continue 668 } 669 670 // Build the dependency 671 dep := &depgraph.Dependency{ 672 Name: rv.ResourceId(), 673 Source: n, 674 Target: target, 675 } 676 677 n.Deps = append(n.Deps, dep) 678 } 679 } 680 681 // graphInitResourceProviders maps the resource providers onto the graph 682 // given a mapping of prefixes to resource providers. 683 // 684 // Unlike the graphAdd* functions, this one can return an error if resource 685 // providers can't be found or can't be instantiated. 686 func graphInitResourceProviders( 687 g *depgraph.Graph, 688 ps map[string]ResourceProviderFactory) error { 689 var errs []error 690 691 // Keep track of providers we know we couldn't instantiate so 692 // that we don't get a ton of errors about the same provider. 693 failures := make(map[string]struct{}) 694 695 for _, n := range g.Nouns { 696 // We only care about the resource providers first. There is guaranteed 697 // to be only one node per tuple (providerId, providerConfig), which 698 // means we don't need to verify we have instantiated it before. 699 rn, ok := n.Meta.(*GraphNodeResourceProvider) 700 if !ok { 701 continue 702 } 703 704 prefixes := matchingPrefixes(rn.ID, ps) 705 if len(prefixes) > 0 { 706 if _, ok := failures[prefixes[0]]; ok { 707 // We already failed this provider, meaning this 708 // resource will never succeed, so just continue. 709 continue 710 } 711 } 712 713 // Go through each prefix and instantiate if necessary, then 714 // verify if this provider is of use to us or not. 715 rn.Providers = make(map[string]ResourceProvider) 716 rn.ProviderKeys = prefixes 717 for _, prefix := range prefixes { 718 p, err := ps[prefix]() 719 if err != nil { 720 errs = append(errs, fmt.Errorf( 721 "Error instantiating resource provider for "+ 722 "prefix %s: %s", prefix, err)) 723 724 // Record the error so that we don't check it again 725 failures[prefix] = struct{}{} 726 727 // Jump to the next prefix 728 continue 729 } 730 731 rn.Providers[prefix] = p 732 } 733 734 // If we never found a provider, then error and continue 735 if len(rn.Providers) == 0 { 736 errs = append(errs, fmt.Errorf( 737 "Provider for configuration '%s' not found.", 738 rn.ID)) 739 continue 740 } 741 } 742 743 if len(errs) > 0 { 744 return &multierror.Error{Errors: errs} 745 } 746 747 return nil 748 } 749 750 // graphMapResourceProviders takes a graph that already has initialized 751 // the resource providers (using graphInitResourceProviders) and maps the 752 // resource providers to the resources themselves. 753 func graphMapResourceProviders(g *depgraph.Graph) error { 754 var errs []error 755 756 // First build a mapping of resource provider ID to the node that 757 // contains those resources. 758 mapping := make(map[string]*GraphNodeResourceProvider) 759 for _, n := range g.Nouns { 760 rn, ok := n.Meta.(*GraphNodeResourceProvider) 761 if !ok { 762 continue 763 } 764 mapping[rn.ID] = rn 765 } 766 767 // Now go through each of the resources and find a matching provider. 768 for _, n := range g.Nouns { 769 rn, ok := n.Meta.(*GraphNodeResource) 770 if !ok { 771 continue 772 } 773 774 rpn, ok := mapping[rn.ResourceProviderID] 775 if !ok { 776 // This should never happen since when building the graph 777 // we ensure that everything matches up. 778 panic(fmt.Sprintf( 779 "Resource provider ID not found: %s (type: %s)", 780 rn.ResourceProviderID, 781 rn.Type)) 782 } 783 784 var provider ResourceProvider 785 for _, k := range rpn.ProviderKeys { 786 // Only try this provider if it has the right prefix 787 if !strings.HasPrefix(rn.Type, k) { 788 continue 789 } 790 791 rp := rpn.Providers[k] 792 if ProviderSatisfies(rp, rn.Type) { 793 provider = rp 794 break 795 } 796 } 797 798 if provider == nil { 799 errs = append(errs, fmt.Errorf( 800 "Resource provider not found for resource type '%s'", 801 rn.Type)) 802 continue 803 } 804 805 rn.Resource.Provider = provider 806 } 807 808 if len(errs) > 0 { 809 return &multierror.Error{Errors: errs} 810 } 811 812 return nil 813 } 814 815 // graphMapResourceProvisioners takes a graph that already has 816 // the resources and maps the resource provisioners to the resources themselves. 817 func graphMapResourceProvisioners(g *depgraph.Graph, 818 provisioners map[string]ResourceProvisionerFactory) error { 819 var errs []error 820 821 // Create a cache of resource provisioners, avoids duplicate 822 // initialization of the instances 823 cache := make(map[string]ResourceProvisioner) 824 825 // Go through each of the resources and find a matching provisioners 826 for _, n := range g.Nouns { 827 rn, ok := n.Meta.(*GraphNodeResource) 828 if !ok { 829 continue 830 } 831 832 // Ignore orphan nodes with no provisioners 833 if rn.Config == nil { 834 continue 835 } 836 837 // Check each provisioner 838 for _, p := range rn.Config.Provisioners { 839 // Check for a cached provisioner 840 provisioner, ok := cache[p.Type] 841 if !ok { 842 // Lookup the factory method 843 factory, ok := provisioners[p.Type] 844 if !ok { 845 errs = append(errs, fmt.Errorf( 846 "Resource provisioner not found for provisioner type '%s'", 847 p.Type)) 848 continue 849 } 850 851 // Initialize the provisioner 852 prov, err := factory() 853 if err != nil { 854 errs = append(errs, fmt.Errorf( 855 "Failed to instantiate provisioner type '%s': %v", 856 p.Type, err)) 857 continue 858 } 859 provisioner = prov 860 861 // Cache this type of provisioner 862 cache[p.Type] = prov 863 } 864 865 // Save the provisioner 866 rn.Resource.Provisioners = append(rn.Resource.Provisioners, &ResourceProvisionerConfig{ 867 Type: p.Type, 868 Provisioner: provisioner, 869 Config: NewResourceConfig(p.RawConfig), 870 RawConfig: p.RawConfig, 871 ConnInfo: p.ConnInfo, 872 }) 873 } 874 } 875 876 if len(errs) > 0 { 877 return &multierror.Error{Errors: errs} 878 } 879 return nil 880 } 881 882 // matchingPrefixes takes a resource type and a set of resource 883 // providers we know about by prefix and returns a list of prefixes 884 // that might be valid for that resource. 885 // 886 // The list returned is in the order that they should be attempted. 887 func matchingPrefixes( 888 t string, 889 ps map[string]ResourceProviderFactory) []string { 890 result := make([]string, 0, 1) 891 for prefix, _ := range ps { 892 if strings.HasPrefix(t, prefix) { 893 result = append(result, prefix) 894 } 895 } 896 897 // Sort by longest first 898 sort.Sort(stringLenSort(result)) 899 900 return result 901 } 902 903 // stringLenSort implements sort.Interface and sorts strings in increasing 904 // length order. i.e. "a", "aa", "aaa" 905 type stringLenSort []string 906 907 func (s stringLenSort) Len() int { 908 return len(s) 909 } 910 911 func (s stringLenSort) Less(i, j int) bool { 912 return len(s[i]) < len(s[j]) 913 } 914 915 func (s stringLenSort) Swap(i, j int) { 916 s[i], s[j] = s[j], s[i] 917 }