github.com/skyscape-cloud-services/terraform@v0.9.2-0.20170609144644-7ece028a1747/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 // Even in the case an error is returned, the state may be returned and will 457 // potentially be partially updated. In addition to returning the resulting 458 // state, this context is updated with the latest state. 459 // 460 // If the state is required after an error, the caller should call 461 // Context.State, rather than rely on the return value. 462 // 463 // TODO: Apply and Refresh should either always return a state, or rely on the 464 // State() method. Currently the helper/resource testing framework relies 465 // on the absence of a returned state to determine if Destroy can be 466 // called, so that will need to be refactored before this can be changed. 467 func (c *Context) Apply() (*State, error) { 468 defer c.acquireRun("apply")() 469 470 // Copy our own state 471 c.state = c.state.DeepCopy() 472 473 // Build the graph. 474 graph, err := c.Graph(GraphTypeApply, nil) 475 if err != nil { 476 return nil, err 477 } 478 479 // Determine the operation 480 operation := walkApply 481 if c.destroy { 482 operation = walkDestroy 483 } 484 485 // Walk the graph 486 walker, err := c.walk(graph, graph, operation) 487 if len(walker.ValidationErrors) > 0 { 488 err = multierror.Append(err, walker.ValidationErrors...) 489 } 490 491 // Clean out any unused things 492 c.state.prune() 493 494 return c.state, err 495 } 496 497 // Plan generates an execution plan for the given context. 498 // 499 // The execution plan encapsulates the context and can be stored 500 // in order to reinstantiate a context later for Apply. 501 // 502 // Plan also updates the diff of this context to be the diff generated 503 // by the plan, so Apply can be called after. 504 func (c *Context) Plan() (*Plan, error) { 505 defer c.acquireRun("plan")() 506 507 p := &Plan{ 508 Module: c.module, 509 Vars: c.variables, 510 State: c.state, 511 Targets: c.targets, 512 } 513 514 var operation walkOperation 515 if c.destroy { 516 operation = walkPlanDestroy 517 } else { 518 // Set our state to be something temporary. We do this so that 519 // the plan can update a fake state so that variables work, then 520 // we replace it back with our old state. 521 old := c.state 522 if old == nil { 523 c.state = &State{} 524 c.state.init() 525 } else { 526 c.state = old.DeepCopy() 527 } 528 defer func() { 529 c.state = old 530 }() 531 532 operation = walkPlan 533 } 534 535 // Setup our diff 536 c.diffLock.Lock() 537 c.diff = new(Diff) 538 c.diff.init() 539 c.diffLock.Unlock() 540 541 // Build the graph. 542 graphType := GraphTypePlan 543 if c.destroy { 544 graphType = GraphTypePlanDestroy 545 } 546 graph, err := c.Graph(graphType, nil) 547 if err != nil { 548 return nil, err 549 } 550 551 // Do the walk 552 walker, err := c.walk(graph, graph, operation) 553 if err != nil { 554 return nil, err 555 } 556 p.Diff = c.diff 557 558 // If this is true, it means we're running unit tests. In this case, 559 // we perform a deep copy just to ensure that all context tests also 560 // test that a diff is copy-able. This will panic if it fails. This 561 // is enabled during unit tests. 562 // 563 // This should never be true during production usage, but even if it is, 564 // it can't do any real harm. 565 if contextTestDeepCopyOnPlan { 566 p.Diff.DeepCopy() 567 } 568 569 /* 570 // We don't do the reverification during the new destroy plan because 571 // it will use a different apply process. 572 if X_legacyGraph { 573 // Now that we have a diff, we can build the exact graph that Apply will use 574 // and catch any possible cycles during the Plan phase. 575 if _, err := c.Graph(GraphTypeLegacy, nil); err != nil { 576 return nil, err 577 } 578 } 579 */ 580 581 var errs error 582 if len(walker.ValidationErrors) > 0 { 583 errs = multierror.Append(errs, walker.ValidationErrors...) 584 } 585 return p, errs 586 } 587 588 // Refresh goes through all the resources in the state and refreshes them 589 // to their latest state. This will update the state that this context 590 // works with, along with returning it. 591 // 592 // Even in the case an error is returned, the state may be returned and 593 // will potentially be partially updated. 594 func (c *Context) Refresh() (*State, error) { 595 defer c.acquireRun("refresh")() 596 597 // Copy our own state 598 c.state = c.state.DeepCopy() 599 600 // Build the graph. 601 graph, err := c.Graph(GraphTypeRefresh, nil) 602 if err != nil { 603 return nil, err 604 } 605 606 // Do the walk 607 if _, err := c.walk(graph, graph, walkRefresh); err != nil { 608 return nil, err 609 } 610 611 // Clean out any unused things 612 c.state.prune() 613 614 return c.state, nil 615 } 616 617 // Stop stops the running task. 618 // 619 // Stop will block until the task completes. 620 func (c *Context) Stop() { 621 log.Printf("[WARN] terraform: Stop called, initiating interrupt sequence") 622 623 c.l.Lock() 624 defer c.l.Unlock() 625 626 // If we're running, then stop 627 if c.runContextCancel != nil { 628 log.Printf("[WARN] terraform: run context exists, stopping") 629 630 // Tell the hook we want to stop 631 c.sh.Stop() 632 633 // Stop the context 634 c.runContextCancel() 635 c.runContextCancel = nil 636 } 637 638 // Grab the condition var before we exit 639 if cond := c.runCond; cond != nil { 640 cond.Wait() 641 } 642 643 log.Printf("[WARN] terraform: stop complete") 644 } 645 646 // Validate validates the configuration and returns any warnings or errors. 647 func (c *Context) Validate() ([]string, []error) { 648 defer c.acquireRun("validate")() 649 650 var errs error 651 652 // Validate the configuration itself 653 if err := c.module.Validate(); err != nil { 654 errs = multierror.Append(errs, err) 655 } 656 657 // This only needs to be done for the root module, since inter-module 658 // variables are validated in the module tree. 659 if config := c.module.Config(); config != nil { 660 // Validate the user variables 661 if err := smcUserVariables(config, c.variables); len(err) > 0 { 662 errs = multierror.Append(errs, err...) 663 } 664 } 665 666 // If we have errors at this point, the graphing has no chance, 667 // so just bail early. 668 if errs != nil { 669 return nil, []error{errs} 670 } 671 672 // Build the graph so we can walk it and run Validate on nodes. 673 // We also validate the graph generated here, but this graph doesn't 674 // necessarily match the graph that Plan will generate, so we'll validate the 675 // graph again later after Planning. 676 graph, err := c.Graph(GraphTypeValidate, nil) 677 if err != nil { 678 return nil, []error{err} 679 } 680 681 // Walk 682 walker, err := c.walk(graph, graph, walkValidate) 683 if err != nil { 684 return nil, multierror.Append(errs, err).Errors 685 } 686 687 // Return the result 688 rerrs := multierror.Append(errs, walker.ValidationErrors...) 689 690 sort.Strings(walker.ValidationWarnings) 691 sort.Slice(rerrs.Errors, func(i, j int) bool { 692 return rerrs.Errors[i].Error() < rerrs.Errors[j].Error() 693 }) 694 695 return walker.ValidationWarnings, rerrs.Errors 696 } 697 698 // Module returns the module tree associated with this context. 699 func (c *Context) Module() *module.Tree { 700 return c.module 701 } 702 703 // Variables will return the mapping of variables that were defined 704 // for this Context. If Input was called, this mapping may be different 705 // than what was given. 706 func (c *Context) Variables() map[string]interface{} { 707 return c.variables 708 } 709 710 // SetVariable sets a variable after a context has already been built. 711 func (c *Context) SetVariable(k string, v interface{}) { 712 c.variables[k] = v 713 } 714 715 func (c *Context) acquireRun(phase string) func() { 716 // With the run lock held, grab the context lock to make changes 717 // to the run context. 718 c.l.Lock() 719 defer c.l.Unlock() 720 721 // Wait until we're no longer running 722 for c.runCond != nil { 723 c.runCond.Wait() 724 } 725 726 // Build our lock 727 c.runCond = sync.NewCond(&c.l) 728 729 // Setup debugging 730 dbug.SetPhase(phase) 731 732 // Create a new run context 733 c.runContext, c.runContextCancel = context.WithCancel(context.Background()) 734 735 // Reset the stop hook so we're not stopped 736 c.sh.Reset() 737 738 // Reset the shadow errors 739 c.shadowErr = nil 740 741 return c.releaseRun 742 } 743 744 func (c *Context) releaseRun() { 745 // Grab the context lock so that we can make modifications to fields 746 c.l.Lock() 747 defer c.l.Unlock() 748 749 // setting the phase to "INVALID" lets us easily detect if we have 750 // operations happening outside of a run, or we missed setting the proper 751 // phase 752 dbug.SetPhase("INVALID") 753 754 // End our run. We check if runContext is non-nil because it can be 755 // set to nil if it was cancelled via Stop() 756 if c.runContextCancel != nil { 757 c.runContextCancel() 758 } 759 760 // Unlock all waiting our condition 761 cond := c.runCond 762 c.runCond = nil 763 cond.Broadcast() 764 765 // Unset the context 766 c.runContext = nil 767 } 768 769 func (c *Context) walk( 770 graph, shadow *Graph, operation walkOperation) (*ContextGraphWalker, error) { 771 // Keep track of the "real" context which is the context that does 772 // the real work: talking to real providers, modifying real state, etc. 773 realCtx := c 774 775 // If we don't want shadowing, remove it 776 if !experiment.Enabled(experiment.X_shadow) { 777 shadow = nil 778 } 779 780 // Just log this so we can see it in a debug log 781 if !c.shadow { 782 log.Printf("[WARN] terraform: shadow graph disabled") 783 shadow = nil 784 } 785 786 // If we have a shadow graph, walk that as well 787 var shadowCtx *Context 788 var shadowCloser Shadow 789 if shadow != nil { 790 // Build the shadow context. In the process, override the real context 791 // with the one that is wrapped so that the shadow context can verify 792 // the results of the real. 793 realCtx, shadowCtx, shadowCloser = newShadowContext(c) 794 } 795 796 log.Printf("[DEBUG] Starting graph walk: %s", operation.String()) 797 798 walker := &ContextGraphWalker{ 799 Context: realCtx, 800 Operation: operation, 801 StopContext: c.runContext, 802 } 803 804 // Watch for a stop so we can call the provider Stop() API. 805 watchStop, watchWait := c.watchStop(walker) 806 807 // Walk the real graph, this will block until it completes 808 realErr := graph.Walk(walker) 809 810 // Close the channel so the watcher stops, and wait for it to return. 811 close(watchStop) 812 <-watchWait 813 814 // If we have a shadow graph and we interrupted the real graph, then 815 // we just close the shadow and never verify it. It is non-trivial to 816 // recreate the exact execution state up until an interruption so this 817 // isn't supported with shadows at the moment. 818 if shadowCloser != nil && c.sh.Stopped() { 819 // Ignore the error result, there is nothing we could care about 820 shadowCloser.CloseShadow() 821 822 // Set it to nil so we don't do anything 823 shadowCloser = nil 824 } 825 826 // If we have a shadow graph, wait for that to complete. 827 if shadowCloser != nil { 828 // Build the graph walker for the shadow. We also wrap this in 829 // a panicwrap so that panics are captured. For the shadow graph, 830 // we just want panics to be normal errors rather than to crash 831 // Terraform. 832 shadowWalker := GraphWalkerPanicwrap(&ContextGraphWalker{ 833 Context: shadowCtx, 834 Operation: operation, 835 }) 836 837 // Kick off the shadow walk. This will block on any operations 838 // on the real walk so it is fine to start first. 839 log.Printf("[INFO] Starting shadow graph walk: %s", operation.String()) 840 shadowCh := make(chan error) 841 go func() { 842 shadowCh <- shadow.Walk(shadowWalker) 843 }() 844 845 // Notify the shadow that we're done 846 if err := shadowCloser.CloseShadow(); err != nil { 847 c.shadowErr = multierror.Append(c.shadowErr, err) 848 } 849 850 // Wait for the walk to end 851 log.Printf("[DEBUG] Waiting for shadow graph to complete...") 852 shadowWalkErr := <-shadowCh 853 854 // Get any shadow errors 855 if err := shadowCloser.ShadowError(); err != nil { 856 c.shadowErr = multierror.Append(c.shadowErr, err) 857 } 858 859 // Verify the contexts (compare) 860 if err := shadowContextVerify(realCtx, shadowCtx); err != nil { 861 c.shadowErr = multierror.Append(c.shadowErr, err) 862 } 863 864 // At this point, if we're supposed to fail on error, then 865 // we PANIC. Some tests just verify that there is an error, 866 // so simply appending it to realErr and returning could hide 867 // shadow problems. 868 // 869 // This must be done BEFORE appending shadowWalkErr since the 870 // shadowWalkErr may include expected errors. 871 // 872 // We only do this if we don't have a real error. In the case of 873 // a real error, we can't guarantee what nodes were and weren't 874 // traversed in parallel scenarios so we can't guarantee no 875 // shadow errors. 876 if c.shadowErr != nil && contextFailOnShadowError && realErr == nil { 877 panic(multierror.Prefix(c.shadowErr, "shadow graph:")) 878 } 879 880 // Now, if we have a walk error, we append that through 881 if shadowWalkErr != nil { 882 c.shadowErr = multierror.Append(c.shadowErr, shadowWalkErr) 883 } 884 885 if c.shadowErr == nil { 886 log.Printf("[INFO] Shadow graph success!") 887 } else { 888 log.Printf("[ERROR] Shadow graph error: %s", c.shadowErr) 889 890 // If we're supposed to fail on shadow errors, then report it 891 if contextFailOnShadowError { 892 realErr = multierror.Append(realErr, multierror.Prefix( 893 c.shadowErr, "shadow graph:")) 894 } 895 } 896 } 897 898 return walker, realErr 899 } 900 901 // watchStop immediately returns a `stop` and a `wait` chan after dispatching 902 // the watchStop goroutine. This will watch the runContext for cancellation and 903 // stop the providers accordingly. When the watch is no longer needed, the 904 // `stop` chan should be closed before waiting on the `wait` chan. 905 // The `wait` chan is important, because without synchronizing with the end of 906 // the watchStop goroutine, the runContext may also be closed during the select 907 // incorrectly causing providers to be stopped. Even if the graph walk is done 908 // at that point, stopping a provider permanently cancels its StopContext which 909 // can cause later actions to fail. 910 func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan struct{}) { 911 stop := make(chan struct{}) 912 wait := make(chan struct{}) 913 914 // get the runContext cancellation channel now, because releaseRun will 915 // write to the runContext field. 916 done := c.runContext.Done() 917 918 go func() { 919 defer close(wait) 920 // Wait for a stop or completion 921 select { 922 case <-done: 923 // done means the context was canceled, so we need to try and stop 924 // providers. 925 case <-stop: 926 // our own stop channel was closed. 927 return 928 } 929 930 // If we're here, we're stopped, trigger the call. 931 932 { 933 // Copy the providers so that a misbehaved blocking Stop doesn't 934 // completely hang Terraform. 935 walker.providerLock.Lock() 936 ps := make([]ResourceProvider, 0, len(walker.providerCache)) 937 for _, p := range walker.providerCache { 938 ps = append(ps, p) 939 } 940 defer walker.providerLock.Unlock() 941 942 for _, p := range ps { 943 // We ignore the error for now since there isn't any reasonable 944 // action to take if there is an error here, since the stop is still 945 // advisory: Terraform will exit once the graph node completes. 946 p.Stop() 947 } 948 } 949 950 { 951 // Call stop on all the provisioners 952 walker.provisionerLock.Lock() 953 ps := make([]ResourceProvisioner, 0, len(walker.provisionerCache)) 954 for _, p := range walker.provisionerCache { 955 ps = append(ps, p) 956 } 957 defer walker.provisionerLock.Unlock() 958 959 for _, p := range ps { 960 // We ignore the error for now since there isn't any reasonable 961 // action to take if there is an error here, since the stop is still 962 // advisory: Terraform will exit once the graph node completes. 963 p.Stop() 964 } 965 } 966 }() 967 968 return stop, wait 969 } 970 971 // parseVariableAsHCL parses the value of a single variable as would have been specified 972 // on the command line via -var or in an environment variable named TF_VAR_x, where x is 973 // the name of the variable. In order to get around the restriction of HCL requiring a 974 // top level object, we prepend a sentinel key, decode the user-specified value as its 975 // value and pull the value back out of the resulting map. 976 func parseVariableAsHCL(name string, input string, targetType config.VariableType) (interface{}, error) { 977 // expecting a string so don't decode anything, just strip quotes 978 if targetType == config.VariableTypeString { 979 return strings.Trim(input, `"`), nil 980 } 981 982 // return empty types 983 if strings.TrimSpace(input) == "" { 984 switch targetType { 985 case config.VariableTypeList: 986 return []interface{}{}, nil 987 case config.VariableTypeMap: 988 return make(map[string]interface{}), nil 989 } 990 } 991 992 const sentinelValue = "SENTINEL_TERRAFORM_VAR_OVERRIDE_KEY" 993 inputWithSentinal := fmt.Sprintf("%s = %s", sentinelValue, input) 994 995 var decoded map[string]interface{} 996 err := hcl.Decode(&decoded, inputWithSentinal) 997 if err != nil { 998 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL: %s", name, input, err) 999 } 1000 1001 if len(decoded) != 1 { 1002 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. Only one value may be specified.", name, input) 1003 } 1004 1005 parsedValue, ok := decoded[sentinelValue] 1006 if !ok { 1007 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) 1008 } 1009 1010 switch targetType { 1011 case config.VariableTypeList: 1012 return parsedValue, nil 1013 case config.VariableTypeMap: 1014 if list, ok := parsedValue.([]map[string]interface{}); ok { 1015 return list[0], nil 1016 } 1017 1018 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) 1019 default: 1020 panic(fmt.Errorf("unknown type %s", targetType.Printable())) 1021 } 1022 }