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