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