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