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 }