github.com/ns1/terraform@v0.7.10-0.20161109153551-8949419bef40/terraform/context.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "sort" 7 "strings" 8 "sync" 9 10 "github.com/hashicorp/go-multierror" 11 "github.com/hashicorp/hcl" 12 "github.com/hashicorp/terraform/config" 13 "github.com/hashicorp/terraform/config/module" 14 "github.com/hashicorp/terraform/helper/experiment" 15 ) 16 17 // InputMode defines what sort of input will be asked for when Input 18 // is called on Context. 19 type InputMode byte 20 21 const ( 22 // InputModeVar asks for all variables 23 InputModeVar InputMode = 1 << iota 24 25 // InputModeVarUnset asks for variables which are not set yet. 26 // InputModeVar must be set for this to have an effect. 27 InputModeVarUnset 28 29 // InputModeProvider asks for provider variables 30 InputModeProvider 31 32 // InputModeStd is the standard operating mode and asks for both variables 33 // and providers. 34 InputModeStd = InputModeVar | InputModeProvider 35 ) 36 37 var ( 38 // contextFailOnShadowError will cause Context operations to return 39 // errors when shadow operations fail. This is only used for testing. 40 contextFailOnShadowError = false 41 42 // contextTestDeepCopyOnPlan will perform a Diff DeepCopy on every 43 // Plan operation, effectively testing the Diff DeepCopy whenever 44 // a Plan occurs. This is enabled for tests. 45 contextTestDeepCopyOnPlan = false 46 ) 47 48 // ContextOpts are the user-configurable options to create a context with 49 // NewContext. 50 type ContextOpts struct { 51 Destroy bool 52 Diff *Diff 53 Hooks []Hook 54 Module *module.Tree 55 Parallelism int 56 State *State 57 StateFutureAllowed bool 58 Providers map[string]ResourceProviderFactory 59 Provisioners map[string]ResourceProvisionerFactory 60 Shadow bool 61 Targets []string 62 Variables map[string]interface{} 63 64 UIInput UIInput 65 } 66 67 // Context represents all the context that Terraform needs in order to 68 // perform operations on infrastructure. This structure is built using 69 // NewContext. See the documentation for that. 70 // 71 // Extra functions on Context can be found in context_*.go files. 72 type Context struct { 73 // Maintainer note: Anytime this struct is changed, please verify 74 // that newShadowContext still does the right thing. Tests should 75 // fail regardless but putting this note here as well. 76 77 components contextComponentFactory 78 destroy bool 79 diff *Diff 80 diffLock sync.RWMutex 81 hooks []Hook 82 module *module.Tree 83 sh *stopHook 84 shadow bool 85 state *State 86 stateLock sync.RWMutex 87 targets []string 88 uiInput UIInput 89 variables map[string]interface{} 90 91 l sync.Mutex // Lock acquired during any task 92 parallelSem Semaphore 93 providerInputConfig map[string]map[string]interface{} 94 runCh <-chan struct{} 95 stopCh chan struct{} 96 shadowErr error 97 } 98 99 // NewContext creates a new Context structure. 100 // 101 // Once a Context is creator, the pointer values within ContextOpts 102 // should not be mutated in any way, since the pointers are copied, not 103 // the values themselves. 104 func NewContext(opts *ContextOpts) (*Context, error) { 105 // Copy all the hooks and add our stop hook. We don't append directly 106 // to the Config so that we're not modifying that in-place. 107 sh := new(stopHook) 108 hooks := make([]Hook, len(opts.Hooks)+1) 109 copy(hooks, opts.Hooks) 110 hooks[len(opts.Hooks)] = sh 111 112 state := opts.State 113 if state == nil { 114 state = new(State) 115 state.init() 116 } 117 118 // If our state is from the future, then error. Callers can avoid 119 // this error by explicitly setting `StateFutureAllowed`. 120 if !opts.StateFutureAllowed && state.FromFutureTerraform() { 121 return nil, fmt.Errorf( 122 "Terraform doesn't allow running any operations against a state\n"+ 123 "that was written by a future Terraform version. The state is\n"+ 124 "reporting it is written by Terraform '%s'.\n\n"+ 125 "Please run at least that version of Terraform to continue.", 126 state.TFVersion) 127 } 128 129 // Explicitly reset our state version to our current version so that 130 // any operations we do will write out that our latest version 131 // has run. 132 state.TFVersion = Version 133 134 // Determine parallelism, default to 10. We do this both to limit 135 // CPU pressure but also to have an extra guard against rate throttling 136 // from providers. 137 par := opts.Parallelism 138 if par == 0 { 139 par = 10 140 } 141 142 // Set up the variables in the following sequence: 143 // 0 - Take default values from the configuration 144 // 1 - Take values from TF_VAR_x environment variables 145 // 2 - Take values specified in -var flags, overriding values 146 // set by environment variables if necessary. This includes 147 // values taken from -var-file in addition. 148 variables := make(map[string]interface{}) 149 150 if opts.Module != nil { 151 var err error 152 variables, err = Variables(opts.Module, opts.Variables) 153 if err != nil { 154 return nil, err 155 } 156 } 157 158 return &Context{ 159 components: &basicComponentFactory{ 160 providers: opts.Providers, 161 provisioners: opts.Provisioners, 162 }, 163 destroy: opts.Destroy, 164 diff: opts.Diff, 165 hooks: hooks, 166 module: opts.Module, 167 shadow: opts.Shadow, 168 state: state, 169 targets: opts.Targets, 170 uiInput: opts.UIInput, 171 variables: variables, 172 173 parallelSem: NewSemaphore(par), 174 providerInputConfig: make(map[string]map[string]interface{}), 175 sh: sh, 176 }, nil 177 } 178 179 type ContextGraphOpts struct { 180 Validate bool 181 Verbose bool 182 } 183 184 // Graph returns the graph for this config. 185 func (c *Context) Graph(g *ContextGraphOpts) (*Graph, error) { 186 return c.graphBuilder(g).Build(RootModulePath) 187 } 188 189 // GraphBuilder returns the GraphBuilder that will be used to create 190 // the graphs for this context. 191 func (c *Context) graphBuilder(g *ContextGraphOpts) GraphBuilder { 192 return &BuiltinGraphBuilder{ 193 Root: c.module, 194 Diff: c.diff, 195 Providers: c.components.ResourceProviders(), 196 Provisioners: c.components.ResourceProvisioners(), 197 State: c.state, 198 Targets: c.targets, 199 Destroy: c.destroy, 200 Validate: g.Validate, 201 Verbose: g.Verbose, 202 } 203 } 204 205 // ShadowError returns any errors caught during a shadow operation. 206 // 207 // A shadow operation is an operation run in parallel to a real operation 208 // that performs the same tasks using new logic on copied state. The results 209 // are compared to ensure that the new logic works the same as the old logic. 210 // The shadow never affects the real operation or return values. 211 // 212 // The result of the shadow operation are only available through this function 213 // call after a real operation is complete. 214 // 215 // For API consumers of Context, you can safely ignore this function 216 // completely if you have no interest in helping report experimental feature 217 // errors to Terraform maintainers. Otherwise, please call this function 218 // after every operation and report this to the user. 219 // 220 // IMPORTANT: Shadow errors are _never_ critical: they _never_ affect 221 // the real state or result of a real operation. They are purely informational 222 // to assist in future Terraform versions being more stable. Please message 223 // this effectively to the end user. 224 // 225 // This must be called only when no other operation is running (refresh, 226 // plan, etc.). The result can be used in parallel to any other operation 227 // running. 228 func (c *Context) ShadowError() error { 229 return c.shadowErr 230 } 231 232 // Input asks for input to fill variables and provider configurations. 233 // This modifies the configuration in-place, so asking for Input twice 234 // may result in different UI output showing different current values. 235 func (c *Context) Input(mode InputMode) error { 236 v := c.acquireRun("input") 237 defer c.releaseRun(v) 238 239 if mode&InputModeVar != 0 { 240 // Walk the variables first for the root module. We walk them in 241 // alphabetical order for UX reasons. 242 rootConf := c.module.Config() 243 names := make([]string, len(rootConf.Variables)) 244 m := make(map[string]*config.Variable) 245 for i, v := range rootConf.Variables { 246 names[i] = v.Name 247 m[v.Name] = v 248 } 249 sort.Strings(names) 250 for _, n := range names { 251 // If we only care about unset variables, then if the variable 252 // is set, continue on. 253 if mode&InputModeVarUnset != 0 { 254 if _, ok := c.variables[n]; ok { 255 continue 256 } 257 } 258 259 var valueType config.VariableType 260 261 v := m[n] 262 switch valueType = v.Type(); valueType { 263 case config.VariableTypeUnknown: 264 continue 265 case config.VariableTypeMap: 266 // OK 267 case config.VariableTypeList: 268 // OK 269 case config.VariableTypeString: 270 // OK 271 default: 272 panic(fmt.Sprintf("Unknown variable type: %#v", v.Type())) 273 } 274 275 // If the variable is not already set, and the variable defines a 276 // default, use that for the value. 277 if _, ok := c.variables[n]; !ok { 278 if v.Default != nil { 279 c.variables[n] = v.Default.(string) 280 continue 281 } 282 } 283 284 // this should only happen during tests 285 if c.uiInput == nil { 286 log.Println("[WARN] Content.uiInput is nil") 287 continue 288 } 289 290 // Ask the user for a value for this variable 291 var value string 292 retry := 0 293 for { 294 var err error 295 value, err = c.uiInput.Input(&InputOpts{ 296 Id: fmt.Sprintf("var.%s", n), 297 Query: fmt.Sprintf("var.%s", n), 298 Description: v.Description, 299 }) 300 if err != nil { 301 return fmt.Errorf( 302 "Error asking for %s: %s", n, err) 303 } 304 305 if value == "" && v.Required() { 306 // Redo if it is required, but abort if we keep getting 307 // blank entries 308 if retry > 2 { 309 return fmt.Errorf("missing required value for %q", n) 310 } 311 retry++ 312 continue 313 } 314 315 break 316 } 317 318 // no value provided, so don't set the variable at all 319 if value == "" { 320 continue 321 } 322 323 decoded, err := parseVariableAsHCL(n, value, valueType) 324 if err != nil { 325 return err 326 } 327 328 if decoded != nil { 329 c.variables[n] = decoded 330 } 331 } 332 } 333 334 if mode&InputModeProvider != 0 { 335 // Build the graph 336 graph, err := c.Graph(&ContextGraphOpts{Validate: true}) 337 if err != nil { 338 return err 339 } 340 341 // Do the walk 342 if _, err := c.walk(graph, nil, walkInput); err != nil { 343 return err 344 } 345 } 346 347 return nil 348 } 349 350 // Apply applies the changes represented by this context and returns 351 // the resulting state. 352 // 353 // In addition to returning the resulting state, this context is updated 354 // with the latest state. 355 func (c *Context) Apply() (*State, error) { 356 v := c.acquireRun("apply") 357 defer c.releaseRun(v) 358 359 // Copy our own state 360 c.state = c.state.DeepCopy() 361 362 X_newApply := experiment.Enabled(experiment.X_newApply) 363 X_newDestroy := experiment.Enabled(experiment.X_newDestroy) 364 newGraphEnabled := (c.destroy && X_newDestroy) || (!c.destroy && X_newApply) 365 366 // Build the original graph. This is before the new graph builders 367 // coming in 0.8. We do this for shadow graphing. 368 oldGraph, err := c.Graph(&ContextGraphOpts{Validate: true}) 369 if err != nil && X_newApply { 370 // If we had an error graphing but we're using the new graph, 371 // just set it to nil and let it go. There are some features that 372 // may work with the new graph that don't with the old. 373 oldGraph = nil 374 err = nil 375 } 376 if err != nil { 377 return nil, err 378 } 379 380 // Build the new graph. We do this no matter what so we can shadow it. 381 newGraph, err := (&ApplyGraphBuilder{ 382 Module: c.module, 383 Diff: c.diff, 384 State: c.state, 385 Providers: c.components.ResourceProviders(), 386 Provisioners: c.components.ResourceProvisioners(), 387 Destroy: c.destroy, 388 }).Build(RootModulePath) 389 if err != nil && !newGraphEnabled { 390 // If we had an error graphing but we're not using this graph, just 391 // set it to nil and record it as a shadow error. 392 c.shadowErr = multierror.Append(c.shadowErr, fmt.Errorf( 393 "Error building new graph: %s", err)) 394 395 newGraph = nil 396 err = nil 397 } 398 if err != nil { 399 return nil, err 400 } 401 402 // Determine what is the real and what is the shadow. The logic here 403 // is straightforward though the if statements are not: 404 // 405 // * Destroy mode - always use original, shadow with nothing because 406 // we're only testing the new APPLY graph. 407 // * Apply with new apply - use new graph, shadow is new graph. We can't 408 // shadow with the old graph because the old graph does a lot more 409 // that it shouldn't. 410 // * Apply with old apply - use old graph, shadow with new graph. 411 // 412 real := oldGraph 413 shadow := newGraph 414 if newGraphEnabled { 415 log.Printf("[WARN] terraform: real graph is experiment, shadow is experiment") 416 real = shadow 417 } else { 418 log.Printf("[WARN] terraform: real graph is original, shadow is experiment") 419 } 420 421 // Determine the operation 422 operation := walkApply 423 if c.destroy { 424 operation = walkDestroy 425 } 426 427 // This shouldn't happen, so assert it. This is before any state changes 428 // so it is safe to crash here. 429 if real == nil { 430 panic("nil real graph") 431 } 432 433 // Walk the graph 434 walker, err := c.walk(real, shadow, operation) 435 if len(walker.ValidationErrors) > 0 { 436 err = multierror.Append(err, walker.ValidationErrors...) 437 } 438 439 // Clean out any unused things 440 c.state.prune() 441 442 return c.state, err 443 } 444 445 // Plan generates an execution plan for the given context. 446 // 447 // The execution plan encapsulates the context and can be stored 448 // in order to reinstantiate a context later for Apply. 449 // 450 // Plan also updates the diff of this context to be the diff generated 451 // by the plan, so Apply can be called after. 452 func (c *Context) Plan() (*Plan, error) { 453 v := c.acquireRun("plan") 454 defer c.releaseRun(v) 455 456 p := &Plan{ 457 Module: c.module, 458 Vars: c.variables, 459 State: c.state, 460 Targets: c.targets, 461 } 462 463 var operation walkOperation 464 if c.destroy { 465 operation = walkPlanDestroy 466 } else { 467 // Set our state to be something temporary. We do this so that 468 // the plan can update a fake state so that variables work, then 469 // we replace it back with our old state. 470 old := c.state 471 if old == nil { 472 c.state = &State{} 473 c.state.init() 474 } else { 475 c.state = old.DeepCopy() 476 } 477 defer func() { 478 c.state = old 479 }() 480 481 operation = walkPlan 482 } 483 484 // Setup our diff 485 c.diffLock.Lock() 486 c.diff = new(Diff) 487 c.diff.init() 488 c.diffLock.Unlock() 489 490 // Used throughout below 491 X_newDestroy := experiment.Enabled(experiment.X_newDestroy) 492 493 // Build the graph. We have a branch here since for the pure-destroy 494 // plan (c.destroy) we use a much simpler graph builder that simply 495 // walks the state and reverses edges. 496 var graph *Graph 497 var err error 498 if c.destroy && X_newDestroy { 499 graph, err = (&DestroyPlanGraphBuilder{ 500 Module: c.module, 501 State: c.state, 502 Targets: c.targets, 503 }).Build(RootModulePath) 504 } else { 505 graph, err = c.Graph(&ContextGraphOpts{Validate: true}) 506 } 507 if err != nil { 508 return nil, err 509 } 510 511 // Do the walk 512 walker, err := c.walk(graph, graph, operation) 513 if err != nil { 514 return nil, err 515 } 516 p.Diff = c.diff 517 518 // If this is true, it means we're running unit tests. In this case, 519 // we perform a deep copy just to ensure that all context tests also 520 // test that a diff is copy-able. This will panic if it fails. This 521 // is enabled during unit tests. 522 // 523 // This should never be true during production usage, but even if it is, 524 // it can't do any real harm. 525 if contextTestDeepCopyOnPlan { 526 p.Diff.DeepCopy() 527 } 528 529 // We don't do the reverification during the new destroy plan because 530 // it will use a different apply process. 531 if !(c.destroy && X_newDestroy) { 532 // Now that we have a diff, we can build the exact graph that Apply will use 533 // and catch any possible cycles during the Plan phase. 534 if _, err := c.Graph(&ContextGraphOpts{Validate: true}); err != nil { 535 return nil, err 536 } 537 } 538 539 var errs error 540 if len(walker.ValidationErrors) > 0 { 541 errs = multierror.Append(errs, walker.ValidationErrors...) 542 } 543 return p, errs 544 } 545 546 // Refresh goes through all the resources in the state and refreshes them 547 // to their latest state. This will update the state that this context 548 // works with, along with returning it. 549 // 550 // Even in the case an error is returned, the state will be returned and 551 // will potentially be partially updated. 552 func (c *Context) Refresh() (*State, error) { 553 v := c.acquireRun("refresh") 554 defer c.releaseRun(v) 555 556 // Copy our own state 557 c.state = c.state.DeepCopy() 558 559 // Build the graph 560 graph, err := c.Graph(&ContextGraphOpts{Validate: true}) 561 if err != nil { 562 return nil, err 563 } 564 565 // Do the walk 566 if _, err := c.walk(graph, graph, walkRefresh); err != nil { 567 return nil, err 568 } 569 570 // Clean out any unused things 571 c.state.prune() 572 573 return c.state, nil 574 } 575 576 // Stop stops the running task. 577 // 578 // Stop will block until the task completes. 579 func (c *Context) Stop() { 580 c.l.Lock() 581 ch := c.runCh 582 583 // If we aren't running, then just return 584 if ch == nil { 585 c.l.Unlock() 586 return 587 } 588 589 // Tell the hook we want to stop 590 c.sh.Stop() 591 592 // Close the stop channel 593 close(c.stopCh) 594 595 // Wait for us to stop 596 c.l.Unlock() 597 <-ch 598 } 599 600 // Validate validates the configuration and returns any warnings or errors. 601 func (c *Context) Validate() ([]string, []error) { 602 v := c.acquireRun("validate") 603 defer c.releaseRun(v) 604 605 var errs error 606 607 // Validate the configuration itself 608 if err := c.module.Validate(); err != nil { 609 errs = multierror.Append(errs, err) 610 } 611 612 // This only needs to be done for the root module, since inter-module 613 // variables are validated in the module tree. 614 if config := c.module.Config(); config != nil { 615 // Validate the user variables 616 if err := smcUserVariables(config, c.variables); len(err) > 0 { 617 errs = multierror.Append(errs, err...) 618 } 619 } 620 621 // If we have errors at this point, the graphing has no chance, 622 // so just bail early. 623 if errs != nil { 624 return nil, []error{errs} 625 } 626 627 // Build the graph so we can walk it and run Validate on nodes. 628 // We also validate the graph generated here, but this graph doesn't 629 // necessarily match the graph that Plan will generate, so we'll validate the 630 // graph again later after Planning. 631 graph, err := c.Graph(&ContextGraphOpts{Validate: true}) 632 if err != nil { 633 return nil, []error{err} 634 } 635 636 // Walk 637 walker, err := c.walk(graph, graph, walkValidate) 638 if err != nil { 639 return nil, multierror.Append(errs, err).Errors 640 } 641 642 // Return the result 643 rerrs := multierror.Append(errs, walker.ValidationErrors...) 644 return walker.ValidationWarnings, rerrs.Errors 645 } 646 647 // Module returns the module tree associated with this context. 648 func (c *Context) Module() *module.Tree { 649 return c.module 650 } 651 652 // Variables will return the mapping of variables that were defined 653 // for this Context. If Input was called, this mapping may be different 654 // than what was given. 655 func (c *Context) Variables() map[string]interface{} { 656 return c.variables 657 } 658 659 // SetVariable sets a variable after a context has already been built. 660 func (c *Context) SetVariable(k string, v interface{}) { 661 c.variables[k] = v 662 } 663 664 func (c *Context) acquireRun(phase string) chan<- struct{} { 665 c.l.Lock() 666 defer c.l.Unlock() 667 668 dbug.SetPhase(phase) 669 670 // Wait for no channel to exist 671 for c.runCh != nil { 672 c.l.Unlock() 673 ch := c.runCh 674 <-ch 675 c.l.Lock() 676 } 677 678 // Create the new channel 679 ch := make(chan struct{}) 680 c.runCh = ch 681 682 // Reset the stop channel so we can watch that 683 c.stopCh = make(chan struct{}) 684 685 // Reset the stop hook so we're not stopped 686 c.sh.Reset() 687 688 // Reset the shadow errors 689 c.shadowErr = nil 690 691 return ch 692 } 693 694 func (c *Context) releaseRun(ch chan<- struct{}) { 695 c.l.Lock() 696 defer c.l.Unlock() 697 698 // setting the phase to "INVALID" lets us easily detect if we have 699 // operations happening outside of a run, or we missed setting the proper 700 // phase 701 dbug.SetPhase("INVALID") 702 703 close(ch) 704 c.runCh = nil 705 c.stopCh = nil 706 } 707 708 func (c *Context) walk( 709 graph, shadow *Graph, operation walkOperation) (*ContextGraphWalker, error) { 710 // Keep track of the "real" context which is the context that does 711 // the real work: talking to real providers, modifying real state, etc. 712 realCtx := c 713 714 // If we don't want shadowing, remove it 715 if !experiment.Enabled(experiment.X_shadow) { 716 shadow = nil 717 } 718 719 // If we have a shadow graph, walk that as well 720 var shadowCtx *Context 721 var shadowCloser Shadow 722 if c.shadow && shadow != nil { 723 // Build the shadow context. In the process, override the real context 724 // with the one that is wrapped so that the shadow context can verify 725 // the results of the real. 726 realCtx, shadowCtx, shadowCloser = newShadowContext(c) 727 } 728 729 // Just log this so we can see it in a debug log 730 if !c.shadow { 731 log.Printf("[WARN] terraform: shadow graph disabled") 732 } 733 734 log.Printf("[DEBUG] Starting graph walk: %s", operation.String()) 735 736 dg, _ := NewDebugGraph("walk", graph, nil) 737 walker := &ContextGraphWalker{ 738 Context: realCtx, 739 Operation: operation, 740 DebugGraph: dg, 741 } 742 743 // Watch for a stop so we can call the provider Stop() API. 744 doneCh := make(chan struct{}) 745 go c.watchStop(walker, c.stopCh, doneCh) 746 747 // Walk the real graph, this will block until it completes 748 realErr := graph.Walk(walker) 749 750 // Close the done channel so the watcher stops 751 close(doneCh) 752 753 // If we have a shadow graph and we interrupted the real graph, then 754 // we just close the shadow and never verify it. It is non-trivial to 755 // recreate the exact execution state up until an interruption so this 756 // isn't supported with shadows at the moment. 757 if shadowCloser != nil && c.sh.Stopped() { 758 // Ignore the error result, there is nothing we could care about 759 shadowCloser.CloseShadow() 760 761 // Set it to nil so we don't do anything 762 shadowCloser = nil 763 } 764 765 // If we have a shadow graph, wait for that to complete. 766 if shadowCloser != nil { 767 // create a debug graph for this walk 768 dg, err := NewDebugGraph("walk-shadow", shadow, nil) 769 if err != nil { 770 log.Printf("[ERROR] %v", err) 771 } 772 773 // Build the graph walker for the shadow. We also wrap this in 774 // a panicwrap so that panics are captured. For the shadow graph, 775 // we just want panics to be normal errors rather than to crash 776 // Terraform. 777 shadowWalker := GraphWalkerPanicwrap(&ContextGraphWalker{ 778 Context: shadowCtx, 779 Operation: operation, 780 DebugGraph: dg, 781 }) 782 783 // Kick off the shadow walk. This will block on any operations 784 // on the real walk so it is fine to start first. 785 log.Printf("[INFO] Starting shadow graph walk: %s", operation.String()) 786 shadowCh := make(chan error) 787 go func() { 788 shadowCh <- shadow.Walk(shadowWalker) 789 }() 790 791 // Notify the shadow that we're done 792 if err := shadowCloser.CloseShadow(); err != nil { 793 c.shadowErr = multierror.Append(c.shadowErr, err) 794 } 795 796 // Wait for the walk to end 797 log.Printf("[DEBUG] Waiting for shadow graph to complete...") 798 shadowWalkErr := <-shadowCh 799 800 // Get any shadow errors 801 if err := shadowCloser.ShadowError(); err != nil { 802 c.shadowErr = multierror.Append(c.shadowErr, err) 803 } 804 805 // Verify the contexts (compare) 806 if err := shadowContextVerify(realCtx, shadowCtx); err != nil { 807 c.shadowErr = multierror.Append(c.shadowErr, err) 808 } 809 810 // At this point, if we're supposed to fail on error, then 811 // we PANIC. Some tests just verify that there is an error, 812 // so simply appending it to realErr and returning could hide 813 // shadow problems. 814 // 815 // This must be done BEFORE appending shadowWalkErr since the 816 // shadowWalkErr may include expected errors. 817 if c.shadowErr != nil && contextFailOnShadowError { 818 panic(multierror.Prefix(c.shadowErr, "shadow graph:")) 819 } 820 821 // Now, if we have a walk error, we append that through 822 if shadowWalkErr != nil { 823 c.shadowErr = multierror.Append(c.shadowErr, shadowWalkErr) 824 } 825 826 if c.shadowErr == nil { 827 log.Printf("[INFO] Shadow graph success!") 828 } else { 829 log.Printf("[ERROR] Shadow graph error: %s", c.shadowErr) 830 831 // If we're supposed to fail on shadow errors, then report it 832 if contextFailOnShadowError { 833 realErr = multierror.Append(realErr, multierror.Prefix( 834 c.shadowErr, "shadow graph:")) 835 } 836 } 837 } 838 839 return walker, realErr 840 } 841 842 func (c *Context) watchStop(walker *ContextGraphWalker, stopCh, doneCh <-chan struct{}) { 843 // Wait for a stop or completion 844 select { 845 case <-stopCh: 846 // Stop was triggered. Fall out of the select 847 case <-doneCh: 848 // Done, just exit completely 849 return 850 } 851 852 // If we're here, we're stopped, trigger the call. 853 854 // Copy the providers so that a misbehaved blocking Stop doesn't 855 // completely hang Terraform. 856 walker.providerLock.Lock() 857 ps := make([]ResourceProvider, 0, len(walker.providerCache)) 858 for _, p := range walker.providerCache { 859 ps = append(ps, p) 860 } 861 defer walker.providerLock.Unlock() 862 863 for _, p := range ps { 864 // We ignore the error for now since there isn't any reasonable 865 // action to take if there is an error here, since the stop is still 866 // advisory: Terraform will exit once the graph node completes. 867 p.Stop() 868 } 869 } 870 871 // parseVariableAsHCL parses the value of a single variable as would have been specified 872 // on the command line via -var or in an environment variable named TF_VAR_x, where x is 873 // the name of the variable. In order to get around the restriction of HCL requiring a 874 // top level object, we prepend a sentinel key, decode the user-specified value as its 875 // value and pull the value back out of the resulting map. 876 func parseVariableAsHCL(name string, input string, targetType config.VariableType) (interface{}, error) { 877 // expecting a string so don't decode anything, just strip quotes 878 if targetType == config.VariableTypeString { 879 return strings.Trim(input, `"`), nil 880 } 881 882 // return empty types 883 if strings.TrimSpace(input) == "" { 884 switch targetType { 885 case config.VariableTypeList: 886 return []interface{}{}, nil 887 case config.VariableTypeMap: 888 return make(map[string]interface{}), nil 889 } 890 } 891 892 const sentinelValue = "SENTINEL_TERRAFORM_VAR_OVERRIDE_KEY" 893 inputWithSentinal := fmt.Sprintf("%s = %s", sentinelValue, input) 894 895 var decoded map[string]interface{} 896 err := hcl.Decode(&decoded, inputWithSentinal) 897 if err != nil { 898 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL: %s", name, input, err) 899 } 900 901 if len(decoded) != 1 { 902 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. Only one value may be specified.", name, input) 903 } 904 905 parsedValue, ok := decoded[sentinelValue] 906 if !ok { 907 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) 908 } 909 910 switch targetType { 911 case config.VariableTypeList: 912 return parsedValue, nil 913 case config.VariableTypeMap: 914 if list, ok := parsedValue.([]map[string]interface{}); ok { 915 return list[0], nil 916 } 917 918 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) 919 default: 920 panic(fmt.Errorf("unknown type %s", targetType.Printable())) 921 } 922 }