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