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