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