summaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/terraform/terraform/graph_walk_context.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/graph_walk_context.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/graph_walk_context.go157
1 files changed, 157 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/graph_walk_context.go b/vendor/github.com/hashicorp/terraform/terraform/graph_walk_context.go
new file mode 100644
index 00000000..e63b4603
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/graph_walk_context.go
@@ -0,0 +1,157 @@
+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)
+}