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