github.com/hashicorp/terraform-plugin-sdk@v1.17.2/terraform/context.go (about)

     1  package terraform
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"log"
     8  	"sync"
     9  
    10  	"github.com/hashicorp/terraform-plugin-sdk/internal/addrs"
    11  	"github.com/hashicorp/terraform-plugin-sdk/internal/configs"
    12  	"github.com/hashicorp/terraform-plugin-sdk/internal/lang"
    13  	"github.com/hashicorp/terraform-plugin-sdk/internal/plans"
    14  	"github.com/hashicorp/terraform-plugin-sdk/internal/providers"
    15  	"github.com/hashicorp/terraform-plugin-sdk/internal/provisioners"
    16  	"github.com/hashicorp/terraform-plugin-sdk/internal/states"
    17  	"github.com/hashicorp/terraform-plugin-sdk/internal/states/statefile"
    18  	"github.com/hashicorp/terraform-plugin-sdk/internal/tfdiags"
    19  	"github.com/zclconf/go-cty/cty"
    20  )
    21  
    22  // InputMode defines what sort of input will be asked for when Input
    23  // is called on Context.
    24  type InputMode byte
    25  
    26  const (
    27  	// InputModeVar asks for all variables
    28  	InputModeVar InputMode = 1 << iota
    29  
    30  	// InputModeVarUnset asks for variables which are not set yet.
    31  	// InputModeVar must be set for this to have an effect.
    32  	InputModeVarUnset
    33  
    34  	// InputModeProvider asks for provider variables
    35  	InputModeProvider
    36  
    37  	// InputModeStd is the standard operating mode and asks for both variables
    38  	// and providers.
    39  	InputModeStd = InputModeVar | InputModeProvider
    40  )
    41  
    42  // ContextOpts are the user-configurable options to create a context with
    43  // NewContext.
    44  type ContextOpts struct {
    45  	Config    *configs.Config
    46  	Changes   *plans.Changes
    47  	State     *states.State
    48  	Targets   []addrs.Targetable
    49  	Variables InputValues
    50  	Meta      *ContextMeta
    51  	Destroy   bool
    52  
    53  	Hooks            []Hook
    54  	Parallelism      int
    55  	ProviderResolver providers.Resolver
    56  	Provisioners     map[string]ProvisionerFactory
    57  
    58  	// If non-nil, will apply as additional constraints on the provider
    59  	// plugins that will be requested from the provider resolver.
    60  	ProviderSHA256s    map[string][]byte
    61  	SkipProviderVerify bool
    62  
    63  	UIInput UIInput
    64  }
    65  
    66  // ContextMeta is metadata about the running context. This is information
    67  // that this package or structure cannot determine on its own but exposes
    68  // into Terraform in various ways. This must be provided by the Context
    69  // initializer.
    70  type ContextMeta struct {
    71  	Env string // Env is the state environment
    72  }
    73  
    74  // Context represents all the context that Terraform needs in order to
    75  // perform operations on infrastructure. This structure is built using
    76  // NewContext.
    77  type Context struct {
    78  	config    *configs.Config
    79  	changes   *plans.Changes
    80  	state     *states.State
    81  	targets   []addrs.Targetable
    82  	variables InputValues
    83  	meta      *ContextMeta
    84  	destroy   bool
    85  
    86  	hooks      []Hook
    87  	components contextComponentFactory
    88  	schemas    *Schemas
    89  	sh         *stopHook
    90  	uiInput    UIInput
    91  
    92  	l                   sync.Mutex // Lock acquired during any task
    93  	parallelSem         Semaphore
    94  	providerInputConfig map[string]map[string]cty.Value
    95  	providerSHA256s     map[string][]byte
    96  	runCond             *sync.Cond
    97  	runContext          context.Context
    98  	runContextCancel    context.CancelFunc
    99  	shadowErr           error
   100  }
   101  
   102  // (additional methods on Context can be found in context_*.go files.)
   103  
   104  // NewContext creates a new Context structure.
   105  //
   106  // Once a Context is created, the caller must not access or mutate any of
   107  // the objects referenced (directly or indirectly) by the ContextOpts fields.
   108  //
   109  // If the returned diagnostics contains errors then the resulting context is
   110  // invalid and must not be used.
   111  func NewContext(opts *ContextOpts) (*Context, tfdiags.Diagnostics) {
   112  	log.Printf("[TRACE] terraform.NewContext: starting")
   113  	diags := CheckCoreVersionRequirements(opts.Config)
   114  	// If version constraints are not met then we'll bail early since otherwise
   115  	// we're likely to just see a bunch of other errors related to
   116  	// incompatibilities, which could be overwhelming for the user.
   117  	if diags.HasErrors() {
   118  		return nil, diags
   119  	}
   120  
   121  	// Copy all the hooks and add our stop hook. We don't append directly
   122  	// to the Config so that we're not modifying that in-place.
   123  	sh := new(stopHook)
   124  	hooks := make([]Hook, len(opts.Hooks)+1)
   125  	copy(hooks, opts.Hooks)
   126  	hooks[len(opts.Hooks)] = sh
   127  
   128  	state := opts.State
   129  	if state == nil {
   130  		state = states.NewState()
   131  	}
   132  
   133  	// Determine parallelism, default to 10. We do this both to limit
   134  	// CPU pressure but also to have an extra guard against rate throttling
   135  	// from providers.
   136  	par := opts.Parallelism
   137  	if par == 0 {
   138  		par = 10
   139  	}
   140  
   141  	// Set up the variables in the following sequence:
   142  	//    0 - Take default values from the configuration
   143  	//    1 - Take values from TF_VAR_x environment variables
   144  	//    2 - Take values specified in -var flags, overriding values
   145  	//        set by environment variables if necessary. This includes
   146  	//        values taken from -var-file in addition.
   147  	var variables InputValues
   148  	if opts.Config != nil {
   149  		// Default variables from the configuration seed our map.
   150  		variables = DefaultVariableValues(opts.Config.Module.Variables)
   151  	}
   152  	// Variables provided by the caller (from CLI, environment, etc) can
   153  	// override the defaults.
   154  	variables = variables.Override(opts.Variables)
   155  
   156  	// Bind available provider plugins to the constraints in config
   157  	var providerFactories map[string]providers.Factory
   158  	if opts.ProviderResolver != nil {
   159  		deps := ConfigTreeDependencies(opts.Config, state)
   160  		reqd := deps.AllPluginRequirements()
   161  		if opts.ProviderSHA256s != nil && !opts.SkipProviderVerify {
   162  			reqd.LockExecutables(opts.ProviderSHA256s)
   163  		}
   164  		log.Printf("[TRACE] terraform.NewContext: resolving provider version selections")
   165  
   166  		var providerDiags tfdiags.Diagnostics
   167  		providerFactories, providerDiags = resourceProviderFactories(opts.ProviderResolver, reqd)
   168  		diags = diags.Append(providerDiags)
   169  
   170  		if diags.HasErrors() {
   171  			return nil, diags
   172  		}
   173  	} else {
   174  		providerFactories = make(map[string]providers.Factory)
   175  	}
   176  
   177  	components := &basicComponentFactory{
   178  		providers:    providerFactories,
   179  		provisioners: opts.Provisioners,
   180  	}
   181  
   182  	log.Printf("[TRACE] terraform.NewContext: loading provider schemas")
   183  	schemas, err := LoadSchemas(opts.Config, opts.State, components)
   184  	if err != nil {
   185  		diags = diags.Append(err)
   186  		return nil, diags
   187  	}
   188  
   189  	changes := opts.Changes
   190  	if changes == nil {
   191  		changes = plans.NewChanges()
   192  	}
   193  
   194  	config := opts.Config
   195  	if config == nil {
   196  		config = configs.NewEmptyConfig()
   197  	}
   198  
   199  	log.Printf("[TRACE] terraform.NewContext: complete")
   200  
   201  	return &Context{
   202  		components: components,
   203  		schemas:    schemas,
   204  		destroy:    opts.Destroy,
   205  		changes:    changes,
   206  		hooks:      hooks,
   207  		meta:       opts.Meta,
   208  		config:     config,
   209  		state:      state,
   210  		targets:    opts.Targets,
   211  		uiInput:    opts.UIInput,
   212  		variables:  variables,
   213  
   214  		parallelSem:         NewSemaphore(par),
   215  		providerInputConfig: make(map[string]map[string]cty.Value),
   216  		providerSHA256s:     opts.ProviderSHA256s,
   217  		sh:                  sh,
   218  	}, nil
   219  }
   220  
   221  func (c *Context) Schemas() *Schemas {
   222  	return c.schemas
   223  }
   224  
   225  type ContextGraphOpts struct {
   226  	// If true, validates the graph structure (checks for cycles).
   227  	Validate bool
   228  
   229  	// Legacy graphs only: won't prune the graph
   230  	Verbose bool
   231  }
   232  
   233  // Graph returns the graph used for the given operation type.
   234  //
   235  // The most extensive or complex graph type is GraphTypePlan.
   236  func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags.Diagnostics) {
   237  	if opts == nil {
   238  		opts = &ContextGraphOpts{Validate: true}
   239  	}
   240  
   241  	log.Printf("[INFO] terraform: building graph: %s", typ)
   242  	switch typ {
   243  	case GraphTypeApply:
   244  		return (&ApplyGraphBuilder{
   245  			Config:     c.config,
   246  			Changes:    c.changes,
   247  			State:      c.state,
   248  			Components: c.components,
   249  			Schemas:    c.schemas,
   250  			Targets:    c.targets,
   251  			Destroy:    c.destroy,
   252  			Validate:   opts.Validate,
   253  		}).Build(addrs.RootModuleInstance)
   254  
   255  	case GraphTypeValidate:
   256  		// The validate graph is just a slightly modified plan graph
   257  		fallthrough
   258  	case GraphTypePlan:
   259  		// Create the plan graph builder
   260  		p := &PlanGraphBuilder{
   261  			Config:     c.config,
   262  			State:      c.state,
   263  			Components: c.components,
   264  			Schemas:    c.schemas,
   265  			Targets:    c.targets,
   266  			Validate:   opts.Validate,
   267  		}
   268  
   269  		// Some special cases for other graph types shared with plan currently
   270  		var b GraphBuilder = p
   271  		switch typ {
   272  		case GraphTypeValidate:
   273  			b = ValidateGraphBuilder(p)
   274  		}
   275  
   276  		return b.Build(addrs.RootModuleInstance)
   277  
   278  	case GraphTypePlanDestroy:
   279  		return (&DestroyPlanGraphBuilder{
   280  			Config:     c.config,
   281  			State:      c.state,
   282  			Components: c.components,
   283  			Schemas:    c.schemas,
   284  			Targets:    c.targets,
   285  			Validate:   opts.Validate,
   286  		}).Build(addrs.RootModuleInstance)
   287  
   288  	case GraphTypeRefresh:
   289  		return (&RefreshGraphBuilder{
   290  			Config:     c.config,
   291  			State:      c.state,
   292  			Components: c.components,
   293  			Schemas:    c.schemas,
   294  			Targets:    c.targets,
   295  			Validate:   opts.Validate,
   296  		}).Build(addrs.RootModuleInstance)
   297  
   298  	case GraphTypeEval:
   299  		return (&EvalGraphBuilder{
   300  			Config:     c.config,
   301  			State:      c.state,
   302  			Components: c.components,
   303  			Schemas:    c.schemas,
   304  		}).Build(addrs.RootModuleInstance)
   305  
   306  	default:
   307  		// Should never happen, because the above is exhaustive for all graph types.
   308  		panic(fmt.Errorf("unsupported graph type %s", typ))
   309  	}
   310  }
   311  
   312  // ShadowError returns any errors caught during a shadow operation.
   313  //
   314  // A shadow operation is an operation run in parallel to a real operation
   315  // that performs the same tasks using new logic on copied state. The results
   316  // are compared to ensure that the new logic works the same as the old logic.
   317  // The shadow never affects the real operation or return values.
   318  //
   319  // The result of the shadow operation are only available through this function
   320  // call after a real operation is complete.
   321  //
   322  // For API consumers of Context, you can safely ignore this function
   323  // completely if you have no interest in helping report experimental feature
   324  // errors to Terraform maintainers. Otherwise, please call this function
   325  // after every operation and report this to the user.
   326  //
   327  // IMPORTANT: Shadow errors are _never_ critical: they _never_ affect
   328  // the real state or result of a real operation. They are purely informational
   329  // to assist in future Terraform versions being more stable. Please message
   330  // this effectively to the end user.
   331  //
   332  // This must be called only when no other operation is running (refresh,
   333  // plan, etc.). The result can be used in parallel to any other operation
   334  // running.
   335  func (c *Context) ShadowError() error {
   336  	return c.shadowErr
   337  }
   338  
   339  // State returns a copy of the current state associated with this context.
   340  //
   341  // This cannot safely be called in parallel with any other Context function.
   342  func (c *Context) State() *states.State {
   343  	return c.state.DeepCopy()
   344  }
   345  
   346  // Eval produces a scope in which expressions can be evaluated for
   347  // the given module path.
   348  //
   349  // This method must first evaluate any ephemeral values (input variables, local
   350  // values, and output values) in the configuration. These ephemeral values are
   351  // not included in the persisted state, so they must be re-computed using other
   352  // values in the state before they can be properly evaluated. The updated
   353  // values are retained in the main state associated with the receiving context.
   354  //
   355  // This function takes no action against remote APIs but it does need access
   356  // to all provider and provisioner instances in order to obtain their schemas
   357  // for type checking.
   358  //
   359  // The result is an evaluation scope that can be used to resolve references
   360  // against the root module. If the returned diagnostics contains errors then
   361  // the returned scope may be nil. If it is not nil then it may still be used
   362  // to attempt expression evaluation or other analysis, but some expressions
   363  // may not behave as expected.
   364  func (c *Context) Eval(path addrs.ModuleInstance) (*lang.Scope, tfdiags.Diagnostics) {
   365  	// This is intended for external callers such as the "terraform console"
   366  	// command. Internally, we create an evaluator in c.walk before walking
   367  	// the graph, and create scopes in ContextGraphWalker.
   368  
   369  	var diags tfdiags.Diagnostics
   370  	defer c.acquireRun("eval")()
   371  
   372  	// Start with a copy of state so that we don't affect any instances
   373  	// that other methods may have already returned.
   374  	c.state = c.state.DeepCopy()
   375  	var walker *ContextGraphWalker
   376  
   377  	graph, graphDiags := c.Graph(GraphTypeEval, nil)
   378  	diags = diags.Append(graphDiags)
   379  	if !diags.HasErrors() {
   380  		var walkDiags tfdiags.Diagnostics
   381  		walker, walkDiags = c.walk(graph, walkEval)
   382  		diags = diags.Append(walker.NonFatalDiagnostics)
   383  		diags = diags.Append(walkDiags)
   384  	}
   385  
   386  	if walker == nil {
   387  		// If we skipped walking the graph (due to errors) then we'll just
   388  		// use a placeholder graph walker here, which'll refer to the
   389  		// unmodified state.
   390  		walker = c.graphWalker(walkEval)
   391  	}
   392  
   393  	// This is a bit weird since we don't normally evaluate outside of
   394  	// the context of a walk, but we'll "re-enter" our desired path here
   395  	// just to get hold of an EvalContext for it. GraphContextBuiltin
   396  	// caches its contexts, so we should get hold of the context that was
   397  	// previously used for evaluation here, unless we skipped walking.
   398  	evalCtx := walker.EnterPath(path)
   399  	return evalCtx.EvaluationScope(nil, EvalDataForNoInstanceKey), diags
   400  }
   401  
   402  // Apply applies the changes represented by this context and returns
   403  // the resulting state.
   404  //
   405  // Even in the case an error is returned, the state may be returned and will
   406  // potentially be partially updated.  In addition to returning the resulting
   407  // state, this context is updated with the latest state.
   408  //
   409  // If the state is required after an error, the caller should call
   410  // Context.State, rather than rely on the return value.
   411  //
   412  // TODO: Apply and Refresh should either always return a state, or rely on the
   413  //       State() method. Currently the helper/resource testing framework relies
   414  //       on the absence of a returned state to determine if Destroy can be
   415  //       called, so that will need to be refactored before this can be changed.
   416  func (c *Context) Apply() (*states.State, tfdiags.Diagnostics) {
   417  	defer c.acquireRun("apply")()
   418  
   419  	// Copy our own state
   420  	c.state = c.state.DeepCopy()
   421  
   422  	// Build the graph.
   423  	graph, diags := c.Graph(GraphTypeApply, nil)
   424  	if diags.HasErrors() {
   425  		return nil, diags
   426  	}
   427  
   428  	// Determine the operation
   429  	operation := walkApply
   430  	if c.destroy {
   431  		operation = walkDestroy
   432  	}
   433  
   434  	// Walk the graph
   435  	walker, walkDiags := c.walk(graph, operation)
   436  	diags = diags.Append(walker.NonFatalDiagnostics)
   437  	diags = diags.Append(walkDiags)
   438  
   439  	if c.destroy && !diags.HasErrors() {
   440  		// If we know we were trying to destroy objects anyway, and we
   441  		// completed without any errors, then we'll also prune out any
   442  		// leftover empty resource husks (left after all of the instances
   443  		// of a resource with "count" or "for_each" are destroyed) to
   444  		// help ensure we end up with an _actually_ empty state, assuming
   445  		// we weren't destroying with -target here.
   446  		//
   447  		// (This doesn't actually take into account -target, but that should
   448  		// be okay because it doesn't throw away anything we can't recompute
   449  		// on a subsequent "terraform plan" run, if the resources are still
   450  		// present in the configuration. However, this _will_ cause "count = 0"
   451  		// resources to read as unknown during the next refresh walk, which
   452  		// may cause some additional churn if used in a data resource or
   453  		// provider block, until we remove refreshing as a separate walk and
   454  		// just do it as part of the plan walk.)
   455  		c.state.PruneResourceHusks()
   456  	}
   457  
   458  	if len(c.targets) > 0 {
   459  		diags = diags.Append(tfdiags.Sourceless(
   460  			tfdiags.Warning,
   461  			"Applied changes may be incomplete",
   462  			`The plan was created with the -target option in effect, so some changes requested in the configuration may have been ignored and the output values may not be fully updated. Run the following command to verify that no other changes are pending:
   463      terraform plan
   464  	
   465  Note that the -target option is not suitable for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
   466  		))
   467  	}
   468  
   469  	return c.state, diags
   470  }
   471  
   472  // Plan generates an execution plan for the given context.
   473  //
   474  // The execution plan encapsulates the context and can be stored
   475  // in order to reinstantiate a context later for Apply.
   476  //
   477  // Plan also updates the diff of this context to be the diff generated
   478  // by the plan, so Apply can be called after.
   479  func (c *Context) Plan() (*plans.Plan, tfdiags.Diagnostics) {
   480  	defer c.acquireRun("plan")()
   481  	c.changes = plans.NewChanges()
   482  
   483  	var diags tfdiags.Diagnostics
   484  
   485  	if len(c.targets) > 0 {
   486  		diags = diags.Append(tfdiags.Sourceless(
   487  			tfdiags.Warning,
   488  			"Resource targeting is in effect",
   489  			`You are creating a plan with the -target option, which means that the result of this plan may not represent all of the changes requested by the current configuration.
   490  		
   491  The -target option is not for routine use, and is provided only for exceptional situations such as recovering from errors or mistakes, or when Terraform specifically suggests to use it as part of an error message.`,
   492  		))
   493  	}
   494  
   495  	varVals := make(map[string]plans.DynamicValue, len(c.variables))
   496  	for k, iv := range c.variables {
   497  		// We use cty.DynamicPseudoType here so that we'll save both the
   498  		// value _and_ its dynamic type in the plan, so we can recover
   499  		// exactly the same value later.
   500  		dv, err := plans.NewDynamicValue(iv.Value, cty.DynamicPseudoType)
   501  		if err != nil {
   502  			diags = diags.Append(tfdiags.Sourceless(
   503  				tfdiags.Error,
   504  				"Failed to prepare variable value for plan",
   505  				fmt.Sprintf("The value for variable %q could not be serialized to store in the plan: %s.", k, err),
   506  			))
   507  			continue
   508  		}
   509  		varVals[k] = dv
   510  	}
   511  
   512  	p := &plans.Plan{
   513  		VariableValues:  varVals,
   514  		TargetAddrs:     c.targets,
   515  		ProviderSHA256s: c.providerSHA256s,
   516  	}
   517  
   518  	var operation walkOperation
   519  	if c.destroy {
   520  		operation = walkPlanDestroy
   521  	} else {
   522  		// Set our state to be something temporary. We do this so that
   523  		// the plan can update a fake state so that variables work, then
   524  		// we replace it back with our old state.
   525  		old := c.state
   526  		if old == nil {
   527  			c.state = states.NewState()
   528  		} else {
   529  			c.state = old.DeepCopy()
   530  		}
   531  		defer func() {
   532  			c.state = old
   533  		}()
   534  
   535  		operation = walkPlan
   536  	}
   537  
   538  	// Build the graph.
   539  	graphType := GraphTypePlan
   540  	if c.destroy {
   541  		graphType = GraphTypePlanDestroy
   542  	}
   543  	graph, graphDiags := c.Graph(graphType, nil)
   544  	diags = diags.Append(graphDiags)
   545  	if graphDiags.HasErrors() {
   546  		return nil, diags
   547  	}
   548  
   549  	// Do the walk
   550  	walker, walkDiags := c.walk(graph, operation)
   551  	diags = diags.Append(walker.NonFatalDiagnostics)
   552  	diags = diags.Append(walkDiags)
   553  	if walkDiags.HasErrors() {
   554  		return nil, diags
   555  	}
   556  	p.Changes = c.changes
   557  
   558  	return p, diags
   559  }
   560  
   561  // Refresh goes through all the resources in the state and refreshes them
   562  // to their latest state. This will update the state that this context
   563  // works with, along with returning it.
   564  //
   565  // Even in the case an error is returned, the state may be returned and
   566  // will potentially be partially updated.
   567  func (c *Context) Refresh() (*states.State, tfdiags.Diagnostics) {
   568  	defer c.acquireRun("refresh")()
   569  
   570  	// Copy our own state
   571  	c.state = c.state.DeepCopy()
   572  
   573  	// Refresh builds a partial changeset as part of its work because it must
   574  	// create placeholder stubs for any resource instances that'll be created
   575  	// in subsequent plan so that provider configurations and data resources
   576  	// can interpolate from them. This plan is always thrown away after
   577  	// the operation completes, restoring any existing changeset.
   578  	oldChanges := c.changes
   579  	defer func() { c.changes = oldChanges }()
   580  	c.changes = plans.NewChanges()
   581  
   582  	// Build the graph.
   583  	graph, diags := c.Graph(GraphTypeRefresh, nil)
   584  	if diags.HasErrors() {
   585  		return nil, diags
   586  	}
   587  
   588  	// Do the walk
   589  	_, walkDiags := c.walk(graph, walkRefresh)
   590  	diags = diags.Append(walkDiags)
   591  	if walkDiags.HasErrors() {
   592  		return nil, diags
   593  	}
   594  
   595  	// During our walk we will have created planned object placeholders in
   596  	// state for resource instances that are in configuration but not yet
   597  	// created. These were created only to allow expression evaluation to
   598  	// work properly in provider and data blocks during the walk and must
   599  	// now be discarded, since a subsequent plan walk is responsible for
   600  	// creating these "for real".
   601  	// TODO: Consolidate refresh and plan into a single walk, so that the
   602  	// refresh walk doesn't need to emulate various aspects of the plan
   603  	// walk in order to properly evaluate provider and data blocks.
   604  	c.state.SyncWrapper().RemovePlannedResourceInstanceObjects()
   605  
   606  	return c.state, diags
   607  }
   608  
   609  // Stop stops the running task.
   610  //
   611  // Stop will block until the task completes.
   612  func (c *Context) Stop() {
   613  	log.Printf("[WARN] terraform: Stop called, initiating interrupt sequence")
   614  
   615  	c.l.Lock()
   616  	defer c.l.Unlock()
   617  
   618  	// If we're running, then stop
   619  	if c.runContextCancel != nil {
   620  		log.Printf("[WARN] terraform: run context exists, stopping")
   621  
   622  		// Tell the hook we want to stop
   623  		c.sh.Stop()
   624  
   625  		// Stop the context
   626  		c.runContextCancel()
   627  		c.runContextCancel = nil
   628  	}
   629  
   630  	// Grab the condition var before we exit
   631  	if cond := c.runCond; cond != nil {
   632  		log.Printf("[INFO] terraform: waiting for graceful stop to complete")
   633  		cond.Wait()
   634  	}
   635  
   636  	log.Printf("[WARN] terraform: stop complete")
   637  }
   638  
   639  // Validate performs semantic validation of the configuration, and returning
   640  // any warnings or errors.
   641  //
   642  // Syntax and structural checks are performed by the configuration loader,
   643  // and so are not repeated here.
   644  func (c *Context) Validate() tfdiags.Diagnostics {
   645  	defer c.acquireRun("validate")()
   646  
   647  	var diags tfdiags.Diagnostics
   648  
   649  	// Validate input variables. We do this only for the values supplied
   650  	// by the root module, since child module calls are validated when we
   651  	// visit their graph nodes.
   652  	if c.config != nil {
   653  		varDiags := checkInputVariables(c.config.Module.Variables, c.variables)
   654  		diags = diags.Append(varDiags)
   655  	}
   656  
   657  	// If we have errors at this point then we probably won't be able to
   658  	// construct a graph without producing redundant errors, so we'll halt early.
   659  	if diags.HasErrors() {
   660  		return diags
   661  	}
   662  
   663  	// Build the graph so we can walk it and run Validate on nodes.
   664  	// We also validate the graph generated here, but this graph doesn't
   665  	// necessarily match the graph that Plan will generate, so we'll validate the
   666  	// graph again later after Planning.
   667  	graph, graphDiags := c.Graph(GraphTypeValidate, nil)
   668  	diags = diags.Append(graphDiags)
   669  	if graphDiags.HasErrors() {
   670  		return diags
   671  	}
   672  
   673  	// Walk
   674  	walker, walkDiags := c.walk(graph, walkValidate)
   675  	diags = diags.Append(walker.NonFatalDiagnostics)
   676  	diags = diags.Append(walkDiags)
   677  	if walkDiags.HasErrors() {
   678  		return diags
   679  	}
   680  
   681  	return diags
   682  }
   683  
   684  // Config returns the configuration tree associated with this context.
   685  func (c *Context) Config() *configs.Config {
   686  	return c.config
   687  }
   688  
   689  // Variables will return the mapping of variables that were defined
   690  // for this Context. If Input was called, this mapping may be different
   691  // than what was given.
   692  func (c *Context) Variables() InputValues {
   693  	return c.variables
   694  }
   695  
   696  // SetVariable sets a variable after a context has already been built.
   697  func (c *Context) SetVariable(k string, v cty.Value) {
   698  	c.variables[k] = &InputValue{
   699  		Value:      v,
   700  		SourceType: ValueFromCaller,
   701  	}
   702  }
   703  
   704  func (c *Context) acquireRun(phase string) func() {
   705  	// With the run lock held, grab the context lock to make changes
   706  	// to the run context.
   707  	c.l.Lock()
   708  	defer c.l.Unlock()
   709  
   710  	// Wait until we're no longer running
   711  	for c.runCond != nil {
   712  		c.runCond.Wait()
   713  	}
   714  
   715  	// Build our lock
   716  	c.runCond = sync.NewCond(&c.l)
   717  
   718  	// Create a new run context
   719  	c.runContext, c.runContextCancel = context.WithCancel(context.Background())
   720  
   721  	// Reset the stop hook so we're not stopped
   722  	c.sh.Reset()
   723  
   724  	// Reset the shadow errors
   725  	c.shadowErr = nil
   726  
   727  	return c.releaseRun
   728  }
   729  
   730  func (c *Context) releaseRun() {
   731  	// Grab the context lock so that we can make modifications to fields
   732  	c.l.Lock()
   733  	defer c.l.Unlock()
   734  
   735  	// End our run. We check if runContext is non-nil because it can be
   736  	// set to nil if it was cancelled via Stop()
   737  	if c.runContextCancel != nil {
   738  		c.runContextCancel()
   739  	}
   740  
   741  	// Unlock all waiting our condition
   742  	cond := c.runCond
   743  	c.runCond = nil
   744  	cond.Broadcast()
   745  
   746  	// Unset the context
   747  	c.runContext = nil
   748  }
   749  
   750  func (c *Context) walk(graph *Graph, operation walkOperation) (*ContextGraphWalker, tfdiags.Diagnostics) {
   751  	log.Printf("[DEBUG] Starting graph walk: %s", operation.String())
   752  
   753  	walker := c.graphWalker(operation)
   754  
   755  	// Watch for a stop so we can call the provider Stop() API.
   756  	watchStop, watchWait := c.watchStop(walker)
   757  
   758  	// Walk the real graph, this will block until it completes
   759  	diags := graph.Walk(walker)
   760  
   761  	// Close the channel so the watcher stops, and wait for it to return.
   762  	close(watchStop)
   763  	<-watchWait
   764  
   765  	return walker, diags
   766  }
   767  
   768  func (c *Context) graphWalker(operation walkOperation) *ContextGraphWalker {
   769  	return &ContextGraphWalker{
   770  		Context:            c,
   771  		State:              c.state.SyncWrapper(),
   772  		Changes:            c.changes.SyncWrapper(),
   773  		Operation:          operation,
   774  		StopContext:        c.runContext,
   775  		RootVariableValues: c.variables,
   776  	}
   777  }
   778  
   779  // watchStop immediately returns a `stop` and a `wait` chan after dispatching
   780  // the watchStop goroutine. This will watch the runContext for cancellation and
   781  // stop the providers accordingly.  When the watch is no longer needed, the
   782  // `stop` chan should be closed before waiting on the `wait` chan.
   783  // The `wait` chan is important, because without synchronizing with the end of
   784  // the watchStop goroutine, the runContext may also be closed during the select
   785  // incorrectly causing providers to be stopped. Even if the graph walk is done
   786  // at that point, stopping a provider permanently cancels its StopContext which
   787  // can cause later actions to fail.
   788  func (c *Context) watchStop(walker *ContextGraphWalker) (chan struct{}, <-chan struct{}) {
   789  	stop := make(chan struct{})
   790  	wait := make(chan struct{})
   791  
   792  	// get the runContext cancellation channel now, because releaseRun will
   793  	// write to the runContext field.
   794  	done := c.runContext.Done()
   795  
   796  	go func() {
   797  		defer close(wait)
   798  		// Wait for a stop or completion
   799  		select {
   800  		case <-done:
   801  			// done means the context was canceled, so we need to try and stop
   802  			// providers.
   803  		case <-stop:
   804  			// our own stop channel was closed.
   805  			return
   806  		}
   807  
   808  		// If we're here, we're stopped, trigger the call.
   809  		log.Printf("[TRACE] Context: requesting providers and provisioners to gracefully stop")
   810  
   811  		{
   812  			// Copy the providers so that a misbehaved blocking Stop doesn't
   813  			// completely hang Terraform.
   814  			walker.providerLock.Lock()
   815  			ps := make([]providers.Interface, 0, len(walker.providerCache))
   816  			for _, p := range walker.providerCache {
   817  				ps = append(ps, p)
   818  			}
   819  			defer walker.providerLock.Unlock()
   820  
   821  			for _, p := range ps {
   822  				// We ignore the error for now since there isn't any reasonable
   823  				// action to take if there is an error here, since the stop is still
   824  				// advisory: Terraform will exit once the graph node completes.
   825  				p.Stop()
   826  			}
   827  		}
   828  
   829  		{
   830  			// Call stop on all the provisioners
   831  			walker.provisionerLock.Lock()
   832  			ps := make([]provisioners.Interface, 0, len(walker.provisionerCache))
   833  			for _, p := range walker.provisionerCache {
   834  				ps = append(ps, p)
   835  			}
   836  			defer walker.provisionerLock.Unlock()
   837  
   838  			for _, p := range ps {
   839  				// We ignore the error for now since there isn't any reasonable
   840  				// action to take if there is an error here, since the stop is still
   841  				// advisory: Terraform will exit once the graph node completes.
   842  				p.Stop()
   843  			}
   844  		}
   845  	}()
   846  
   847  	return stop, wait
   848  }
   849  
   850  // ShimLegacyState is a helper that takes the legacy state type and
   851  // converts it to the new state type.
   852  //
   853  // This is implemented as a state file upgrade, so it will not preserve
   854  // parts of the state structure that are not included in a serialized state,
   855  // such as the resolved results of any local values, outputs in non-root
   856  // modules, etc.
   857  func ShimLegacyState(legacy *State) (*states.State, error) {
   858  	if legacy == nil {
   859  		return nil, nil
   860  	}
   861  	var buf bytes.Buffer
   862  	err := WriteState(legacy, &buf)
   863  	if err != nil {
   864  		return nil, err
   865  	}
   866  	f, err := statefile.Read(&buf)
   867  	if err != nil {
   868  		return nil, err
   869  	}
   870  	return f.State, err
   871  }
   872  
   873  // MustShimLegacyState is a wrapper around ShimLegacyState that panics if
   874  // the conversion does not succeed. This is primarily intended for tests where
   875  // the given legacy state is an object constructed within the test.
   876  func MustShimLegacyState(legacy *State) *states.State {
   877  	ret, err := ShimLegacyState(legacy)
   878  	if err != nil {
   879  		panic(err)
   880  	}
   881  	return ret
   882  }