github.com/r3labs/terraform@v0.8.4/terraform/graph_walk_context.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "sync" 7 8 "github.com/hashicorp/errwrap" 9 "github.com/hashicorp/terraform/dag" 10 ) 11 12 // ContextGraphWalker is the GraphWalker implementation used with the 13 // Context struct to walk and evaluate the graph. 14 type ContextGraphWalker struct { 15 NullGraphWalker 16 17 // Configurable values 18 Context *Context 19 Operation walkOperation 20 21 // Outputs, do not set these. Do not read these while the graph 22 // is being walked. 23 ValidationWarnings []string 24 ValidationErrors []error 25 26 errorLock sync.Mutex 27 once sync.Once 28 contexts map[string]*BuiltinEvalContext 29 contextLock sync.Mutex 30 interpolaterVars map[string]map[string]interface{} 31 interpolaterVarLock sync.Mutex 32 providerCache map[string]ResourceProvider 33 providerConfigCache map[string]*ResourceConfig 34 providerLock sync.Mutex 35 provisionerCache map[string]ResourceProvisioner 36 provisionerLock sync.Mutex 37 } 38 39 func (w *ContextGraphWalker) EnterPath(path []string) EvalContext { 40 w.once.Do(w.init) 41 42 w.contextLock.Lock() 43 defer w.contextLock.Unlock() 44 45 // If we already have a context for this path cached, use that 46 key := PathCacheKey(path) 47 if ctx, ok := w.contexts[key]; ok { 48 return ctx 49 } 50 51 // Setup the variables for this interpolater 52 variables := make(map[string]interface{}) 53 if len(path) <= 1 { 54 for k, v := range w.Context.variables { 55 variables[k] = v 56 } 57 } 58 w.interpolaterVarLock.Lock() 59 if m, ok := w.interpolaterVars[key]; ok { 60 for k, v := range m { 61 variables[k] = v 62 } 63 } 64 w.interpolaterVars[key] = variables 65 w.interpolaterVarLock.Unlock() 66 67 ctx := &BuiltinEvalContext{ 68 PathValue: path, 69 Hooks: w.Context.hooks, 70 InputValue: w.Context.uiInput, 71 Components: w.Context.components, 72 ProviderCache: w.providerCache, 73 ProviderConfigCache: w.providerConfigCache, 74 ProviderInputConfig: w.Context.providerInputConfig, 75 ProviderLock: &w.providerLock, 76 ProvisionerCache: w.provisionerCache, 77 ProvisionerLock: &w.provisionerLock, 78 DiffValue: w.Context.diff, 79 DiffLock: &w.Context.diffLock, 80 StateValue: w.Context.state, 81 StateLock: &w.Context.stateLock, 82 Interpolater: &Interpolater{ 83 Operation: w.Operation, 84 Module: w.Context.module, 85 State: w.Context.state, 86 StateLock: &w.Context.stateLock, 87 VariableValues: variables, 88 VariableValuesLock: &w.interpolaterVarLock, 89 }, 90 InterpolaterVars: w.interpolaterVars, 91 InterpolaterVarLock: &w.interpolaterVarLock, 92 } 93 94 w.contexts[key] = ctx 95 return ctx 96 } 97 98 func (w *ContextGraphWalker) EnterEvalTree(v dag.Vertex, n EvalNode) EvalNode { 99 log.Printf("[TRACE] [%s] Entering eval tree: %s", 100 w.Operation, dag.VertexName(v)) 101 102 // Acquire a lock on the semaphore 103 w.Context.parallelSem.Acquire() 104 105 // We want to filter the evaluation tree to only include operations 106 // that belong in this operation. 107 return EvalFilter(n, EvalNodeFilterOp(w.Operation)) 108 } 109 110 func (w *ContextGraphWalker) ExitEvalTree( 111 v dag.Vertex, output interface{}, err error) error { 112 log.Printf("[TRACE] [%s] Exiting eval tree: %s", 113 w.Operation, dag.VertexName(v)) 114 115 // Release the semaphore 116 w.Context.parallelSem.Release() 117 118 if err == nil { 119 return nil 120 } 121 122 // Acquire the lock because anything is going to require a lock. 123 w.errorLock.Lock() 124 defer w.errorLock.Unlock() 125 126 // Try to get a validation error out of it. If its not a validation 127 // error, then just record the normal error. 128 verr, ok := err.(*EvalValidateError) 129 if !ok { 130 return err 131 } 132 133 for _, msg := range verr.Warnings { 134 w.ValidationWarnings = append( 135 w.ValidationWarnings, 136 fmt.Sprintf("%s: %s", dag.VertexName(v), msg)) 137 } 138 for _, e := range verr.Errors { 139 w.ValidationErrors = append( 140 w.ValidationErrors, 141 errwrap.Wrapf(fmt.Sprintf("%s: {{err}}", dag.VertexName(v)), e)) 142 } 143 144 return nil 145 } 146 147 func (w *ContextGraphWalker) init() { 148 w.contexts = make(map[string]*BuiltinEvalContext, 5) 149 w.providerCache = make(map[string]ResourceProvider, 5) 150 w.providerConfigCache = make(map[string]*ResourceConfig, 5) 151 w.provisionerCache = make(map[string]ResourceProvisioner, 5) 152 w.interpolaterVars = make(map[string]map[string]interface{}, 5) 153 }