diff options
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/eval_context_builtin.go')
-rw-r--r-- | vendor/github.com/hashicorp/terraform/terraform/eval_context_builtin.go | 292 |
1 files changed, 150 insertions, 142 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/eval_context_builtin.go b/vendor/github.com/hashicorp/terraform/terraform/eval_context_builtin.go index 1b6ee5a..20b3793 100644 --- a/vendor/github.com/hashicorp/terraform/terraform/eval_context_builtin.go +++ b/vendor/github.com/hashicorp/terraform/terraform/eval_context_builtin.go | |||
@@ -6,7 +6,20 @@ import ( | |||
6 | "log" | 6 | "log" |
7 | "sync" | 7 | "sync" |
8 | 8 | ||
9 | "github.com/hashicorp/terraform/config" | 9 | "github.com/hashicorp/terraform/plans" |
10 | "github.com/hashicorp/terraform/providers" | ||
11 | "github.com/hashicorp/terraform/provisioners" | ||
12 | "github.com/hashicorp/terraform/version" | ||
13 | |||
14 | "github.com/hashicorp/terraform/states" | ||
15 | |||
16 | "github.com/hashicorp/hcl2/hcl" | ||
17 | "github.com/hashicorp/terraform/configs/configschema" | ||
18 | "github.com/hashicorp/terraform/lang" | ||
19 | "github.com/hashicorp/terraform/tfdiags" | ||
20 | |||
21 | "github.com/hashicorp/terraform/addrs" | ||
22 | "github.com/zclconf/go-cty/cty" | ||
10 | ) | 23 | ) |
11 | 24 | ||
12 | // BuiltinEvalContext is an EvalContext implementation that is used by | 25 | // BuiltinEvalContext is an EvalContext implementation that is used by |
@@ -16,35 +29,47 @@ type BuiltinEvalContext struct { | |||
16 | StopContext context.Context | 29 | StopContext context.Context |
17 | 30 | ||
18 | // PathValue is the Path that this context is operating within. | 31 | // PathValue is the Path that this context is operating within. |
19 | PathValue []string | 32 | PathValue addrs.ModuleInstance |
20 | 33 | ||
21 | // Interpolater setting below affect the interpolation of variables. | 34 | // Evaluator is used for evaluating expressions within the scope of this |
35 | // eval context. | ||
36 | Evaluator *Evaluator | ||
37 | |||
38 | // Schemas is a repository of all of the schemas we should need to | ||
39 | // decode configuration blocks and expressions. This must be constructed by | ||
40 | // the caller to include schemas for all of the providers, resource types, | ||
41 | // data sources and provisioners used by the given configuration and | ||
42 | // state. | ||
22 | // | 43 | // |
23 | // The InterpolaterVars are the exact value for ${var.foo} values. | 44 | // This must not be mutated during evaluation. |
24 | // The map is shared between all contexts and is a mapping of | 45 | Schemas *Schemas |
25 | // PATH to KEY to VALUE. Because it is shared by all contexts as well | 46 | |
26 | // as the Interpolater itself, it is protected by InterpolaterVarLock | 47 | // VariableValues contains the variable values across all modules. This |
27 | // which must be locked during any access to the map. | 48 | // structure is shared across the entire containing context, and so it |
28 | Interpolater *Interpolater | 49 | // may be accessed only when holding VariableValuesLock. |
29 | InterpolaterVars map[string]map[string]interface{} | 50 | // The keys of the first level of VariableValues are the string |
30 | InterpolaterVarLock *sync.Mutex | 51 | // representations of addrs.ModuleInstance values. The second-level keys |
52 | // are variable names within each module instance. | ||
53 | VariableValues map[string]map[string]cty.Value | ||
54 | VariableValuesLock *sync.Mutex | ||
31 | 55 | ||
32 | Components contextComponentFactory | 56 | Components contextComponentFactory |
33 | Hooks []Hook | 57 | Hooks []Hook |
34 | InputValue UIInput | 58 | InputValue UIInput |
35 | ProviderCache map[string]ResourceProvider | 59 | ProviderCache map[string]providers.Interface |
36 | ProviderInputConfig map[string]map[string]interface{} | 60 | ProviderInputConfig map[string]map[string]cty.Value |
37 | ProviderLock *sync.Mutex | 61 | ProviderLock *sync.Mutex |
38 | ProvisionerCache map[string]ResourceProvisioner | 62 | ProvisionerCache map[string]provisioners.Interface |
39 | ProvisionerLock *sync.Mutex | 63 | ProvisionerLock *sync.Mutex |
40 | DiffValue *Diff | 64 | ChangesValue *plans.ChangesSync |
41 | DiffLock *sync.RWMutex | 65 | StateValue *states.SyncState |
42 | StateValue *State | ||
43 | StateLock *sync.RWMutex | ||
44 | 66 | ||
45 | once sync.Once | 67 | once sync.Once |
46 | } | 68 | } |
47 | 69 | ||
70 | // BuiltinEvalContext implements EvalContext | ||
71 | var _ EvalContext = (*BuiltinEvalContext)(nil) | ||
72 | |||
48 | func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} { | 73 | func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} { |
49 | // This can happen during tests. During tests, we just block forever. | 74 | // This can happen during tests. During tests, we just block forever. |
50 | if ctx.StopContext == nil { | 75 | if ctx.StopContext == nil { |
@@ -78,12 +103,13 @@ func (ctx *BuiltinEvalContext) Input() UIInput { | |||
78 | return ctx.InputValue | 103 | return ctx.InputValue |
79 | } | 104 | } |
80 | 105 | ||
81 | func (ctx *BuiltinEvalContext) InitProvider(typeName, name string) (ResourceProvider, error) { | 106 | func (ctx *BuiltinEvalContext) InitProvider(typeName string, addr addrs.ProviderConfig) (providers.Interface, error) { |
82 | ctx.once.Do(ctx.init) | 107 | ctx.once.Do(ctx.init) |
108 | absAddr := addr.Absolute(ctx.Path()) | ||
83 | 109 | ||
84 | // If we already initialized, it is an error | 110 | // If we already initialized, it is an error |
85 | if p := ctx.Provider(name); p != nil { | 111 | if p := ctx.Provider(absAddr); p != nil { |
86 | return nil, fmt.Errorf("Provider '%s' already initialized", name) | 112 | return nil, fmt.Errorf("%s is already initialized", addr) |
87 | } | 113 | } |
88 | 114 | ||
89 | // Warning: make sure to acquire these locks AFTER the call to Provider | 115 | // Warning: make sure to acquire these locks AFTER the call to Provider |
@@ -91,85 +117,102 @@ func (ctx *BuiltinEvalContext) InitProvider(typeName, name string) (ResourceProv | |||
91 | ctx.ProviderLock.Lock() | 117 | ctx.ProviderLock.Lock() |
92 | defer ctx.ProviderLock.Unlock() | 118 | defer ctx.ProviderLock.Unlock() |
93 | 119 | ||
94 | p, err := ctx.Components.ResourceProvider(typeName, name) | 120 | key := absAddr.String() |
121 | |||
122 | p, err := ctx.Components.ResourceProvider(typeName, key) | ||
95 | if err != nil { | 123 | if err != nil { |
96 | return nil, err | 124 | return nil, err |
97 | } | 125 | } |
98 | 126 | ||
99 | ctx.ProviderCache[name] = p | 127 | log.Printf("[TRACE] BuiltinEvalContext: Initialized %q provider for %s", typeName, absAddr) |
128 | ctx.ProviderCache[key] = p | ||
129 | |||
100 | return p, nil | 130 | return p, nil |
101 | } | 131 | } |
102 | 132 | ||
103 | func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider { | 133 | func (ctx *BuiltinEvalContext) Provider(addr addrs.AbsProviderConfig) providers.Interface { |
104 | ctx.once.Do(ctx.init) | 134 | ctx.once.Do(ctx.init) |
105 | 135 | ||
106 | ctx.ProviderLock.Lock() | 136 | ctx.ProviderLock.Lock() |
107 | defer ctx.ProviderLock.Unlock() | 137 | defer ctx.ProviderLock.Unlock() |
108 | 138 | ||
109 | return ctx.ProviderCache[n] | 139 | return ctx.ProviderCache[addr.String()] |
140 | } | ||
141 | |||
142 | func (ctx *BuiltinEvalContext) ProviderSchema(addr addrs.AbsProviderConfig) *ProviderSchema { | ||
143 | ctx.once.Do(ctx.init) | ||
144 | |||
145 | return ctx.Schemas.ProviderSchema(addr.ProviderConfig.Type) | ||
110 | } | 146 | } |
111 | 147 | ||
112 | func (ctx *BuiltinEvalContext) CloseProvider(n string) error { | 148 | func (ctx *BuiltinEvalContext) CloseProvider(addr addrs.ProviderConfig) error { |
113 | ctx.once.Do(ctx.init) | 149 | ctx.once.Do(ctx.init) |
114 | 150 | ||
115 | ctx.ProviderLock.Lock() | 151 | ctx.ProviderLock.Lock() |
116 | defer ctx.ProviderLock.Unlock() | 152 | defer ctx.ProviderLock.Unlock() |
117 | 153 | ||
118 | var provider interface{} | 154 | key := addr.Absolute(ctx.Path()).String() |
119 | provider = ctx.ProviderCache[n] | 155 | provider := ctx.ProviderCache[key] |
120 | if provider != nil { | 156 | if provider != nil { |
121 | if p, ok := provider.(ResourceProviderCloser); ok { | 157 | delete(ctx.ProviderCache, key) |
122 | delete(ctx.ProviderCache, n) | 158 | return provider.Close() |
123 | return p.Close() | ||
124 | } | ||
125 | } | 159 | } |
126 | 160 | ||
127 | return nil | 161 | return nil |
128 | } | 162 | } |
129 | 163 | ||
130 | func (ctx *BuiltinEvalContext) ConfigureProvider( | 164 | func (ctx *BuiltinEvalContext) ConfigureProvider(addr addrs.ProviderConfig, cfg cty.Value) tfdiags.Diagnostics { |
131 | n string, cfg *ResourceConfig) error { | 165 | var diags tfdiags.Diagnostics |
132 | p := ctx.Provider(n) | 166 | absAddr := addr.Absolute(ctx.Path()) |
167 | p := ctx.Provider(absAddr) | ||
133 | if p == nil { | 168 | if p == nil { |
134 | return fmt.Errorf("Provider '%s' not initialized", n) | 169 | diags = diags.Append(fmt.Errorf("%s not initialized", addr)) |
170 | return diags | ||
135 | } | 171 | } |
136 | return p.Configure(cfg) | 172 | |
173 | providerSchema := ctx.ProviderSchema(absAddr) | ||
174 | if providerSchema == nil { | ||
175 | diags = diags.Append(fmt.Errorf("schema for %s is not available", absAddr)) | ||
176 | return diags | ||
177 | } | ||
178 | |||
179 | req := providers.ConfigureRequest{ | ||
180 | TerraformVersion: version.String(), | ||
181 | Config: cfg, | ||
182 | } | ||
183 | |||
184 | resp := p.Configure(req) | ||
185 | return resp.Diagnostics | ||
137 | } | 186 | } |
138 | 187 | ||
139 | func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} { | 188 | func (ctx *BuiltinEvalContext) ProviderInput(pc addrs.ProviderConfig) map[string]cty.Value { |
140 | ctx.ProviderLock.Lock() | 189 | ctx.ProviderLock.Lock() |
141 | defer ctx.ProviderLock.Unlock() | 190 | defer ctx.ProviderLock.Unlock() |
142 | 191 | ||
143 | // Make a copy of the path so we can safely edit it | 192 | if !ctx.Path().IsRoot() { |
144 | path := ctx.Path() | 193 | // Only root module provider configurations can have input. |
145 | pathCopy := make([]string, len(path)+1) | 194 | return nil |
146 | copy(pathCopy, path) | ||
147 | |||
148 | // Go up the tree. | ||
149 | for i := len(path) - 1; i >= 0; i-- { | ||
150 | pathCopy[i+1] = n | ||
151 | k := PathCacheKey(pathCopy[:i+2]) | ||
152 | if v, ok := ctx.ProviderInputConfig[k]; ok { | ||
153 | return v | ||
154 | } | ||
155 | } | 195 | } |
156 | 196 | ||
157 | return nil | 197 | return ctx.ProviderInputConfig[pc.String()] |
158 | } | 198 | } |
159 | 199 | ||
160 | func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) { | 200 | func (ctx *BuiltinEvalContext) SetProviderInput(pc addrs.ProviderConfig, c map[string]cty.Value) { |
161 | providerPath := make([]string, len(ctx.Path())+1) | 201 | absProvider := pc.Absolute(ctx.Path()) |
162 | copy(providerPath, ctx.Path()) | 202 | |
163 | providerPath[len(providerPath)-1] = n | 203 | if !ctx.Path().IsRoot() { |
204 | // Only root module provider configurations can have input. | ||
205 | log.Printf("[WARN] BuiltinEvalContext: attempt to SetProviderInput for non-root module") | ||
206 | return | ||
207 | } | ||
164 | 208 | ||
165 | // Save the configuration | 209 | // Save the configuration |
166 | ctx.ProviderLock.Lock() | 210 | ctx.ProviderLock.Lock() |
167 | ctx.ProviderInputConfig[PathCacheKey(providerPath)] = c | 211 | ctx.ProviderInputConfig[absProvider.String()] = c |
168 | ctx.ProviderLock.Unlock() | 212 | ctx.ProviderLock.Unlock() |
169 | } | 213 | } |
170 | 214 | ||
171 | func (ctx *BuiltinEvalContext) InitProvisioner( | 215 | func (ctx *BuiltinEvalContext) InitProvisioner(n string) (provisioners.Interface, error) { |
172 | n string) (ResourceProvisioner, error) { | ||
173 | ctx.once.Do(ctx.init) | 216 | ctx.once.Do(ctx.init) |
174 | 217 | ||
175 | // If we already initialized, it is an error | 218 | // If we already initialized, it is an error |
@@ -182,10 +225,7 @@ func (ctx *BuiltinEvalContext) InitProvisioner( | |||
182 | ctx.ProvisionerLock.Lock() | 225 | ctx.ProvisionerLock.Lock() |
183 | defer ctx.ProvisionerLock.Unlock() | 226 | defer ctx.ProvisionerLock.Unlock() |
184 | 227 | ||
185 | provPath := make([]string, len(ctx.Path())+1) | 228 | key := PathObjectCacheKey(ctx.Path(), n) |
186 | copy(provPath, ctx.Path()) | ||
187 | provPath[len(provPath)-1] = n | ||
188 | key := PathCacheKey(provPath) | ||
189 | 229 | ||
190 | p, err := ctx.Components.ResourceProvisioner(n, key) | 230 | p, err := ctx.Components.ResourceProvisioner(n, key) |
191 | if err != nil { | 231 | if err != nil { |
@@ -193,20 +233,24 @@ func (ctx *BuiltinEvalContext) InitProvisioner( | |||
193 | } | 233 | } |
194 | 234 | ||
195 | ctx.ProvisionerCache[key] = p | 235 | ctx.ProvisionerCache[key] = p |
236 | |||
196 | return p, nil | 237 | return p, nil |
197 | } | 238 | } |
198 | 239 | ||
199 | func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner { | 240 | func (ctx *BuiltinEvalContext) Provisioner(n string) provisioners.Interface { |
200 | ctx.once.Do(ctx.init) | 241 | ctx.once.Do(ctx.init) |
201 | 242 | ||
202 | ctx.ProvisionerLock.Lock() | 243 | ctx.ProvisionerLock.Lock() |
203 | defer ctx.ProvisionerLock.Unlock() | 244 | defer ctx.ProvisionerLock.Unlock() |
204 | 245 | ||
205 | provPath := make([]string, len(ctx.Path())+1) | 246 | key := PathObjectCacheKey(ctx.Path(), n) |
206 | copy(provPath, ctx.Path()) | 247 | return ctx.ProvisionerCache[key] |
207 | provPath[len(provPath)-1] = n | 248 | } |
249 | |||
250 | func (ctx *BuiltinEvalContext) ProvisionerSchema(n string) *configschema.Block { | ||
251 | ctx.once.Do(ctx.init) | ||
208 | 252 | ||
209 | return ctx.ProvisionerCache[PathCacheKey(provPath)] | 253 | return ctx.Schemas.ProvisionerConfig(n) |
210 | } | 254 | } |
211 | 255 | ||
212 | func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error { | 256 | func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error { |
@@ -215,106 +259,70 @@ func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error { | |||
215 | ctx.ProvisionerLock.Lock() | 259 | ctx.ProvisionerLock.Lock() |
216 | defer ctx.ProvisionerLock.Unlock() | 260 | defer ctx.ProvisionerLock.Unlock() |
217 | 261 | ||
218 | provPath := make([]string, len(ctx.Path())+1) | 262 | key := PathObjectCacheKey(ctx.Path(), n) |
219 | copy(provPath, ctx.Path()) | ||
220 | provPath[len(provPath)-1] = n | ||
221 | 263 | ||
222 | var prov interface{} | 264 | prov := ctx.ProvisionerCache[key] |
223 | prov = ctx.ProvisionerCache[PathCacheKey(provPath)] | ||
224 | if prov != nil { | 265 | if prov != nil { |
225 | if p, ok := prov.(ResourceProvisionerCloser); ok { | 266 | return prov.Close() |
226 | delete(ctx.ProvisionerCache, PathCacheKey(provPath)) | ||
227 | return p.Close() | ||
228 | } | ||
229 | } | 267 | } |
230 | 268 | ||
231 | return nil | 269 | return nil |
232 | } | 270 | } |
233 | 271 | ||
234 | func (ctx *BuiltinEvalContext) Interpolate( | 272 | func (ctx *BuiltinEvalContext) EvaluateBlock(body hcl.Body, schema *configschema.Block, self addrs.Referenceable, keyData InstanceKeyEvalData) (cty.Value, hcl.Body, tfdiags.Diagnostics) { |
235 | cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) { | 273 | var diags tfdiags.Diagnostics |
236 | 274 | scope := ctx.EvaluationScope(self, keyData) | |
237 | if cfg != nil { | 275 | body, evalDiags := scope.ExpandBlock(body, schema) |
238 | scope := &InterpolationScope{ | 276 | diags = diags.Append(evalDiags) |
239 | Path: ctx.Path(), | 277 | val, evalDiags := scope.EvalBlock(body, schema) |
240 | Resource: r, | 278 | diags = diags.Append(evalDiags) |
241 | } | 279 | return val, body, diags |
242 | |||
243 | vs, err := ctx.Interpolater.Values(scope, cfg.Variables) | ||
244 | if err != nil { | ||
245 | return nil, err | ||
246 | } | ||
247 | |||
248 | // Do the interpolation | ||
249 | if err := cfg.Interpolate(vs); err != nil { | ||
250 | return nil, err | ||
251 | } | ||
252 | } | ||
253 | |||
254 | result := NewResourceConfig(cfg) | ||
255 | result.interpolateForce() | ||
256 | return result, nil | ||
257 | } | 280 | } |
258 | 281 | ||
259 | func (ctx *BuiltinEvalContext) InterpolateProvider( | 282 | func (ctx *BuiltinEvalContext) EvaluateExpr(expr hcl.Expression, wantType cty.Type, self addrs.Referenceable) (cty.Value, tfdiags.Diagnostics) { |
260 | pc *config.ProviderConfig, r *Resource) (*ResourceConfig, error) { | 283 | scope := ctx.EvaluationScope(self, EvalDataForNoInstanceKey) |
261 | 284 | return scope.EvalExpr(expr, wantType) | |
262 | var cfg *config.RawConfig | 285 | } |
263 | |||
264 | if pc != nil && pc.RawConfig != nil { | ||
265 | scope := &InterpolationScope{ | ||
266 | Path: ctx.Path(), | ||
267 | Resource: r, | ||
268 | } | ||
269 | |||
270 | cfg = pc.RawConfig | ||
271 | |||
272 | vs, err := ctx.Interpolater.Values(scope, cfg.Variables) | ||
273 | if err != nil { | ||
274 | return nil, err | ||
275 | } | ||
276 | 286 | ||
277 | // Do the interpolation | 287 | func (ctx *BuiltinEvalContext) EvaluationScope(self addrs.Referenceable, keyData InstanceKeyEvalData) *lang.Scope { |
278 | if err := cfg.Interpolate(vs); err != nil { | 288 | data := &evaluationStateData{ |
279 | return nil, err | 289 | Evaluator: ctx.Evaluator, |
280 | } | 290 | ModulePath: ctx.PathValue, |
291 | InstanceKeyData: keyData, | ||
292 | Operation: ctx.Evaluator.Operation, | ||
281 | } | 293 | } |
282 | 294 | return ctx.Evaluator.Scope(data, self) | |
283 | result := NewResourceConfig(cfg) | ||
284 | result.interpolateForce() | ||
285 | return result, nil | ||
286 | } | 295 | } |
287 | 296 | ||
288 | func (ctx *BuiltinEvalContext) Path() []string { | 297 | func (ctx *BuiltinEvalContext) Path() addrs.ModuleInstance { |
289 | return ctx.PathValue | 298 | return ctx.PathValue |
290 | } | 299 | } |
291 | 300 | ||
292 | func (ctx *BuiltinEvalContext) SetVariables(n string, vs map[string]interface{}) { | 301 | func (ctx *BuiltinEvalContext) SetModuleCallArguments(n addrs.ModuleCallInstance, vals map[string]cty.Value) { |
293 | ctx.InterpolaterVarLock.Lock() | 302 | ctx.VariableValuesLock.Lock() |
294 | defer ctx.InterpolaterVarLock.Unlock() | 303 | defer ctx.VariableValuesLock.Unlock() |
295 | 304 | ||
296 | path := make([]string, len(ctx.Path())+1) | 305 | childPath := n.ModuleInstance(ctx.PathValue) |
297 | copy(path, ctx.Path()) | 306 | key := childPath.String() |
298 | path[len(path)-1] = n | ||
299 | key := PathCacheKey(path) | ||
300 | 307 | ||
301 | vars := ctx.InterpolaterVars[key] | 308 | args := ctx.VariableValues[key] |
302 | if vars == nil { | 309 | if args == nil { |
303 | vars = make(map[string]interface{}) | 310 | args = make(map[string]cty.Value) |
304 | ctx.InterpolaterVars[key] = vars | 311 | ctx.VariableValues[key] = vals |
312 | return | ||
305 | } | 313 | } |
306 | 314 | ||
307 | for k, v := range vs { | 315 | for k, v := range vals { |
308 | vars[k] = v | 316 | args[k] = v |
309 | } | 317 | } |
310 | } | 318 | } |
311 | 319 | ||
312 | func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) { | 320 | func (ctx *BuiltinEvalContext) Changes() *plans.ChangesSync { |
313 | return ctx.DiffValue, ctx.DiffLock | 321 | return ctx.ChangesValue |
314 | } | 322 | } |
315 | 323 | ||
316 | func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) { | 324 | func (ctx *BuiltinEvalContext) State() *states.SyncState { |
317 | return ctx.StateValue, ctx.StateLock | 325 | return ctx.StateValue |
318 | } | 326 | } |
319 | 327 | ||
320 | func (ctx *BuiltinEvalContext) init() { | 328 | func (ctx *BuiltinEvalContext) init() { |