opentofu/terraform/graph_walk_context.go

119 lines
3.4 KiB
Go
Raw Normal View History

package terraform
import (
"sync"
"github.com/hashicorp/terraform/dag"
)
// ContextGraphWalker is the GraphWalker implementation used with the
// Context struct to walk and evaluate the graph.
type ContextGraphWalker struct {
NullGraphWalker
2015-02-07 17:14:34 -06:00
// Configurable values
Context *Context
Operation walkOperation
2015-02-07 17:14:34 -06:00
// Outputs, do not set these. Do not read these while the graph
// is being walked.
ValidationWarnings []string
ValidationErrors []error
2015-02-07 17:14:34 -06:00
errorLock sync.Mutex
once sync.Once
contexts map[string]*BuiltinEvalContext
contextLock sync.Mutex
providerCache map[string]ResourceProvider
providerConfigCache map[string]*ResourceConfig
providerLock sync.Mutex
provisionerCache map[string]ResourceProvisioner
provisionerLock sync.Mutex
}
func (w *ContextGraphWalker) EnterGraph(g *Graph) EvalContext {
w.once.Do(w.init)
w.contextLock.Lock()
defer w.contextLock.Unlock()
// If we already have a context for this path cached, use that
key := PathCacheKey(g.Path)
if ctx, ok := w.contexts[key]; ok {
return ctx
}
// Variables should be our context variables, but these only apply
// to the root module. As we enter subgraphs, we don't want to set
// variables, which is set by the SetVariables EvalContext function.
variables := w.Context.variables
if len(g.Path) > 1 {
// We're in a submodule, the variables should be empty
variables = make(map[string]string)
}
ctx := &BuiltinEvalContext{
PathValue: g.Path,
2015-02-11 15:43:07 -06:00
Hooks: w.Context.hooks,
2015-02-13 19:59:54 -06:00
InputValue: w.Context.uiInput,
Providers: w.Context.providers,
ProviderCache: w.providerCache,
ProviderConfigCache: w.providerConfigCache,
2015-02-13 19:59:54 -06:00
ProviderInputConfig: w.Context.providerInputConfig,
ProviderLock: &w.providerLock,
Provisioners: w.Context.provisioners,
ProvisionerCache: w.provisionerCache,
ProvisionerLock: &w.provisionerLock,
2015-02-12 21:34:21 -06:00
DiffValue: w.Context.diff,
DiffLock: &w.Context.diffLock,
2015-02-11 10:48:45 -06:00
StateValue: w.Context.state,
StateLock: &w.Context.stateLock,
Interpolater: &Interpolater{
Operation: w.Operation,
Module: w.Context.module,
State: w.Context.state,
StateLock: &w.Context.stateLock,
Variables: variables,
},
}
w.contexts[key] = ctx
return ctx
}
func (w *ContextGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode {
// We want to filter the evaluation tree to only include operations
// that belong in this operation.
return EvalFilter(n, EvalNodeFilterOp(w.Operation))
}
func (w *ContextGraphWalker) ExitEvalTree(
v dag.Vertex, output interface{}, err error) error {
if err == nil {
return nil
}
// Acquire the lock because anything is going to require a lock.
2015-02-07 17:14:34 -06:00
w.errorLock.Lock()
defer w.errorLock.Unlock()
// Try to get a validation error out of it. If its not a validation
// error, then just record the normal error.
verr, ok := err.(*EvalValidateError)
if !ok {
return err
}
// Record the validation error
w.ValidationWarnings = append(w.ValidationWarnings, verr.Warnings...)
w.ValidationErrors = append(w.ValidationErrors, verr.Errors...)
return nil
}
func (w *ContextGraphWalker) init() {
w.contexts = make(map[string]*BuiltinEvalContext, 5)
w.providerCache = make(map[string]ResourceProvider, 5)
w.providerConfigCache = make(map[string]*ResourceConfig, 5)
2015-02-09 13:15:54 -06:00
w.provisionerCache = make(map[string]ResourceProvisioner, 5)
}