mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-28 18:01:01 -06:00
db7596c045
Use the configured providers directly, rather than looking for inherited provider configuration during graph evaluation. First remove the provider config cache, and the associated SetProviderConfig and ParentProviderConfig methods on the eval context. Every provider must be configured, so there's no need to look for configuration from other provider instances. The config.ProviderConfig struct now has a Scope field which stores the proper path for the interpolation scope. To get this metadata to the interpolator, we add an EvalInterpolatProvider node which can carry the ProviderConfig, and an InterpolateProvider context method to carry the ProviderConfig.Scope into the InterplationScope. Some of the tests could be adjusted to account for the new inheritance behavior, and some were simply no longer valid and will be removed. The remaining tests have questions on how they should work in practice. This mostly concerns orphaned modules where there is no longer a way to obtain a provider. In some cases we may require that a minimal provider config be present to handle the destroy process, but we need further testing. All disabled code was commented out in this commit to record any additional comments. The following commit will be a cleanup pass.
158 lines
4.3 KiB
Go
158 lines
4.3 KiB
Go
package terraform
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"sync"
|
|
|
|
"github.com/hashicorp/errwrap"
|
|
"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
|
|
|
|
// Configurable values
|
|
Context *Context
|
|
Operation walkOperation
|
|
StopContext context.Context
|
|
|
|
// Outputs, do not set these. Do not read these while the graph
|
|
// is being walked.
|
|
ValidationWarnings []string
|
|
ValidationErrors []error
|
|
|
|
errorLock sync.Mutex
|
|
once sync.Once
|
|
contexts map[string]*BuiltinEvalContext
|
|
contextLock sync.Mutex
|
|
interpolaterVars map[string]map[string]interface{}
|
|
interpolaterVarLock sync.Mutex
|
|
providerCache map[string]ResourceProvider
|
|
//providerConfigCache map[string]*ResourceConfig
|
|
providerLock sync.Mutex
|
|
provisionerCache map[string]ResourceProvisioner
|
|
provisionerLock sync.Mutex
|
|
}
|
|
|
|
func (w *ContextGraphWalker) EnterPath(path []string) 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(path)
|
|
if ctx, ok := w.contexts[key]; ok {
|
|
return ctx
|
|
}
|
|
|
|
// Setup the variables for this interpolater
|
|
variables := make(map[string]interface{})
|
|
if len(path) <= 1 {
|
|
for k, v := range w.Context.variables {
|
|
variables[k] = v
|
|
}
|
|
}
|
|
w.interpolaterVarLock.Lock()
|
|
if m, ok := w.interpolaterVars[key]; ok {
|
|
for k, v := range m {
|
|
variables[k] = v
|
|
}
|
|
}
|
|
w.interpolaterVars[key] = variables
|
|
w.interpolaterVarLock.Unlock()
|
|
|
|
ctx := &BuiltinEvalContext{
|
|
StopContext: w.StopContext,
|
|
PathValue: path,
|
|
Hooks: w.Context.hooks,
|
|
InputValue: w.Context.uiInput,
|
|
Components: w.Context.components,
|
|
ProviderCache: w.providerCache,
|
|
//ProviderConfigCache: w.providerConfigCache,
|
|
ProviderInputConfig: w.Context.providerInputConfig,
|
|
ProviderLock: &w.providerLock,
|
|
ProvisionerCache: w.provisionerCache,
|
|
ProvisionerLock: &w.provisionerLock,
|
|
DiffValue: w.Context.diff,
|
|
DiffLock: &w.Context.diffLock,
|
|
StateValue: w.Context.state,
|
|
StateLock: &w.Context.stateLock,
|
|
Interpolater: &Interpolater{
|
|
Operation: w.Operation,
|
|
Meta: w.Context.meta,
|
|
Module: w.Context.module,
|
|
State: w.Context.state,
|
|
StateLock: &w.Context.stateLock,
|
|
VariableValues: variables,
|
|
VariableValuesLock: &w.interpolaterVarLock,
|
|
},
|
|
InterpolaterVars: w.interpolaterVars,
|
|
InterpolaterVarLock: &w.interpolaterVarLock,
|
|
}
|
|
|
|
w.contexts[key] = ctx
|
|
return ctx
|
|
}
|
|
|
|
func (w *ContextGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode {
|
|
log.Printf("[TRACE] [%s] Entering eval tree: %s",
|
|
w.Operation, dag.VertexName(v))
|
|
|
|
// Acquire a lock on the semaphore
|
|
w.Context.parallelSem.Acquire()
|
|
|
|
// 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 {
|
|
log.Printf("[TRACE] [%s] Exiting eval tree: %s",
|
|
w.Operation, dag.VertexName(v))
|
|
|
|
// Release the semaphore
|
|
w.Context.parallelSem.Release()
|
|
|
|
if err == nil {
|
|
return nil
|
|
}
|
|
|
|
// Acquire the lock because anything is going to require a lock.
|
|
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
|
|
}
|
|
|
|
for _, msg := range verr.Warnings {
|
|
w.ValidationWarnings = append(
|
|
w.ValidationWarnings,
|
|
fmt.Sprintf("%s: %s", dag.VertexName(v), msg))
|
|
}
|
|
for _, e := range verr.Errors {
|
|
w.ValidationErrors = append(
|
|
w.ValidationErrors,
|
|
errwrap.Wrapf(fmt.Sprintf("%s: {{err}}", dag.VertexName(v)), e))
|
|
}
|
|
|
|
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)
|
|
w.provisionerCache = make(map[string]ResourceProvisioner, 5)
|
|
w.interpolaterVars = make(map[string]map[string]interface{}, 5)
|
|
}
|