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