9 "github.com/hashicorp/terraform/config"
12 // BuiltinEvalContext is an EvalContext implementation that is used by
13 // Terraform by default.
14 type BuiltinEvalContext struct {
15 // StopContext is the context used to track whether we're complete
16 StopContext context.Context
18 // PathValue is the Path that this context is operating within.
21 // Interpolater setting below affect the interpolation of variables.
23 // The InterpolaterVars are the exact value for ${var.foo} values.
24 // The map is shared between all contexts and is a mapping of
25 // PATH to KEY to VALUE. Because it is shared by all contexts as well
26 // as the Interpolater itself, it is protected by InterpolaterVarLock
27 // which must be locked during any access to the map.
28 Interpolater *Interpolater
29 InterpolaterVars map[string]map[string]interface{}
30 InterpolaterVarLock *sync.Mutex
32 Components contextComponentFactory
35 ProviderCache map[string]ResourceProvider
36 ProviderInputConfig map[string]map[string]interface{}
37 ProviderLock *sync.Mutex
38 ProvisionerCache map[string]ResourceProvisioner
39 ProvisionerLock *sync.Mutex
41 DiffLock *sync.RWMutex
43 StateLock *sync.RWMutex
48 func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} {
49 // This can happen during tests. During tests, we just block forever.
50 if ctx.StopContext == nil {
54 return ctx.StopContext.Done()
57 func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error {
58 for _, h := range ctx.Hooks {
65 case HookActionContinue:
68 // Return an early exit error to trigger an early exit
69 log.Printf("[WARN] Early exit triggered by hook: %T", h)
70 return EvalEarlyExitError{}
77 func (ctx *BuiltinEvalContext) Input() UIInput {
81 func (ctx *BuiltinEvalContext) InitProvider(typeName, name string) (ResourceProvider, error) {
84 // If we already initialized, it is an error
85 if p := ctx.Provider(name); p != nil {
86 return nil, fmt.Errorf("Provider '%s' already initialized", name)
89 // Warning: make sure to acquire these locks AFTER the call to Provider
90 // above, since it also acquires locks.
91 ctx.ProviderLock.Lock()
92 defer ctx.ProviderLock.Unlock()
94 p, err := ctx.Components.ResourceProvider(typeName, name)
99 ctx.ProviderCache[name] = p
103 func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
104 ctx.once.Do(ctx.init)
106 ctx.ProviderLock.Lock()
107 defer ctx.ProviderLock.Unlock()
109 return ctx.ProviderCache[n]
112 func (ctx *BuiltinEvalContext) CloseProvider(n string) error {
113 ctx.once.Do(ctx.init)
115 ctx.ProviderLock.Lock()
116 defer ctx.ProviderLock.Unlock()
118 var provider interface{}
119 provider = ctx.ProviderCache[n]
121 if p, ok := provider.(ResourceProviderCloser); ok {
122 delete(ctx.ProviderCache, n)
130 func (ctx *BuiltinEvalContext) ConfigureProvider(
131 n string, cfg *ResourceConfig) error {
134 return fmt.Errorf("Provider '%s' not initialized", n)
136 return p.Configure(cfg)
139 func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} {
140 ctx.ProviderLock.Lock()
141 defer ctx.ProviderLock.Unlock()
143 // Make a copy of the path so we can safely edit it
145 pathCopy := make([]string, len(path)+1)
149 for i := len(path) - 1; i >= 0; i-- {
151 k := PathCacheKey(pathCopy[:i+2])
152 if v, ok := ctx.ProviderInputConfig[k]; ok {
160 func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) {
161 providerPath := make([]string, len(ctx.Path())+1)
162 copy(providerPath, ctx.Path())
163 providerPath[len(providerPath)-1] = n
165 // Save the configuration
166 ctx.ProviderLock.Lock()
167 ctx.ProviderInputConfig[PathCacheKey(providerPath)] = c
168 ctx.ProviderLock.Unlock()
171 func (ctx *BuiltinEvalContext) InitProvisioner(
172 n string) (ResourceProvisioner, error) {
173 ctx.once.Do(ctx.init)
175 // If we already initialized, it is an error
176 if p := ctx.Provisioner(n); p != nil {
177 return nil, fmt.Errorf("Provisioner '%s' already initialized", n)
180 // Warning: make sure to acquire these locks AFTER the call to Provisioner
181 // above, since it also acquires locks.
182 ctx.ProvisionerLock.Lock()
183 defer ctx.ProvisionerLock.Unlock()
185 provPath := make([]string, len(ctx.Path())+1)
186 copy(provPath, ctx.Path())
187 provPath[len(provPath)-1] = n
188 key := PathCacheKey(provPath)
190 p, err := ctx.Components.ResourceProvisioner(n, key)
195 ctx.ProvisionerCache[key] = p
199 func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner {
200 ctx.once.Do(ctx.init)
202 ctx.ProvisionerLock.Lock()
203 defer ctx.ProvisionerLock.Unlock()
205 provPath := make([]string, len(ctx.Path())+1)
206 copy(provPath, ctx.Path())
207 provPath[len(provPath)-1] = n
209 return ctx.ProvisionerCache[PathCacheKey(provPath)]
212 func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error {
213 ctx.once.Do(ctx.init)
215 ctx.ProvisionerLock.Lock()
216 defer ctx.ProvisionerLock.Unlock()
218 provPath := make([]string, len(ctx.Path())+1)
219 copy(provPath, ctx.Path())
220 provPath[len(provPath)-1] = n
223 prov = ctx.ProvisionerCache[PathCacheKey(provPath)]
225 if p, ok := prov.(ResourceProvisionerCloser); ok {
226 delete(ctx.ProvisionerCache, PathCacheKey(provPath))
234 func (ctx *BuiltinEvalContext) Interpolate(
235 cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) {
238 scope := &InterpolationScope{
243 vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
248 // Do the interpolation
249 if err := cfg.Interpolate(vs); err != nil {
254 result := NewResourceConfig(cfg)
255 result.interpolateForce()
259 func (ctx *BuiltinEvalContext) InterpolateProvider(
260 pc *config.ProviderConfig, r *Resource) (*ResourceConfig, error) {
262 var cfg *config.RawConfig
264 if pc != nil && pc.RawConfig != nil {
265 scope := &InterpolationScope{
272 vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
277 // Do the interpolation
278 if err := cfg.Interpolate(vs); err != nil {
283 result := NewResourceConfig(cfg)
284 result.interpolateForce()
288 func (ctx *BuiltinEvalContext) Path() []string {
292 func (ctx *BuiltinEvalContext) SetVariables(n string, vs map[string]interface{}) {
293 ctx.InterpolaterVarLock.Lock()
294 defer ctx.InterpolaterVarLock.Unlock()
296 path := make([]string, len(ctx.Path())+1)
297 copy(path, ctx.Path())
298 path[len(path)-1] = n
299 key := PathCacheKey(path)
301 vars := ctx.InterpolaterVars[key]
303 vars = make(map[string]interface{})
304 ctx.InterpolaterVars[key] = vars
307 for k, v := range vs {
312 func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) {
313 return ctx.DiffValue, ctx.DiffLock
316 func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) {
317 return ctx.StateValue, ctx.StateLock
320 func (ctx *BuiltinEvalContext) init() {