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