github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/terraform/context_eval.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  
     6  	"github.com/hashicorp/terraform/internal/addrs"
     7  	"github.com/hashicorp/terraform/internal/configs"
     8  	"github.com/hashicorp/terraform/internal/lang"
     9  	"github.com/hashicorp/terraform/internal/states"
    10  	"github.com/hashicorp/terraform/internal/tfdiags"
    11  )
    12  
    13  type EvalOpts struct {
    14  	SetVariables InputValues
    15  }
    16  
    17  // Eval produces a scope in which expressions can be evaluated for
    18  // the given module path.
    19  //
    20  // This method must first evaluate any ephemeral values (input variables, local
    21  // values, and output values) in the configuration. These ephemeral values are
    22  // not included in the persisted state, so they must be re-computed using other
    23  // values in the state before they can be properly evaluated. The updated
    24  // values are retained in the main state associated with the receiving context.
    25  //
    26  // This function takes no action against remote APIs but it does need access
    27  // to all provider and provisioner instances in order to obtain their schemas
    28  // for type checking.
    29  //
    30  // The result is an evaluation scope that can be used to resolve references
    31  // against the root module. If the returned diagnostics contains errors then
    32  // the returned scope may be nil. If it is not nil then it may still be used
    33  // to attempt expression evaluation or other analysis, but some expressions
    34  // may not behave as expected.
    35  func (c *Context) Eval(config *configs.Config, state *states.State, moduleAddr addrs.ModuleInstance, opts *EvalOpts) (*lang.Scope, tfdiags.Diagnostics) {
    36  	// This is intended for external callers such as the "terraform console"
    37  	// command. Internally, we create an evaluator in c.walk before walking
    38  	// the graph, and create scopes in ContextGraphWalker.
    39  
    40  	var diags tfdiags.Diagnostics
    41  	defer c.acquireRun("eval")()
    42  
    43  	// Start with a copy of state so that we don't affect the instance that
    44  	// the caller is holding.
    45  	state = state.DeepCopy()
    46  	var walker *ContextGraphWalker
    47  
    48  	variables := opts.SetVariables
    49  
    50  	// By the time we get here, we should have values defined for all of
    51  	// the root module variables, even if some of them are "unknown". It's the
    52  	// caller's responsibility to have already handled the decoding of these
    53  	// from the various ways the CLI allows them to be set and to produce
    54  	// user-friendly error messages if they are not all present, and so
    55  	// the error message from checkInputVariables should never be seen and
    56  	// includes language asking the user to report a bug.
    57  	varDiags := checkInputVariables(config.Module.Variables, variables)
    58  	diags = diags.Append(varDiags)
    59  
    60  	log.Printf("[DEBUG] Building and walking 'eval' graph")
    61  
    62  	graph, moreDiags := (&EvalGraphBuilder{
    63  		Config:             config,
    64  		State:              state,
    65  		RootVariableValues: variables,
    66  		Plugins:            c.plugins,
    67  	}).Build(addrs.RootModuleInstance)
    68  	diags = diags.Append(moreDiags)
    69  	if moreDiags.HasErrors() {
    70  		return nil, diags
    71  	}
    72  
    73  	walkOpts := &graphWalkOpts{
    74  		InputState: state,
    75  		Config:     config,
    76  	}
    77  
    78  	walker, moreDiags = c.walk(graph, walkEval, walkOpts)
    79  	diags = diags.Append(moreDiags)
    80  	if walker != nil {
    81  		diags = diags.Append(walker.NonFatalDiagnostics)
    82  	} else {
    83  		// If we skipped walking the graph (due to errors) then we'll just
    84  		// use a placeholder graph walker here, which'll refer to the
    85  		// unmodified state.
    86  		walker = c.graphWalker(walkEval, walkOpts)
    87  	}
    88  
    89  	// This is a bit weird since we don't normally evaluate outside of
    90  	// the context of a walk, but we'll "re-enter" our desired path here
    91  	// just to get hold of an EvalContext for it. ContextGraphWalker
    92  	// caches its contexts, so we should get hold of the context that was
    93  	// previously used for evaluation here, unless we skipped walking.
    94  	evalCtx := walker.EnterPath(moduleAddr)
    95  	return evalCtx.EvaluationScope(nil, EvalDataForNoInstanceKey), diags
    96  }