github.com/opentofu/opentofu@v1.7.1/internal/tofu/graph_walk_context.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package tofu 7 8 import ( 9 "context" 10 "sync" 11 "time" 12 13 "github.com/zclconf/go-cty/cty" 14 15 "github.com/opentofu/opentofu/internal/addrs" 16 "github.com/opentofu/opentofu/internal/checks" 17 "github.com/opentofu/opentofu/internal/configs" 18 "github.com/opentofu/opentofu/internal/encryption" 19 "github.com/opentofu/opentofu/internal/instances" 20 "github.com/opentofu/opentofu/internal/plans" 21 "github.com/opentofu/opentofu/internal/providers" 22 "github.com/opentofu/opentofu/internal/provisioners" 23 "github.com/opentofu/opentofu/internal/refactoring" 24 "github.com/opentofu/opentofu/internal/states" 25 "github.com/opentofu/opentofu/internal/tfdiags" 26 ) 27 28 // ContextGraphWalker is the GraphWalker implementation used with the 29 // Context struct to walk and evaluate the graph. 30 type ContextGraphWalker struct { 31 NullGraphWalker 32 33 // Configurable values 34 Context *Context 35 State *states.SyncState // Used for safe concurrent access to state 36 RefreshState *states.SyncState // Used for safe concurrent access to state 37 PrevRunState *states.SyncState // Used for safe concurrent access to state 38 Changes *plans.ChangesSync // Used for safe concurrent writes to changes 39 Checks *checks.State // Used for safe concurrent writes of checkable objects and their check results 40 InstanceExpander *instances.Expander // Tracks our gradual expansion of module and resource instances 41 ImportResolver *ImportResolver // Tracks import targets as they are being resolved 42 MoveResults refactoring.MoveResults // Read-only record of earlier processing of move statements 43 Operation walkOperation 44 StopContext context.Context 45 RootVariableValues InputValues 46 Config *configs.Config 47 PlanTimestamp time.Time 48 Encryption encryption.Encryption 49 50 // This is an output. Do not set this, nor read it while a graph walk 51 // is in progress. 52 NonFatalDiagnostics tfdiags.Diagnostics 53 54 once sync.Once 55 contexts map[string]*BuiltinEvalContext 56 contextLock sync.Mutex 57 variableValues map[string]map[string]cty.Value 58 variableValuesLock sync.Mutex 59 providerCache map[string]providers.Interface 60 providerLock sync.Mutex 61 provisionerCache map[string]provisioners.Interface 62 provisionerLock sync.Mutex 63 } 64 65 func (w *ContextGraphWalker) EnterPath(path addrs.ModuleInstance) EvalContext { 66 w.contextLock.Lock() 67 defer w.contextLock.Unlock() 68 69 // If we already have a context for this path cached, use that 70 key := path.String() 71 if ctx, ok := w.contexts[key]; ok { 72 return ctx 73 } 74 75 ctx := w.EvalContext().WithPath(path) 76 w.contexts[key] = ctx.(*BuiltinEvalContext) 77 return ctx 78 } 79 80 func (w *ContextGraphWalker) EvalContext() EvalContext { 81 w.once.Do(w.init) 82 83 // Our evaluator shares some locks with the main context and the walker 84 // so that we can safely run multiple evaluations at once across 85 // different modules. 86 evaluator := &Evaluator{ 87 Meta: w.Context.meta, 88 Config: w.Config, 89 Operation: w.Operation, 90 State: w.State, 91 Changes: w.Changes, 92 Plugins: w.Context.plugins, 93 VariableValues: w.variableValues, 94 VariableValuesLock: &w.variableValuesLock, 95 PlanTimestamp: w.PlanTimestamp, 96 } 97 98 ctx := &BuiltinEvalContext{ 99 StopContext: w.StopContext, 100 Hooks: w.Context.hooks, 101 InputValue: w.Context.uiInput, 102 InstanceExpanderValue: w.InstanceExpander, 103 Plugins: w.Context.plugins, 104 MoveResultsValue: w.MoveResults, 105 ImportResolverValue: w.ImportResolver, 106 ProviderCache: w.providerCache, 107 ProviderInputConfig: w.Context.providerInputConfig, 108 ProviderLock: &w.providerLock, 109 ProvisionerCache: w.provisionerCache, 110 ProvisionerLock: &w.provisionerLock, 111 ChangesValue: w.Changes, 112 ChecksValue: w.Checks, 113 StateValue: w.State, 114 RefreshStateValue: w.RefreshState, 115 PrevRunStateValue: w.PrevRunState, 116 Evaluator: evaluator, 117 VariableValues: w.variableValues, 118 VariableValuesLock: &w.variableValuesLock, 119 Encryption: w.Encryption, 120 } 121 122 return ctx 123 } 124 125 func (w *ContextGraphWalker) init() { 126 w.contexts = make(map[string]*BuiltinEvalContext) 127 w.providerCache = make(map[string]providers.Interface) 128 w.provisionerCache = make(map[string]provisioners.Interface) 129 w.variableValues = make(map[string]map[string]cty.Value) 130 131 // Populate root module variable values. Other modules will be populated 132 // during the graph walk. 133 w.variableValues[""] = make(map[string]cty.Value) 134 for k, iv := range w.RootVariableValues { 135 w.variableValues[""][k] = iv.Value 136 } 137 } 138 139 func (w *ContextGraphWalker) Execute(ctx EvalContext, n GraphNodeExecutable) tfdiags.Diagnostics { 140 // Acquire a lock on the semaphore 141 w.Context.parallelSem.Acquire() 142 defer w.Context.parallelSem.Release() 143 144 return n.Execute(ctx, w.Operation) 145 }