github.com/nbering/terraform@v0.8.5-0.20170113232247-453f670684b5/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 GraphTypePlan: 220 return (&PlanGraphBuilder{ 221 Module: c.module, 222 State: c.state, 223 Providers: c.components.ResourceProviders(), 224 Targets: c.targets, 225 Validate: opts.Validate, 226 }).Build(RootModulePath) 227 228 case GraphTypePlanDestroy: 229 return (&DestroyPlanGraphBuilder{ 230 Module: c.module, 231 State: c.state, 232 Targets: c.targets, 233 Validate: opts.Validate, 234 }).Build(RootModulePath) 235 236 case GraphTypeLegacy: 237 return c.graphBuilder(opts).Build(RootModulePath) 238 } 239 240 return nil, fmt.Errorf("unknown graph type: %s", typ) 241 } 242 243 // GraphBuilder returns the GraphBuilder that will be used to create 244 // the graphs for this context. 245 func (c *Context) graphBuilder(g *ContextGraphOpts) GraphBuilder { 246 return &BuiltinGraphBuilder{ 247 Root: c.module, 248 Diff: c.diff, 249 Providers: c.components.ResourceProviders(), 250 Provisioners: c.components.ResourceProvisioners(), 251 State: c.state, 252 Targets: c.targets, 253 Destroy: c.destroy, 254 Validate: g.Validate, 255 Verbose: g.Verbose, 256 } 257 } 258 259 // ShadowError returns any errors caught during a shadow operation. 260 // 261 // A shadow operation is an operation run in parallel to a real operation 262 // that performs the same tasks using new logic on copied state. The results 263 // are compared to ensure that the new logic works the same as the old logic. 264 // The shadow never affects the real operation or return values. 265 // 266 // The result of the shadow operation are only available through this function 267 // call after a real operation is complete. 268 // 269 // For API consumers of Context, you can safely ignore this function 270 // completely if you have no interest in helping report experimental feature 271 // errors to Terraform maintainers. Otherwise, please call this function 272 // after every operation and report this to the user. 273 // 274 // IMPORTANT: Shadow errors are _never_ critical: they _never_ affect 275 // the real state or result of a real operation. They are purely informational 276 // to assist in future Terraform versions being more stable. Please message 277 // this effectively to the end user. 278 // 279 // This must be called only when no other operation is running (refresh, 280 // plan, etc.). The result can be used in parallel to any other operation 281 // running. 282 func (c *Context) ShadowError() error { 283 return c.shadowErr 284 } 285 286 // Interpolater returns an Interpolater built on a copy of the state 287 // that can be used to test interpolation values. 288 func (c *Context) Interpolater() *Interpolater { 289 var varLock sync.Mutex 290 var stateLock sync.RWMutex 291 return &Interpolater{ 292 Operation: walkApply, 293 Module: c.module, 294 State: c.state.DeepCopy(), 295 StateLock: &stateLock, 296 VariableValues: c.variables, 297 VariableValuesLock: &varLock, 298 } 299 } 300 301 // Input asks for input to fill variables and provider configurations. 302 // This modifies the configuration in-place, so asking for Input twice 303 // may result in different UI output showing different current values. 304 func (c *Context) Input(mode InputMode) error { 305 v := c.acquireRun("input") 306 defer c.releaseRun(v) 307 308 if mode&InputModeVar != 0 { 309 // Walk the variables first for the root module. We walk them in 310 // alphabetical order for UX reasons. 311 rootConf := c.module.Config() 312 names := make([]string, len(rootConf.Variables)) 313 m := make(map[string]*config.Variable) 314 for i, v := range rootConf.Variables { 315 names[i] = v.Name 316 m[v.Name] = v 317 } 318 sort.Strings(names) 319 for _, n := range names { 320 // If we only care about unset variables, then if the variable 321 // is set, continue on. 322 if mode&InputModeVarUnset != 0 { 323 if _, ok := c.variables[n]; ok { 324 continue 325 } 326 } 327 328 var valueType config.VariableType 329 330 v := m[n] 331 switch valueType = v.Type(); valueType { 332 case config.VariableTypeUnknown: 333 continue 334 case config.VariableTypeMap: 335 // OK 336 case config.VariableTypeList: 337 // OK 338 case config.VariableTypeString: 339 // OK 340 default: 341 panic(fmt.Sprintf("Unknown variable type: %#v", v.Type())) 342 } 343 344 // If the variable is not already set, and the variable defines a 345 // default, use that for the value. 346 if _, ok := c.variables[n]; !ok { 347 if v.Default != nil { 348 c.variables[n] = v.Default.(string) 349 continue 350 } 351 } 352 353 // this should only happen during tests 354 if c.uiInput == nil { 355 log.Println("[WARN] Content.uiInput is nil") 356 continue 357 } 358 359 // Ask the user for a value for this variable 360 var value string 361 retry := 0 362 for { 363 var err error 364 value, err = c.uiInput.Input(&InputOpts{ 365 Id: fmt.Sprintf("var.%s", n), 366 Query: fmt.Sprintf("var.%s", n), 367 Description: v.Description, 368 }) 369 if err != nil { 370 return fmt.Errorf( 371 "Error asking for %s: %s", n, err) 372 } 373 374 if value == "" && v.Required() { 375 // Redo if it is required, but abort if we keep getting 376 // blank entries 377 if retry > 2 { 378 return fmt.Errorf("missing required value for %q", n) 379 } 380 retry++ 381 continue 382 } 383 384 break 385 } 386 387 // no value provided, so don't set the variable at all 388 if value == "" { 389 continue 390 } 391 392 decoded, err := parseVariableAsHCL(n, value, valueType) 393 if err != nil { 394 return err 395 } 396 397 if decoded != nil { 398 c.variables[n] = decoded 399 } 400 } 401 } 402 403 if mode&InputModeProvider != 0 { 404 // Build the graph 405 graph, err := c.Graph(GraphTypeLegacy, nil) 406 if err != nil { 407 return err 408 } 409 410 // Do the walk 411 if _, err := c.walk(graph, nil, walkInput); err != nil { 412 return err 413 } 414 } 415 416 return nil 417 } 418 419 // Apply applies the changes represented by this context and returns 420 // the resulting state. 421 // 422 // In addition to returning the resulting state, this context is updated 423 // with the latest state. 424 func (c *Context) Apply() (*State, error) { 425 v := c.acquireRun("apply") 426 defer c.releaseRun(v) 427 428 // Copy our own state 429 c.state = c.state.DeepCopy() 430 431 // Enable the new graph by default 432 X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph) 433 434 // Build the graph. 435 graphType := GraphTypeLegacy 436 if !X_legacyGraph { 437 graphType = GraphTypeApply 438 } 439 graph, err := c.Graph(graphType, nil) 440 if err != nil { 441 return nil, err 442 } 443 444 // Determine the operation 445 operation := walkApply 446 if c.destroy { 447 operation = walkDestroy 448 } 449 450 // Walk the graph 451 walker, err := c.walk(graph, graph, operation) 452 if len(walker.ValidationErrors) > 0 { 453 err = multierror.Append(err, walker.ValidationErrors...) 454 } 455 456 // Clean out any unused things 457 c.state.prune() 458 459 return c.state, err 460 } 461 462 // Plan generates an execution plan for the given context. 463 // 464 // The execution plan encapsulates the context and can be stored 465 // in order to reinstantiate a context later for Apply. 466 // 467 // Plan also updates the diff of this context to be the diff generated 468 // by the plan, so Apply can be called after. 469 func (c *Context) Plan() (*Plan, error) { 470 v := c.acquireRun("plan") 471 defer c.releaseRun(v) 472 473 p := &Plan{ 474 Module: c.module, 475 Vars: c.variables, 476 State: c.state, 477 Targets: c.targets, 478 } 479 480 var operation walkOperation 481 if c.destroy { 482 operation = walkPlanDestroy 483 } else { 484 // Set our state to be something temporary. We do this so that 485 // the plan can update a fake state so that variables work, then 486 // we replace it back with our old state. 487 old := c.state 488 if old == nil { 489 c.state = &State{} 490 c.state.init() 491 } else { 492 c.state = old.DeepCopy() 493 } 494 defer func() { 495 c.state = old 496 }() 497 498 operation = walkPlan 499 } 500 501 // Setup our diff 502 c.diffLock.Lock() 503 c.diff = new(Diff) 504 c.diff.init() 505 c.diffLock.Unlock() 506 507 // Used throughout below 508 X_legacyGraph := experiment.Enabled(experiment.X_legacyGraph) 509 510 // Build the graph. 511 graphType := GraphTypeLegacy 512 if !X_legacyGraph { 513 if c.destroy { 514 graphType = GraphTypePlanDestroy 515 } else { 516 graphType = GraphTypePlan 517 } 518 } 519 graph, err := c.Graph(graphType, nil) 520 if err != nil { 521 return nil, err 522 } 523 524 // Do the walk 525 walker, err := c.walk(graph, graph, operation) 526 if err != nil { 527 return nil, err 528 } 529 p.Diff = c.diff 530 531 // If this is true, it means we're running unit tests. In this case, 532 // we perform a deep copy just to ensure that all context tests also 533 // test that a diff is copy-able. This will panic if it fails. This 534 // is enabled during unit tests. 535 // 536 // This should never be true during production usage, but even if it is, 537 // it can't do any real harm. 538 if contextTestDeepCopyOnPlan { 539 p.Diff.DeepCopy() 540 } 541 542 // We don't do the reverification during the new destroy plan because 543 // it will use a different apply process. 544 if X_legacyGraph { 545 // Now that we have a diff, we can build the exact graph that Apply will use 546 // and catch any possible cycles during the Plan phase. 547 if _, err := c.Graph(GraphTypeLegacy, nil); err != nil { 548 return nil, err 549 } 550 } 551 552 var errs error 553 if len(walker.ValidationErrors) > 0 { 554 errs = multierror.Append(errs, walker.ValidationErrors...) 555 } 556 return p, errs 557 } 558 559 // Refresh goes through all the resources in the state and refreshes them 560 // to their latest state. This will update the state that this context 561 // works with, along with returning it. 562 // 563 // Even in the case an error is returned, the state will be returned and 564 // will potentially be partially updated. 565 func (c *Context) Refresh() (*State, error) { 566 v := c.acquireRun("refresh") 567 defer c.releaseRun(v) 568 569 // Copy our own state 570 c.state = c.state.DeepCopy() 571 572 // Build the graph 573 graph, err := c.Graph(GraphTypeLegacy, nil) 574 if err != nil { 575 return nil, err 576 } 577 578 // Do the walk 579 if _, err := c.walk(graph, graph, walkRefresh); err != nil { 580 return nil, err 581 } 582 583 // Clean out any unused things 584 c.state.prune() 585 586 return c.state, nil 587 } 588 589 // Stop stops the running task. 590 // 591 // Stop will block until the task completes. 592 func (c *Context) Stop() { 593 c.l.Lock() 594 ch := c.runCh 595 596 // If we aren't running, then just return 597 if ch == nil { 598 c.l.Unlock() 599 return 600 } 601 602 // Tell the hook we want to stop 603 c.sh.Stop() 604 605 // Close the stop channel 606 close(c.stopCh) 607 608 // Wait for us to stop 609 c.l.Unlock() 610 <-ch 611 } 612 613 // Validate validates the configuration and returns any warnings or errors. 614 func (c *Context) Validate() ([]string, []error) { 615 v := c.acquireRun("validate") 616 defer c.releaseRun(v) 617 618 var errs error 619 620 // Validate the configuration itself 621 if err := c.module.Validate(); err != nil { 622 errs = multierror.Append(errs, err) 623 } 624 625 // This only needs to be done for the root module, since inter-module 626 // variables are validated in the module tree. 627 if config := c.module.Config(); config != nil { 628 // Validate the user variables 629 if err := smcUserVariables(config, c.variables); len(err) > 0 { 630 errs = multierror.Append(errs, err...) 631 } 632 } 633 634 // If we have errors at this point, the graphing has no chance, 635 // so just bail early. 636 if errs != nil { 637 return nil, []error{errs} 638 } 639 640 // Build the graph so we can walk it and run Validate on nodes. 641 // We also validate the graph generated here, but this graph doesn't 642 // necessarily match the graph that Plan will generate, so we'll validate the 643 // graph again later after Planning. 644 graph, err := c.Graph(GraphTypeLegacy, nil) 645 if err != nil { 646 return nil, []error{err} 647 } 648 649 // Walk 650 walker, err := c.walk(graph, graph, walkValidate) 651 if err != nil { 652 return nil, multierror.Append(errs, err).Errors 653 } 654 655 // Return the result 656 rerrs := multierror.Append(errs, walker.ValidationErrors...) 657 return walker.ValidationWarnings, rerrs.Errors 658 } 659 660 // Module returns the module tree associated with this context. 661 func (c *Context) Module() *module.Tree { 662 return c.module 663 } 664 665 // Variables will return the mapping of variables that were defined 666 // for this Context. If Input was called, this mapping may be different 667 // than what was given. 668 func (c *Context) Variables() map[string]interface{} { 669 return c.variables 670 } 671 672 // SetVariable sets a variable after a context has already been built. 673 func (c *Context) SetVariable(k string, v interface{}) { 674 c.variables[k] = v 675 } 676 677 func (c *Context) acquireRun(phase string) chan<- struct{} { 678 c.l.Lock() 679 defer c.l.Unlock() 680 681 dbug.SetPhase(phase) 682 683 // Wait for no channel to exist 684 for c.runCh != nil { 685 c.l.Unlock() 686 ch := c.runCh 687 <-ch 688 c.l.Lock() 689 } 690 691 // Create the new channel 692 ch := make(chan struct{}) 693 c.runCh = ch 694 695 // Reset the stop channel so we can watch that 696 c.stopCh = make(chan struct{}) 697 698 // Reset the stop hook so we're not stopped 699 c.sh.Reset() 700 701 // Reset the shadow errors 702 c.shadowErr = nil 703 704 return ch 705 } 706 707 func (c *Context) releaseRun(ch chan<- struct{}) { 708 c.l.Lock() 709 defer c.l.Unlock() 710 711 // setting the phase to "INVALID" lets us easily detect if we have 712 // operations happening outside of a run, or we missed setting the proper 713 // phase 714 dbug.SetPhase("INVALID") 715 716 close(ch) 717 c.runCh = nil 718 c.stopCh = nil 719 } 720 721 func (c *Context) walk( 722 graph, shadow *Graph, operation walkOperation) (*ContextGraphWalker, error) { 723 // Keep track of the "real" context which is the context that does 724 // the real work: talking to real providers, modifying real state, etc. 725 realCtx := c 726 727 // If we don't want shadowing, remove it 728 if !experiment.Enabled(experiment.X_shadow) { 729 shadow = nil 730 } 731 732 // If we have a shadow graph, walk that as well 733 var shadowCtx *Context 734 var shadowCloser Shadow 735 if c.shadow && shadow != nil { 736 // Build the shadow context. In the process, override the real context 737 // with the one that is wrapped so that the shadow context can verify 738 // the results of the real. 739 realCtx, shadowCtx, shadowCloser = newShadowContext(c) 740 } 741 742 // Just log this so we can see it in a debug log 743 if !c.shadow { 744 log.Printf("[WARN] terraform: shadow graph disabled") 745 } 746 747 log.Printf("[DEBUG] Starting graph walk: %s", operation.String()) 748 749 walker := &ContextGraphWalker{ 750 Context: realCtx, 751 Operation: operation, 752 } 753 754 // Watch for a stop so we can call the provider Stop() API. 755 doneCh := make(chan struct{}) 756 go c.watchStop(walker, c.stopCh, doneCh) 757 758 // Walk the real graph, this will block until it completes 759 realErr := graph.Walk(walker) 760 761 // Close the done channel so the watcher stops 762 close(doneCh) 763 764 // If we have a shadow graph and we interrupted the real graph, then 765 // we just close the shadow and never verify it. It is non-trivial to 766 // recreate the exact execution state up until an interruption so this 767 // isn't supported with shadows at the moment. 768 if shadowCloser != nil && c.sh.Stopped() { 769 // Ignore the error result, there is nothing we could care about 770 shadowCloser.CloseShadow() 771 772 // Set it to nil so we don't do anything 773 shadowCloser = nil 774 } 775 776 // If we have a shadow graph, wait for that to complete. 777 if shadowCloser != nil { 778 // Build the graph walker for the shadow. We also wrap this in 779 // a panicwrap so that panics are captured. For the shadow graph, 780 // we just want panics to be normal errors rather than to crash 781 // Terraform. 782 shadowWalker := GraphWalkerPanicwrap(&ContextGraphWalker{ 783 Context: shadowCtx, 784 Operation: operation, 785 }) 786 787 // Kick off the shadow walk. This will block on any operations 788 // on the real walk so it is fine to start first. 789 log.Printf("[INFO] Starting shadow graph walk: %s", operation.String()) 790 shadowCh := make(chan error) 791 go func() { 792 shadowCh <- shadow.Walk(shadowWalker) 793 }() 794 795 // Notify the shadow that we're done 796 if err := shadowCloser.CloseShadow(); err != nil { 797 c.shadowErr = multierror.Append(c.shadowErr, err) 798 } 799 800 // Wait for the walk to end 801 log.Printf("[DEBUG] Waiting for shadow graph to complete...") 802 shadowWalkErr := <-shadowCh 803 804 // Get any shadow errors 805 if err := shadowCloser.ShadowError(); err != nil { 806 c.shadowErr = multierror.Append(c.shadowErr, err) 807 } 808 809 // Verify the contexts (compare) 810 if err := shadowContextVerify(realCtx, shadowCtx); err != nil { 811 c.shadowErr = multierror.Append(c.shadowErr, err) 812 } 813 814 // At this point, if we're supposed to fail on error, then 815 // we PANIC. Some tests just verify that there is an error, 816 // so simply appending it to realErr and returning could hide 817 // shadow problems. 818 // 819 // This must be done BEFORE appending shadowWalkErr since the 820 // shadowWalkErr may include expected errors. 821 // 822 // We only do this if we don't have a real error. In the case of 823 // a real error, we can't guarantee what nodes were and weren't 824 // traversed in parallel scenarios so we can't guarantee no 825 // shadow errors. 826 if c.shadowErr != nil && contextFailOnShadowError && realErr == nil { 827 panic(multierror.Prefix(c.shadowErr, "shadow graph:")) 828 } 829 830 // Now, if we have a walk error, we append that through 831 if shadowWalkErr != nil { 832 c.shadowErr = multierror.Append(c.shadowErr, shadowWalkErr) 833 } 834 835 if c.shadowErr == nil { 836 log.Printf("[INFO] Shadow graph success!") 837 } else { 838 log.Printf("[ERROR] Shadow graph error: %s", c.shadowErr) 839 840 // If we're supposed to fail on shadow errors, then report it 841 if contextFailOnShadowError { 842 realErr = multierror.Append(realErr, multierror.Prefix( 843 c.shadowErr, "shadow graph:")) 844 } 845 } 846 } 847 848 return walker, realErr 849 } 850 851 func (c *Context) watchStop(walker *ContextGraphWalker, stopCh, doneCh <-chan struct{}) { 852 // Wait for a stop or completion 853 select { 854 case <-stopCh: 855 // Stop was triggered. Fall out of the select 856 case <-doneCh: 857 // Done, just exit completely 858 return 859 } 860 861 // If we're here, we're stopped, trigger the call. 862 863 // Copy the providers so that a misbehaved blocking Stop doesn't 864 // completely hang Terraform. 865 walker.providerLock.Lock() 866 ps := make([]ResourceProvider, 0, len(walker.providerCache)) 867 for _, p := range walker.providerCache { 868 ps = append(ps, p) 869 } 870 defer walker.providerLock.Unlock() 871 872 for _, p := range ps { 873 // We ignore the error for now since there isn't any reasonable 874 // action to take if there is an error here, since the stop is still 875 // advisory: Terraform will exit once the graph node completes. 876 p.Stop() 877 } 878 } 879 880 // parseVariableAsHCL parses the value of a single variable as would have been specified 881 // on the command line via -var or in an environment variable named TF_VAR_x, where x is 882 // the name of the variable. In order to get around the restriction of HCL requiring a 883 // top level object, we prepend a sentinel key, decode the user-specified value as its 884 // value and pull the value back out of the resulting map. 885 func parseVariableAsHCL(name string, input string, targetType config.VariableType) (interface{}, error) { 886 // expecting a string so don't decode anything, just strip quotes 887 if targetType == config.VariableTypeString { 888 return strings.Trim(input, `"`), nil 889 } 890 891 // return empty types 892 if strings.TrimSpace(input) == "" { 893 switch targetType { 894 case config.VariableTypeList: 895 return []interface{}{}, nil 896 case config.VariableTypeMap: 897 return make(map[string]interface{}), nil 898 } 899 } 900 901 const sentinelValue = "SENTINEL_TERRAFORM_VAR_OVERRIDE_KEY" 902 inputWithSentinal := fmt.Sprintf("%s = %s", sentinelValue, input) 903 904 var decoded map[string]interface{} 905 err := hcl.Decode(&decoded, inputWithSentinal) 906 if err != nil { 907 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL: %s", name, input, err) 908 } 909 910 if len(decoded) != 1 { 911 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. Only one value may be specified.", name, input) 912 } 913 914 parsedValue, ok := decoded[sentinelValue] 915 if !ok { 916 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) 917 } 918 919 switch targetType { 920 case config.VariableTypeList: 921 return parsedValue, nil 922 case config.VariableTypeMap: 923 if list, ok := parsedValue.([]map[string]interface{}); ok { 924 return list[0], nil 925 } 926 927 return nil, fmt.Errorf("Cannot parse value for variable %s (%q) as valid HCL. One value must be specified.", name, input) 928 default: 929 panic(fmt.Errorf("unknown type %s", targetType.Printable())) 930 } 931 }