github.com/adamar/terraform@v0.2.2-0.20141016210445-2e703afdad0e/terraform/context.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "sort" 8 "strconv" 9 "strings" 10 "sync" 11 "sync/atomic" 12 13 "github.com/hashicorp/terraform/config" 14 "github.com/hashicorp/terraform/config/module" 15 "github.com/hashicorp/terraform/depgraph" 16 "github.com/hashicorp/terraform/helper/multierror" 17 ) 18 19 // This is a function type used to implement a walker for the resource 20 // tree internally on the Terraform structure. 21 type genericWalkFunc func(*walkContext, *Resource) error 22 23 // Context represents all the context that Terraform needs in order to 24 // perform operations on infrastructure. This structure is built using 25 // ContextOpts and NewContext. See the documentation for those. 26 // 27 // Additionally, a context can be created from a Plan using Plan.Context. 28 type Context struct { 29 module *module.Tree 30 diff *Diff 31 hooks []Hook 32 state *State 33 providerConfig map[string]map[string]map[string]interface{} 34 providers map[string]ResourceProviderFactory 35 provisioners map[string]ResourceProvisionerFactory 36 variables map[string]string 37 uiInput UIInput 38 39 parallelSem Semaphore // Semaphore used to limit parallelism 40 l sync.Mutex // Lock acquired during any task 41 sl sync.RWMutex // Lock acquired to R/W internal data 42 runCh <-chan struct{} 43 sh *stopHook 44 } 45 46 // ContextOpts are the user-creatable configuration structure to create 47 // a context with NewContext. 48 type ContextOpts struct { 49 Diff *Diff 50 Hooks []Hook 51 Module *module.Tree 52 Parallelism int 53 State *State 54 Providers map[string]ResourceProviderFactory 55 Provisioners map[string]ResourceProvisionerFactory 56 Variables map[string]string 57 58 UIInput UIInput 59 } 60 61 // InputMode defines what sort of input will be asked for when Input 62 // is called on Context. 63 type InputMode byte 64 65 const ( 66 // InputModeVar asks for variables 67 InputModeVar InputMode = 1 << iota 68 69 // InputModeProvider asks for provider variables 70 InputModeProvider 71 72 // InputModeStd is the standard operating mode and asks for both variables 73 // and providers. 74 InputModeStd = InputModeVar | InputModeProvider 75 ) 76 77 // NewContext creates a new context. 78 // 79 // Once a context is created, the pointer values within ContextOpts should 80 // not be mutated in any way, since the pointers are copied, not the values 81 // themselves. 82 func NewContext(opts *ContextOpts) *Context { 83 sh := new(stopHook) 84 85 // Copy all the hooks and add our stop hook. We don't append directly 86 // to the Config so that we're not modifying that in-place. 87 hooks := make([]Hook, len(opts.Hooks)+1) 88 copy(hooks, opts.Hooks) 89 hooks[len(opts.Hooks)] = sh 90 91 // Make the parallelism channel 92 par := opts.Parallelism 93 if par == 0 { 94 par = 10 95 } 96 97 return &Context{ 98 diff: opts.Diff, 99 hooks: hooks, 100 module: opts.Module, 101 state: opts.State, 102 providerConfig: make(map[string]map[string]map[string]interface{}), 103 providers: opts.Providers, 104 provisioners: opts.Provisioners, 105 variables: opts.Variables, 106 uiInput: opts.UIInput, 107 108 parallelSem: NewSemaphore(par), 109 sh: sh, 110 } 111 } 112 113 // Apply applies the changes represented by this context and returns 114 // the resulting state. 115 // 116 // In addition to returning the resulting state, this context is updated 117 // with the latest state. 118 func (c *Context) Apply() (*State, error) { 119 v := c.acquireRun() 120 defer c.releaseRun(v) 121 122 // Set our state right away. No matter what, this IS our new state, 123 // even if there is an error below. 124 c.state = c.state.deepcopy() 125 if c.state == nil { 126 c.state = &State{} 127 } 128 c.state.init() 129 130 // Walk 131 log.Printf("[INFO] Apply walk starting") 132 err := c.walkContext(walkApply, rootModulePath).Walk() 133 log.Printf("[INFO] Apply walk complete") 134 135 // Prune the state so that we have as clean a state as possible 136 c.state.prune() 137 138 return c.state, err 139 } 140 141 // Graph returns the graph for this context. 142 func (c *Context) Graph() (*depgraph.Graph, error) { 143 return Graph(&GraphOpts{ 144 Diff: c.diff, 145 Module: c.module, 146 Providers: c.providers, 147 Provisioners: c.provisioners, 148 State: c.state, 149 }) 150 } 151 152 // Input asks for input to fill variables and provider configurations. 153 // This modifies the configuration in-place, so asking for Input twice 154 // may result in different UI output showing different current values. 155 func (c *Context) Input(mode InputMode) error { 156 v := c.acquireRun() 157 defer c.releaseRun(v) 158 159 if mode&InputModeVar != 0 { 160 // Walk the variables first for the root module. We walk them in 161 // alphabetical order for UX reasons. 162 rootConf := c.module.Config() 163 names := make([]string, len(rootConf.Variables)) 164 m := make(map[string]*config.Variable) 165 for i, v := range rootConf.Variables { 166 names[i] = v.Name 167 m[v.Name] = v 168 } 169 sort.Strings(names) 170 for _, n := range names { 171 v := m[n] 172 switch v.Type() { 173 case config.VariableTypeMap: 174 continue 175 case config.VariableTypeString: 176 // Good! 177 default: 178 panic(fmt.Sprintf("Unknown variable type: %s", v.Type())) 179 } 180 181 var defaultString string 182 if v.Default != nil { 183 defaultString = v.Default.(string) 184 } 185 186 // Ask the user for a value for this variable 187 var value string 188 for { 189 var err error 190 value, err = c.uiInput.Input(&InputOpts{ 191 Id: fmt.Sprintf("var.%s", n), 192 Query: fmt.Sprintf("var.%s", n), 193 Default: defaultString, 194 Description: v.Description, 195 }) 196 if err != nil { 197 return fmt.Errorf( 198 "Error asking for %s: %s", n, err) 199 } 200 201 if value == "" && v.Required() { 202 // Redo if it is required. 203 continue 204 } 205 206 if value == "" { 207 // No value, just exit the loop. With no value, we just 208 // use whatever is currently set in variables. 209 break 210 } 211 212 break 213 } 214 215 if value != "" { 216 c.variables[n] = value 217 } 218 } 219 } 220 221 if mode&InputModeProvider != 0 { 222 // Create the walk context and walk the inputs, which will gather the 223 // inputs for any resource providers. 224 wc := c.walkContext(walkInput, rootModulePath) 225 wc.Meta = new(walkInputMeta) 226 return wc.Walk() 227 } 228 229 return nil 230 } 231 232 // Plan generates an execution plan for the given context. 233 // 234 // The execution plan encapsulates the context and can be stored 235 // in order to reinstantiate a context later for Apply. 236 // 237 // Plan also updates the diff of this context to be the diff generated 238 // by the plan, so Apply can be called after. 239 func (c *Context) Plan(opts *PlanOpts) (*Plan, error) { 240 v := c.acquireRun() 241 defer c.releaseRun(v) 242 243 p := &Plan{ 244 Module: c.module, 245 Vars: c.variables, 246 State: c.state, 247 } 248 249 wc := c.walkContext(walkInvalid, rootModulePath) 250 wc.Meta = p 251 252 if opts != nil && opts.Destroy { 253 wc.Operation = walkPlanDestroy 254 } else { 255 // Set our state to be something temporary. We do this so that 256 // the plan can update a fake state so that variables work, then 257 // we replace it back with our old state. 258 old := c.state 259 if old == nil { 260 c.state = &State{} 261 c.state.init() 262 } else { 263 c.state = old.deepcopy() 264 } 265 defer func() { 266 c.state = old 267 }() 268 269 wc.Operation = walkPlan 270 } 271 272 // Walk and run the plan 273 err := wc.Walk() 274 275 // Update the diff so that our context is up-to-date 276 c.diff = p.Diff 277 278 return p, err 279 } 280 281 // Refresh goes through all the resources in the state and refreshes them 282 // to their latest state. This will update the state that this context 283 // works with, along with returning it. 284 // 285 // Even in the case an error is returned, the state will be returned and 286 // will potentially be partially updated. 287 func (c *Context) Refresh() (*State, error) { 288 v := c.acquireRun() 289 defer c.releaseRun(v) 290 291 // Update our state 292 c.state = c.state.deepcopy() 293 294 // Walk the graph 295 err := c.walkContext(walkRefresh, rootModulePath).Walk() 296 297 // Prune the state 298 c.state.prune() 299 return c.state, err 300 } 301 302 // Stop stops the running task. 303 // 304 // Stop will block until the task completes. 305 func (c *Context) Stop() { 306 c.l.Lock() 307 ch := c.runCh 308 309 // If we aren't running, then just return 310 if ch == nil { 311 c.l.Unlock() 312 return 313 } 314 315 // Tell the hook we want to stop 316 c.sh.Stop() 317 318 // Wait for us to stop 319 c.l.Unlock() 320 <-ch 321 } 322 323 // Validate validates the configuration and returns any warnings or errors. 324 func (c *Context) Validate() ([]string, []error) { 325 var rerr *multierror.Error 326 327 // Validate the configuration itself 328 if err := c.module.Validate(); err != nil { 329 rerr = multierror.ErrorAppend(rerr, err) 330 } 331 332 // This only needs to be done for the root module, since inter-module 333 // variables are validated in the module tree. 334 if config := c.module.Config(); config != nil { 335 // Validate the user variables 336 if errs := smcUserVariables(config, c.variables); len(errs) > 0 { 337 rerr = multierror.ErrorAppend(rerr, errs...) 338 } 339 } 340 341 // Validate the entire graph 342 walkMeta := new(walkValidateMeta) 343 wc := c.walkContext(walkValidate, rootModulePath) 344 wc.Meta = walkMeta 345 if err := wc.Walk(); err != nil { 346 rerr = multierror.ErrorAppend(rerr, err) 347 } 348 349 // Flatten the warns/errs so that we get all the module errors as well, 350 // then aggregate. 351 warns, errs := walkMeta.Flatten() 352 if len(errs) > 0 { 353 rerr = multierror.ErrorAppend(rerr, errs...) 354 } 355 356 errs = nil 357 if rerr != nil && len(rerr.Errors) > 0 { 358 errs = rerr.Errors 359 } 360 361 return warns, errs 362 } 363 364 func (c *Context) acquireRun() chan<- struct{} { 365 c.l.Lock() 366 defer c.l.Unlock() 367 368 // Wait for no channel to exist 369 for c.runCh != nil { 370 c.l.Unlock() 371 ch := c.runCh 372 <-ch 373 c.l.Lock() 374 } 375 376 ch := make(chan struct{}) 377 c.runCh = ch 378 return ch 379 } 380 381 func (c *Context) releaseRun(ch chan<- struct{}) { 382 c.l.Lock() 383 defer c.l.Unlock() 384 385 close(ch) 386 c.runCh = nil 387 c.sh.Reset() 388 } 389 390 func (c *Context) walkContext(op walkOperation, path []string) *walkContext { 391 // Get the config structure 392 m := c.module 393 for _, n := range path[1:] { 394 cs := m.Children() 395 m = cs[n] 396 } 397 var conf *config.Config 398 if m != nil { 399 conf = m.Config() 400 } 401 402 // Calculate the default variable values 403 defaultVars := make(map[string]string) 404 if conf != nil { 405 for _, v := range conf.Variables { 406 for k, val := range v.DefaultsMap() { 407 defaultVars[k] = val 408 } 409 } 410 } 411 412 return &walkContext{ 413 Context: c, 414 Operation: op, 415 Path: path, 416 Variables: c.variables, 417 418 defaultVariables: defaultVars, 419 } 420 } 421 422 // walkContext is the context in which a graph walk is done. It stores 423 // much the same as a Context but works on a specific module. 424 type walkContext struct { 425 Context *Context 426 Meta interface{} 427 Operation walkOperation 428 Path []string 429 Variables map[string]string 430 431 defaultVariables map[string]string 432 433 // This is only set manually by subsequent context creations 434 // in genericWalkFunc. 435 graph *depgraph.Graph 436 } 437 438 // walkOperation is an enum which tells the walkContext what to do. 439 type walkOperation byte 440 441 const ( 442 walkInvalid walkOperation = iota 443 walkInput 444 walkApply 445 walkPlan 446 walkPlanDestroy 447 walkRefresh 448 walkValidate 449 ) 450 451 func (c *walkContext) Walk() error { 452 g := c.graph 453 if g == nil { 454 gopts := &GraphOpts{ 455 Module: c.Context.module, 456 Providers: c.Context.providers, 457 Provisioners: c.Context.provisioners, 458 State: c.Context.state, 459 } 460 if c.Operation == walkApply { 461 gopts.Diff = c.Context.diff 462 } 463 464 var err error 465 g, err = Graph(gopts) 466 if err != nil { 467 return err 468 } 469 } 470 471 var walkFn depgraph.WalkFunc 472 switch c.Operation { 473 case walkInput: 474 walkFn = c.inputWalkFn() 475 case walkApply: 476 walkFn = c.applyWalkFn() 477 case walkPlan: 478 walkFn = c.planWalkFn() 479 case walkPlanDestroy: 480 walkFn = c.planDestroyWalkFn() 481 case walkRefresh: 482 walkFn = c.refreshWalkFn() 483 case walkValidate: 484 walkFn = c.validateWalkFn() 485 default: 486 panic(fmt.Sprintf("unknown operation: %s", c.Operation)) 487 } 488 489 if err := g.Walk(walkFn); err != nil { 490 return err 491 } 492 493 switch c.Operation { 494 case walkInput: 495 fallthrough 496 case walkValidate: 497 // Don't calculate outputs 498 return nil 499 } 500 501 // We did an apply, so we need to calculate the outputs. If we have no 502 // outputs, then we're done. 503 m := c.Context.module 504 for _, n := range c.Path[1:] { 505 cs := m.Children() 506 m = cs[n] 507 } 508 if m == nil { 509 return nil 510 } 511 conf := m.Config() 512 if len(conf.Outputs) == 0 { 513 return nil 514 } 515 516 // Likewise, if we have no resources in our state, we're done. This 517 // guards against the case that we destroyed. 518 mod := c.Context.state.ModuleByPath(c.Path) 519 if mod == nil { 520 return nil 521 } 522 if c.Operation == walkApply { 523 // On Apply, we prune so that we don't do outputs if we destroyed 524 mod.prune() 525 } 526 if len(mod.Resources) == 0 { 527 mod.Outputs = nil 528 return nil 529 } 530 531 outputs := make(map[string]string) 532 for _, o := range conf.Outputs { 533 if err := c.computeVars(o.RawConfig, nil); err != nil { 534 return err 535 } 536 vraw := o.RawConfig.Config()["value"] 537 if vraw == nil { 538 // This likely means that the result of the output is 539 // a computed variable. 540 if o.RawConfig.Raw["value"] != nil { 541 vraw = config.UnknownVariableValue 542 } 543 } 544 if vraw != nil { 545 outputs[o.Name] = vraw.(string) 546 } 547 } 548 549 // Assign the outputs to the root module 550 mod.Outputs = outputs 551 552 return nil 553 } 554 555 func (c *walkContext) inputWalkFn() depgraph.WalkFunc { 556 meta := c.Meta.(*walkInputMeta) 557 meta.Lock() 558 if meta.Done == nil { 559 meta.Done = make(map[string]struct{}) 560 } 561 meta.Unlock() 562 563 return func(n *depgraph.Noun) error { 564 // If it is the root node, ignore 565 if n.Name == GraphRootNode { 566 return nil 567 } 568 569 switch rn := n.Meta.(type) { 570 case *GraphNodeModule: 571 // Build another walkContext for this module and walk it. 572 wc := c.Context.walkContext(c.Operation, rn.Path) 573 574 // Set the graph to specifically walk this subgraph 575 wc.graph = rn.Graph 576 577 // Preserve the meta 578 wc.Meta = c.Meta 579 580 return wc.Walk() 581 case *GraphNodeResource: 582 // Resources don't matter for input. Continue. 583 return nil 584 case *GraphNodeResourceProvider: 585 // Acquire the lock the whole time so we only ask for input 586 // one at a time. 587 meta.Lock() 588 defer meta.Unlock() 589 590 // If we already did this provider, then we're done. 591 if _, ok := meta.Done[rn.ID]; ok { 592 return nil 593 } 594 595 // Get the raw configuration because this is what we 596 // pass into the API. 597 var raw *config.RawConfig 598 sharedProvider := rn.Provider 599 if sharedProvider.Config != nil { 600 raw = sharedProvider.Config.RawConfig 601 } 602 rc := NewResourceConfig(raw) 603 604 // Wrap the input into a namespace 605 input := &PrefixUIInput{ 606 IdPrefix: fmt.Sprintf("provider.%s", rn.ID), 607 QueryPrefix: fmt.Sprintf("provider.%s.", rn.ID), 608 UIInput: c.Context.uiInput, 609 } 610 611 // Go through each provider and capture the input necessary 612 // to satisfy it. 613 configs := make(map[string]map[string]interface{}) 614 for k, p := range sharedProvider.Providers { 615 newc, err := p.Input(input, rc) 616 if err != nil { 617 return fmt.Errorf( 618 "Error configuring %s: %s", k, err) 619 } 620 if newc != nil { 621 configs[k] = newc.Raw 622 } 623 } 624 625 // Mark this provider as done 626 meta.Done[rn.ID] = struct{}{} 627 628 // Set the configuration 629 c.Context.providerConfig[rn.ID] = configs 630 } 631 632 return nil 633 } 634 } 635 636 func (c *walkContext) applyWalkFn() depgraph.WalkFunc { 637 cb := func(c *walkContext, r *Resource) error { 638 var err error 639 640 diff := r.Diff 641 if diff.Empty() { 642 log.Printf("[DEBUG] %s: Diff is empty. Will not apply.", r.Id) 643 return nil 644 } 645 646 is := r.State 647 if is == nil { 648 is = new(InstanceState) 649 } 650 is.init() 651 652 if !diff.Destroy { 653 // Since we need the configuration, interpolate the variables 654 if err := r.Config.interpolate(c, r); err != nil { 655 return err 656 } 657 658 diff, err = r.Provider.Diff(r.Info, is, r.Config) 659 if err != nil { 660 return err 661 } 662 663 // This can happen if we aren't actually applying anything 664 // except an ID (the "null" provider). It is not really an issue 665 // since the Same check later down will catch any real problems. 666 if diff == nil { 667 diff = new(InstanceDiff) 668 diff.init() 669 } 670 671 // Delete id from the diff because it is dependent on 672 // our internal plan function. 673 delete(r.Diff.Attributes, "id") 674 delete(diff.Attributes, "id") 675 676 // Verify the diffs are the same 677 if !r.Diff.Same(diff) { 678 log.Printf( 679 "[ERROR] Diffs don't match.\n\nDiff 1: %#v"+ 680 "\n\nDiff 2: %#v", 681 r.Diff, diff) 682 return fmt.Errorf( 683 "%s: diffs didn't match during apply. This is a "+ 684 "bug with the resource provider, please report a bug.", 685 r.Id) 686 } 687 } 688 689 // Remove any output values from the diff 690 for k, ad := range diff.Attributes { 691 if ad.Type == DiffAttrOutput { 692 delete(diff.Attributes, k) 693 } 694 } 695 696 for _, h := range c.Context.hooks { 697 handleHook(h.PreApply(r.Info, is, diff)) 698 } 699 700 // We create a new instance if there was no ID 701 // previously or the diff requires re-creating the 702 // underlying instance 703 createNew := is.ID == "" || diff.RequiresNew() 704 705 // With the completed diff, apply! 706 log.Printf("[DEBUG] %s: Executing Apply", r.Id) 707 is, applyerr := r.Provider.Apply(r.Info, is, diff) 708 709 var errs []error 710 if applyerr != nil { 711 errs = append(errs, applyerr) 712 } 713 714 // Make sure the result is instantiated 715 if is == nil { 716 is = new(InstanceState) 717 } 718 is.init() 719 720 // Force the "id" attribute to be our ID 721 if is.ID != "" { 722 is.Attributes["id"] = is.ID 723 } 724 725 for ak, av := range is.Attributes { 726 // If the value is the unknown variable value, then it is an error. 727 // In this case we record the error and remove it from the state 728 if av == config.UnknownVariableValue { 729 errs = append(errs, fmt.Errorf( 730 "Attribute with unknown value: %s", ak)) 731 delete(is.Attributes, ak) 732 } 733 } 734 735 // Set the result state 736 r.State = is 737 c.persistState(r) 738 739 // Invoke any provisioners we have defined. This is only done 740 // if the resource was created, as updates or deletes do not 741 // invoke provisioners. 742 // 743 // Additionally, we need to be careful to not run this if there 744 // was an error during the provider apply. 745 tainted := false 746 if applyerr == nil && createNew && len(r.Provisioners) > 0 { 747 for _, h := range c.Context.hooks { 748 handleHook(h.PreProvisionResource(r.Info, is)) 749 } 750 751 if err := c.applyProvisioners(r, is); err != nil { 752 errs = append(errs, err) 753 tainted = true 754 } 755 756 for _, h := range c.Context.hooks { 757 handleHook(h.PostProvisionResource(r.Info, is)) 758 } 759 } 760 761 // If we're tainted then we need to update some flags 762 if tainted && r.Flags&FlagTainted == 0 { 763 r.Flags &^= FlagPrimary 764 r.Flags &^= FlagHasTainted 765 r.Flags |= FlagTainted 766 r.TaintedIndex = -1 767 c.persistState(r) 768 } 769 770 for _, h := range c.Context.hooks { 771 handleHook(h.PostApply(r.Info, is, applyerr)) 772 } 773 774 // Determine the new state and update variables 775 err = nil 776 if len(errs) > 0 { 777 err = &multierror.Error{Errors: errs} 778 } 779 780 return err 781 } 782 783 return c.genericWalkFn(cb) 784 } 785 786 func (c *walkContext) planWalkFn() depgraph.WalkFunc { 787 var l sync.Mutex 788 789 // Initialize the result 790 result := c.Meta.(*Plan) 791 result.init() 792 793 cb := func(c *walkContext, r *Resource) error { 794 if r.Flags&FlagTainted != 0 { 795 // We don't diff tainted resources. 796 return nil 797 } 798 799 var diff *InstanceDiff 800 801 is := r.State 802 803 for _, h := range c.Context.hooks { 804 handleHook(h.PreDiff(r.Info, is)) 805 } 806 807 if r.Flags&FlagOrphan != 0 { 808 log.Printf("[DEBUG] %s: Orphan, marking for destroy", r.Id) 809 810 // This is an orphan (no config), so we mark it to be destroyed 811 diff = &InstanceDiff{Destroy: true} 812 } else { 813 // Make sure the configuration is interpolated 814 if err := r.Config.interpolate(c, r); err != nil { 815 return err 816 } 817 818 // Get a diff from the newest state 819 log.Printf("[DEBUG] %s: Executing diff", r.Id) 820 var err error 821 822 diffIs := is 823 if diffIs == nil || r.Flags&FlagHasTainted != 0 { 824 // If we're tainted, we pretend to create a new thing. 825 diffIs = new(InstanceState) 826 } 827 diffIs.init() 828 829 diff, err = r.Provider.Diff(r.Info, diffIs, r.Config) 830 if err != nil { 831 return err 832 } 833 } 834 835 if diff == nil { 836 diff = new(InstanceDiff) 837 } 838 839 if r.Flags&FlagHasTainted != 0 { 840 // This primary has a tainted resource, so just mark for 841 // destroy... 842 log.Printf("[DEBUG] %s: Tainted children, marking for destroy", r.Id) 843 diff.DestroyTainted = true 844 } 845 846 if diff.RequiresNew() && is != nil && is.ID != "" { 847 // This will also require a destroy 848 diff.Destroy = true 849 } 850 851 if diff.RequiresNew() || is == nil || is.ID == "" { 852 var oldID string 853 if is != nil { 854 oldID = is.Attributes["id"] 855 } 856 857 // Add diff to compute new ID 858 diff.init() 859 diff.Attributes["id"] = &ResourceAttrDiff{ 860 Old: oldID, 861 NewComputed: true, 862 RequiresNew: true, 863 Type: DiffAttrOutput, 864 } 865 } 866 867 if !diff.Empty() { 868 log.Printf("[DEBUG] %s: Diff: %#v", r.Id, diff) 869 870 l.Lock() 871 md := result.Diff.ModuleByPath(c.Path) 872 if md == nil { 873 md = result.Diff.AddModule(c.Path) 874 } 875 md.Resources[r.Id] = diff 876 l.Unlock() 877 } 878 879 for _, h := range c.Context.hooks { 880 handleHook(h.PostDiff(r.Info, diff)) 881 } 882 883 // Determine the new state and update variables 884 if !diff.Empty() { 885 is = is.MergeDiff(diff) 886 } 887 888 // Set it so that it can be updated 889 r.State = is 890 c.persistState(r) 891 892 return nil 893 } 894 895 return c.genericWalkFn(cb) 896 } 897 898 func (c *walkContext) planDestroyWalkFn() depgraph.WalkFunc { 899 var l sync.Mutex 900 901 // Initialize the result 902 result := c.Meta.(*Plan) 903 result.init() 904 905 var walkFn depgraph.WalkFunc 906 walkFn = func(n *depgraph.Noun) error { 907 switch m := n.Meta.(type) { 908 case *GraphNodeModule: 909 // Build another walkContext for this module and walk it. 910 wc := c.Context.walkContext(c.Operation, m.Path) 911 912 // Set the graph to specifically walk this subgraph 913 wc.graph = m.Graph 914 915 // Preserve the meta 916 wc.Meta = c.Meta 917 918 return wc.Walk() 919 case *GraphNodeResource: 920 // If we're expanding, then expand the nodes, and then rewalk the graph 921 if m.ExpandMode > ResourceExpandNone { 922 return c.genericWalkResource(m, walkFn) 923 } 924 925 r := m.Resource 926 927 if r.State != nil && r.State.ID != "" { 928 log.Printf("[DEBUG] %s: Making for destroy", r.Id) 929 930 l.Lock() 931 defer l.Unlock() 932 md := result.Diff.ModuleByPath(c.Path) 933 if md == nil { 934 md = result.Diff.AddModule(c.Path) 935 } 936 md.Resources[r.Id] = &InstanceDiff{Destroy: true} 937 } else { 938 log.Printf("[DEBUG] %s: Not marking for destroy, no ID", r.Id) 939 } 940 } 941 942 return nil 943 } 944 945 return walkFn 946 } 947 948 func (c *walkContext) refreshWalkFn() depgraph.WalkFunc { 949 cb := func(c *walkContext, r *Resource) error { 950 is := r.State 951 952 if is == nil || is.ID == "" { 953 log.Printf("[DEBUG] %s: Not refreshing, ID is empty", r.Id) 954 return nil 955 } 956 957 for _, h := range c.Context.hooks { 958 handleHook(h.PreRefresh(r.Info, is)) 959 } 960 961 is, err := r.Provider.Refresh(r.Info, is) 962 if err != nil { 963 return err 964 } 965 if is == nil { 966 is = new(InstanceState) 967 is.init() 968 } 969 970 // Set the updated state 971 r.State = is 972 c.persistState(r) 973 974 for _, h := range c.Context.hooks { 975 handleHook(h.PostRefresh(r.Info, is)) 976 } 977 978 return nil 979 } 980 981 return c.genericWalkFn(cb) 982 } 983 984 func (c *walkContext) validateWalkFn() depgraph.WalkFunc { 985 var l sync.Mutex 986 987 meta := c.Meta.(*walkValidateMeta) 988 if meta.Children == nil { 989 meta.Children = make(map[string]*walkValidateMeta) 990 } 991 992 var walkFn depgraph.WalkFunc 993 walkFn = func(n *depgraph.Noun) error { 994 // If it is the root node, ignore 995 if n.Name == GraphRootNode { 996 return nil 997 } 998 999 switch rn := n.Meta.(type) { 1000 case *GraphNodeModule: 1001 // Build another walkContext for this module and walk it. 1002 wc := c.Context.walkContext(walkValidate, rn.Path) 1003 1004 // Set the graph to specifically walk this subgraph 1005 wc.graph = rn.Graph 1006 1007 // Build the meta parameter. Do this by sharing the Children 1008 // reference but copying the rest into our own Children list. 1009 newMeta := new(walkValidateMeta) 1010 newMeta.Children = meta.Children 1011 wc.Meta = newMeta 1012 1013 if err := wc.Walk(); err != nil { 1014 return err 1015 } 1016 1017 newMeta.Children = nil 1018 meta.Children[strings.Join(rn.Path, ".")] = newMeta 1019 return nil 1020 case *GraphNodeResource: 1021 if rn.Resource == nil { 1022 panic("resource should never be nil") 1023 } 1024 1025 // If we're expanding, then expand the nodes, and then rewalk the graph 1026 if rn.ExpandMode > ResourceExpandNone { 1027 // Interpolate the count and verify it is non-negative 1028 rc := NewResourceConfig(rn.Config.RawCount) 1029 rc.interpolate(c, rn.Resource) 1030 count, err := rn.Config.Count() 1031 if err == nil { 1032 if count < 0 { 1033 err = fmt.Errorf( 1034 "%s error: count must be positive", rn.Resource.Id) 1035 } 1036 } 1037 if err != nil { 1038 l.Lock() 1039 defer l.Unlock() 1040 meta.Errs = append(meta.Errs, err) 1041 return nil 1042 } 1043 1044 return c.genericWalkResource(rn, walkFn) 1045 } 1046 1047 // If it doesn't have a provider, that is a different problem 1048 if rn.Resource.Provider == nil { 1049 return nil 1050 } 1051 1052 // Don't validate orphans or tainted since they never have a config 1053 if rn.Resource.Flags&FlagOrphan != 0 { 1054 return nil 1055 } 1056 if rn.Resource.Flags&FlagTainted != 0 { 1057 return nil 1058 } 1059 1060 // If the resouce name doesn't match the name regular 1061 // expression, show a warning. 1062 if !config.NameRegexp.Match([]byte(rn.Config.Name)) { 1063 l.Lock() 1064 meta.Warns = append(meta.Warns, fmt.Sprintf( 1065 "%s: module name can only contain letters, numbers, "+ 1066 "dashes, and underscores.\n"+ 1067 "This will be an error in Terraform 0.4", 1068 rn.Resource.Id)) 1069 l.Unlock() 1070 } 1071 1072 log.Printf("[INFO] Validating resource: %s", rn.Resource.Id) 1073 ws, es := rn.Resource.Provider.ValidateResource( 1074 rn.Resource.Info.Type, rn.Resource.Config) 1075 for i, w := range ws { 1076 ws[i] = fmt.Sprintf("'%s' warning: %s", rn.Resource.Id, w) 1077 } 1078 for i, e := range es { 1079 es[i] = fmt.Errorf("'%s' error: %s", rn.Resource.Id, e) 1080 } 1081 1082 l.Lock() 1083 meta.Warns = append(meta.Warns, ws...) 1084 meta.Errs = append(meta.Errs, es...) 1085 l.Unlock() 1086 1087 for idx, p := range rn.Resource.Provisioners { 1088 ws, es := p.Provisioner.Validate(p.Config) 1089 for i, w := range ws { 1090 ws[i] = fmt.Sprintf("'%s.provisioner.%d' warning: %s", rn.Resource.Id, idx, w) 1091 } 1092 for i, e := range es { 1093 es[i] = fmt.Errorf("'%s.provisioner.%d' error: %s", rn.Resource.Id, idx, e) 1094 } 1095 1096 l.Lock() 1097 meta.Warns = append(meta.Warns, ws...) 1098 meta.Errs = append(meta.Errs, es...) 1099 l.Unlock() 1100 } 1101 1102 case *GraphNodeResourceProvider: 1103 sharedProvider := rn.Provider 1104 1105 // Check if we have an override 1106 cs, ok := c.Context.providerConfig[rn.ID] 1107 if !ok { 1108 cs = make(map[string]map[string]interface{}) 1109 } 1110 1111 for k, p := range sharedProvider.Providers { 1112 // Merge the configurations to get what we use to configure with 1113 rc := sharedProvider.MergeConfig(false, cs[k]) 1114 rc.interpolate(c, nil) 1115 1116 log.Printf("[INFO] Validating provider: %s", k) 1117 ws, es := p.Validate(rc) 1118 for i, w := range ws { 1119 ws[i] = fmt.Sprintf("Provider '%s' warning: %s", k, w) 1120 } 1121 for i, e := range es { 1122 es[i] = fmt.Errorf("Provider '%s' error: %s", k, e) 1123 } 1124 1125 l.Lock() 1126 meta.Warns = append(meta.Warns, ws...) 1127 meta.Errs = append(meta.Errs, es...) 1128 l.Unlock() 1129 } 1130 } 1131 1132 return nil 1133 } 1134 1135 return walkFn 1136 } 1137 1138 func (c *walkContext) genericWalkFn(cb genericWalkFunc) depgraph.WalkFunc { 1139 // This will keep track of whether we're stopped or not 1140 var stop uint32 = 0 1141 1142 var walkFn depgraph.WalkFunc 1143 walkFn = func(n *depgraph.Noun) error { 1144 // If it is the root node, ignore 1145 if n.Name == GraphRootNode { 1146 return nil 1147 } 1148 1149 // If we're stopped, return right away 1150 if atomic.LoadUint32(&stop) != 0 { 1151 return nil 1152 } 1153 1154 switch m := n.Meta.(type) { 1155 case *GraphNodeModule: 1156 // Build another walkContext for this module and walk it. 1157 wc := c.Context.walkContext(c.Operation, m.Path) 1158 1159 // Set the graph to specifically walk this subgraph 1160 wc.graph = m.Graph 1161 1162 // Preserve the meta 1163 wc.Meta = c.Meta 1164 1165 // Set the variables 1166 if m.Config != nil { 1167 wc.Variables = make(map[string]string) 1168 1169 rc := NewResourceConfig(m.Config.RawConfig) 1170 rc.interpolate(c, nil) 1171 for k, v := range rc.Config { 1172 wc.Variables[k] = v.(string) 1173 } 1174 for k, _ := range rc.Raw { 1175 if _, ok := wc.Variables[k]; !ok { 1176 wc.Variables[k] = config.UnknownVariableValue 1177 } 1178 } 1179 } 1180 1181 return wc.Walk() 1182 case *GraphNodeResource: 1183 // Continue, we care about this the most 1184 case *GraphNodeResourceProvider: 1185 sharedProvider := m.Provider 1186 1187 // Check if we have an override 1188 cs, ok := c.Context.providerConfig[m.ID] 1189 if !ok { 1190 cs = make(map[string]map[string]interface{}) 1191 } 1192 1193 for k, p := range sharedProvider.Providers { 1194 // Merge the configurations to get what we use to configure with 1195 rc := sharedProvider.MergeConfig(false, cs[k]) 1196 rc.interpolate(c, nil) 1197 1198 log.Printf("[INFO] Configuring provider: %s", k) 1199 err := p.Configure(rc) 1200 if err != nil { 1201 return err 1202 } 1203 } 1204 1205 return nil 1206 default: 1207 panic(fmt.Sprintf("unknown graph node: %#v", n.Meta)) 1208 } 1209 1210 rn := n.Meta.(*GraphNodeResource) 1211 1212 // If we're expanding, then expand the nodes, and then rewalk the graph 1213 if rn.ExpandMode > ResourceExpandNone { 1214 return c.genericWalkResource(rn, walkFn) 1215 } 1216 1217 // Make sure that at least some resource configuration is set 1218 if rn.Config == nil { 1219 rn.Resource.Config = new(ResourceConfig) 1220 } else { 1221 rn.Resource.Config = NewResourceConfig(rn.Config.RawConfig) 1222 } 1223 1224 // Handle recovery of special panic scenarios 1225 defer func() { 1226 if v := recover(); v != nil { 1227 if v == HookActionHalt { 1228 atomic.StoreUint32(&stop, 1) 1229 } else { 1230 panic(v) 1231 } 1232 } 1233 }() 1234 1235 // Limit parallelism 1236 c.Context.parallelSem.Acquire() 1237 defer c.Context.parallelSem.Release() 1238 1239 // Call the callack 1240 log.Printf( 1241 "[INFO] Module %s walking: %s (Graph node: %s)", 1242 strings.Join(c.Path, "."), 1243 rn.Resource.Id, 1244 n.Name) 1245 if err := cb(c, rn.Resource); err != nil { 1246 log.Printf("[ERROR] Error walking '%s': %s", rn.Resource.Id, err) 1247 return err 1248 } 1249 1250 return nil 1251 } 1252 1253 return walkFn 1254 } 1255 1256 func (c *walkContext) genericWalkResource( 1257 rn *GraphNodeResource, fn depgraph.WalkFunc) error { 1258 // Interpolate the count 1259 rc := NewResourceConfig(rn.Config.RawCount) 1260 rc.interpolate(c, rn.Resource) 1261 1262 // Expand the node to the actual resources 1263 g, err := rn.Expand() 1264 if err != nil { 1265 return err 1266 } 1267 1268 // Walk the graph with our function 1269 if err := g.Walk(fn); err != nil { 1270 return err 1271 } 1272 1273 return nil 1274 } 1275 1276 // applyProvisioners is used to run any provisioners a resource has 1277 // defined after the resource creation has already completed. 1278 func (c *walkContext) applyProvisioners(r *Resource, is *InstanceState) error { 1279 // Store the original connection info, restore later 1280 origConnInfo := is.Ephemeral.ConnInfo 1281 defer func() { 1282 is.Ephemeral.ConnInfo = origConnInfo 1283 }() 1284 1285 for _, prov := range r.Provisioners { 1286 // Interpolate since we may have variables that depend on the 1287 // local resource. 1288 if err := prov.Config.interpolate(c, r); err != nil { 1289 return err 1290 } 1291 1292 // Interpolate the conn info, since it may contain variables 1293 connInfo := NewResourceConfig(prov.ConnInfo) 1294 if err := connInfo.interpolate(c, r); err != nil { 1295 return err 1296 } 1297 1298 // Merge the connection information 1299 overlay := make(map[string]string) 1300 if origConnInfo != nil { 1301 for k, v := range origConnInfo { 1302 overlay[k] = v 1303 } 1304 } 1305 for k, v := range connInfo.Config { 1306 switch vt := v.(type) { 1307 case string: 1308 overlay[k] = vt 1309 case int64: 1310 overlay[k] = strconv.FormatInt(vt, 10) 1311 case int32: 1312 overlay[k] = strconv.FormatInt(int64(vt), 10) 1313 case int: 1314 overlay[k] = strconv.FormatInt(int64(vt), 10) 1315 case float32: 1316 overlay[k] = strconv.FormatFloat(float64(vt), 'f', 3, 32) 1317 case float64: 1318 overlay[k] = strconv.FormatFloat(vt, 'f', 3, 64) 1319 case bool: 1320 overlay[k] = strconv.FormatBool(vt) 1321 default: 1322 overlay[k] = fmt.Sprintf("%v", vt) 1323 } 1324 } 1325 is.Ephemeral.ConnInfo = overlay 1326 1327 // Invoke the Provisioner 1328 for _, h := range c.Context.hooks { 1329 handleHook(h.PreProvision(r.Info, prov.Type)) 1330 } 1331 1332 output := ProvisionerUIOutput{ 1333 Info: r.Info, 1334 Type: prov.Type, 1335 Hooks: c.Context.hooks, 1336 } 1337 err := prov.Provisioner.Apply(&output, is, prov.Config) 1338 if err != nil { 1339 return err 1340 } 1341 1342 for _, h := range c.Context.hooks { 1343 handleHook(h.PostProvision(r.Info, prov.Type)) 1344 } 1345 } 1346 1347 return nil 1348 } 1349 1350 // persistState persists the state in a Resource to the actual final 1351 // state location. 1352 func (c *walkContext) persistState(r *Resource) { 1353 // Acquire a state lock around this whole thing since we're updating that 1354 c.Context.sl.Lock() 1355 defer c.Context.sl.Unlock() 1356 1357 // If we have no state, then we don't persist. 1358 if c.Context.state == nil { 1359 return 1360 } 1361 1362 // Get the state for this resource. The resource state should always 1363 // exist because we call graphInitState before anything that could 1364 // potentially call this. 1365 module := c.Context.state.ModuleByPath(c.Path) 1366 if module == nil { 1367 module = c.Context.state.AddModule(c.Path) 1368 } 1369 rs := module.Resources[r.Id] 1370 if rs == nil { 1371 rs = &ResourceState{Type: r.Info.Type} 1372 rs.init() 1373 module.Resources[r.Id] = rs 1374 } 1375 rs.Dependencies = r.Dependencies 1376 1377 // Assign the instance state to the proper location 1378 if r.Flags&FlagDeposed != 0 { 1379 // We were previously the primary and have been deposed, so 1380 // now we are the final tainted resource 1381 r.TaintedIndex = len(rs.Tainted) - 1 1382 rs.Tainted[r.TaintedIndex] = r.State 1383 1384 } else if r.Flags&FlagTainted != 0 { 1385 if r.TaintedIndex >= 0 { 1386 // Tainted with a pre-existing index, just update that spot 1387 rs.Tainted[r.TaintedIndex] = r.State 1388 1389 } else if r.Flags&FlagReplacePrimary != 0 { 1390 // We just replaced the primary, so restore the primary 1391 rs.Primary = rs.Tainted[len(rs.Tainted)-1] 1392 1393 // Set ourselves as tainted 1394 rs.Tainted[len(rs.Tainted)-1] = r.State 1395 1396 } else { 1397 // Newly tainted, so append it to the list, update the 1398 // index, and remove the primary. 1399 rs.Tainted = append(rs.Tainted, r.State) 1400 r.TaintedIndex = len(rs.Tainted) - 1 1401 rs.Primary = nil 1402 } 1403 1404 } else if r.Flags&FlagReplacePrimary != 0 { 1405 // If the ID is blank (there was an error), then we leave 1406 // the primary that exists, and do not store this as a tainted 1407 // instance 1408 if r.State.ID == "" { 1409 return 1410 } 1411 1412 // Push the old primary into the tainted state 1413 rs.Tainted = append(rs.Tainted, rs.Primary) 1414 1415 // Set this as the new primary 1416 rs.Primary = r.State 1417 1418 } else { 1419 // The primary instance, so just set it directly 1420 rs.Primary = r.State 1421 } 1422 1423 // Do a pruning so that empty resources are not saved 1424 rs.prune() 1425 } 1426 1427 // computeVars takes the State and given RawConfig and processes all 1428 // the variables. This dynamically discovers the attributes instead of 1429 // using a static map[string]string that the genericWalkFn uses. 1430 func (c *walkContext) computeVars( 1431 raw *config.RawConfig, r *Resource) error { 1432 // If there isn't a raw configuration, don't do anything 1433 if raw == nil { 1434 return nil 1435 } 1436 1437 // Copy the default variables 1438 vs := make(map[string]string) 1439 for k, v := range c.defaultVariables { 1440 vs[k] = v 1441 } 1442 1443 // Next, the actual computed variables 1444 for n, rawV := range raw.Variables { 1445 switch v := rawV.(type) { 1446 case *config.CountVariable: 1447 switch v.Type { 1448 case config.CountValueIndex: 1449 if r != nil { 1450 vs[n] = strconv.FormatInt(int64(r.CountIndex), 10) 1451 } 1452 } 1453 case *config.ModuleVariable: 1454 value, err := c.computeModuleVariable(v) 1455 if err != nil { 1456 return err 1457 } 1458 1459 vs[n] = value 1460 case *config.PathVariable: 1461 switch v.Type { 1462 case config.PathValueCwd: 1463 wd, err := os.Getwd() 1464 if err != nil { 1465 return fmt.Errorf( 1466 "Couldn't get cwd for var %s: %s", 1467 v.FullKey(), err) 1468 } 1469 1470 vs[n] = wd 1471 case config.PathValueModule: 1472 if t := c.Context.module.Child(c.Path[1:]); t != nil { 1473 vs[n] = t.Config().Dir 1474 } 1475 case config.PathValueRoot: 1476 vs[n] = c.Context.module.Config().Dir 1477 } 1478 case *config.ResourceVariable: 1479 var attr string 1480 var err error 1481 if v.Multi && v.Index == -1 { 1482 attr, err = c.computeResourceMultiVariable(v) 1483 } else { 1484 attr, err = c.computeResourceVariable(v) 1485 } 1486 if err != nil { 1487 return err 1488 } 1489 1490 vs[n] = attr 1491 case *config.UserVariable: 1492 val, ok := c.Variables[v.Name] 1493 if ok { 1494 vs[n] = val 1495 continue 1496 } 1497 1498 // Look up if we have any variables with this prefix because 1499 // those are map overrides. Include those. 1500 for k, val := range c.Variables { 1501 if strings.HasPrefix(k, v.Name+".") { 1502 vs["var."+k] = val 1503 } 1504 } 1505 } 1506 } 1507 1508 // Interpolate the variables 1509 return raw.Interpolate(vs) 1510 } 1511 1512 func (c *walkContext) computeModuleVariable( 1513 v *config.ModuleVariable) (string, error) { 1514 // Build the path to our child 1515 path := make([]string, len(c.Path), len(c.Path)+1) 1516 copy(path, c.Path) 1517 path = append(path, v.Name) 1518 1519 // Grab some locks 1520 c.Context.sl.RLock() 1521 defer c.Context.sl.RUnlock() 1522 1523 // Get that module from our state 1524 mod := c.Context.state.ModuleByPath(path) 1525 if mod == nil { 1526 return "", fmt.Errorf( 1527 "Module '%s' not found for variable '%s'", 1528 strings.Join(path[1:], "."), 1529 v.FullKey()) 1530 } 1531 1532 value, ok := mod.Outputs[v.Field] 1533 if !ok { 1534 return "", fmt.Errorf( 1535 "Output field '%s' not found for variable '%s'", 1536 v.Field, 1537 v.FullKey()) 1538 } 1539 1540 return value, nil 1541 } 1542 1543 func (c *walkContext) computeResourceVariable( 1544 v *config.ResourceVariable) (string, error) { 1545 id := v.ResourceId() 1546 if v.Multi { 1547 id = fmt.Sprintf("%s.%d", id, v.Index) 1548 } 1549 1550 c.Context.sl.RLock() 1551 defer c.Context.sl.RUnlock() 1552 1553 // Get the relevant module 1554 module := c.Context.state.ModuleByPath(c.Path) 1555 1556 r, ok := module.Resources[id] 1557 if !ok { 1558 if v.Multi && v.Index == 0 { 1559 r, ok = module.Resources[v.ResourceId()] 1560 } 1561 if !ok { 1562 return "", fmt.Errorf( 1563 "Resource '%s' not found for variable '%s'", 1564 id, 1565 v.FullKey()) 1566 } 1567 } 1568 1569 if r.Primary == nil { 1570 goto MISSING 1571 } 1572 1573 if attr, ok := r.Primary.Attributes[v.Field]; ok { 1574 return attr, nil 1575 } 1576 1577 // We didn't find the exact field, so lets separate the dots 1578 // and see if anything along the way is a computed set. i.e. if 1579 // we have "foo.0.bar" as the field, check to see if "foo" is 1580 // a computed list. If so, then the whole thing is computed. 1581 if parts := strings.Split(v.Field, "."); len(parts) > 1 { 1582 for i := 1; i < len(parts); i++ { 1583 key := fmt.Sprintf("%s.#", strings.Join(parts[:i], ".")) 1584 if attr, ok := r.Primary.Attributes[key]; ok { 1585 return attr, nil 1586 } 1587 } 1588 } 1589 1590 MISSING: 1591 return "", fmt.Errorf( 1592 "Resource '%s' does not have attribute '%s' "+ 1593 "for variable '%s'", 1594 id, 1595 v.Field, 1596 v.FullKey()) 1597 } 1598 1599 func (c *walkContext) computeResourceMultiVariable( 1600 v *config.ResourceVariable) (string, error) { 1601 c.Context.sl.RLock() 1602 defer c.Context.sl.RUnlock() 1603 1604 // Get the resource from the configuration so we can know how 1605 // many of the resource there is. 1606 var cr *config.Resource 1607 for _, r := range c.Context.module.Config().Resources { 1608 if r.Id() == v.ResourceId() { 1609 cr = r 1610 break 1611 } 1612 } 1613 if cr == nil { 1614 return "", fmt.Errorf( 1615 "Resource '%s' not found for variable '%s'", 1616 v.ResourceId(), 1617 v.FullKey()) 1618 } 1619 1620 // Get the relevant module 1621 // TODO: Not use only root module 1622 module := c.Context.state.RootModule() 1623 1624 count, err := cr.Count() 1625 if err != nil { 1626 return "", fmt.Errorf( 1627 "Error reading %s count: %s", 1628 v.ResourceId(), 1629 err) 1630 } 1631 1632 // If we have no count, return empty 1633 if count == 0 { 1634 return "", nil 1635 } 1636 1637 var values []string 1638 for i := 0; i < count; i++ { 1639 id := fmt.Sprintf("%s.%d", v.ResourceId(), i) 1640 1641 // If we're dealing with only a single resource, then the 1642 // ID doesn't have a trailing index. 1643 if count == 1 { 1644 id = v.ResourceId() 1645 } 1646 1647 r, ok := module.Resources[id] 1648 if !ok { 1649 continue 1650 } 1651 1652 if r.Primary == nil { 1653 continue 1654 } 1655 1656 attr, ok := r.Primary.Attributes[v.Field] 1657 if !ok { 1658 continue 1659 } 1660 1661 values = append(values, attr) 1662 } 1663 1664 if len(values) == 0 { 1665 return "", fmt.Errorf( 1666 "Resource '%s' does not have attribute '%s' "+ 1667 "for variable '%s'", 1668 v.ResourceId(), 1669 v.Field, 1670 v.FullKey()) 1671 } 1672 1673 return strings.Join(values, config.InterpSplitDelim), nil 1674 } 1675 1676 type walkInputMeta struct { 1677 sync.Mutex 1678 1679 Done map[string]struct{} 1680 } 1681 1682 type walkValidateMeta struct { 1683 Errs []error 1684 Warns []string 1685 Children map[string]*walkValidateMeta 1686 } 1687 1688 func (m *walkValidateMeta) Flatten() ([]string, []error) { 1689 // Prune out the empty children 1690 for k, m2 := range m.Children { 1691 if len(m2.Errs) == 0 && len(m2.Warns) == 0 { 1692 delete(m.Children, k) 1693 } 1694 } 1695 1696 // If we have no children, then just return what we have 1697 if len(m.Children) == 0 { 1698 return m.Warns, m.Errs 1699 } 1700 1701 // Otherwise, copy the errors and warnings 1702 errs := make([]error, len(m.Errs)) 1703 warns := make([]string, len(m.Warns)) 1704 for i, err := range m.Errs { 1705 errs[i] = err 1706 } 1707 for i, warn := range m.Warns { 1708 warns[i] = warn 1709 } 1710 1711 // Now go through each child and copy it in... 1712 for k, c := range m.Children { 1713 for _, err := range c.Errs { 1714 errs = append(errs, fmt.Errorf( 1715 "Module %s: %s", k, err)) 1716 } 1717 for _, warn := range c.Warns { 1718 warns = append(warns, fmt.Sprintf( 1719 "Module %s: %s", k, warn)) 1720 } 1721 } 1722 1723 return warns, errs 1724 }