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