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