github.com/magodo/terraform@v0.11.12-beta1/terraform/eval_context_builtin.go (about) 1 package terraform 2 3 import ( 4 "context" 5 "fmt" 6 "log" 7 "sync" 8 9 "github.com/hashicorp/terraform/config" 10 ) 11 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 17 18 // PathValue is the Path that this context is operating within. 19 PathValue []string 20 21 // Interpolater setting below affect the interpolation of variables. 22 // 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 31 32 Components contextComponentFactory 33 Hooks []Hook 34 InputValue UIInput 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 40 DiffValue *Diff 41 DiffLock *sync.RWMutex 42 StateValue *State 43 StateLock *sync.RWMutex 44 45 once sync.Once 46 } 47 48 func (ctx *BuiltinEvalContext) Stopped() <-chan struct{} { 49 // This can happen during tests. During tests, we just block forever. 50 if ctx.StopContext == nil { 51 return nil 52 } 53 54 return ctx.StopContext.Done() 55 } 56 57 func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error { 58 for _, h := range ctx.Hooks { 59 action, err := fn(h) 60 if err != nil { 61 return err 62 } 63 64 switch action { 65 case HookActionContinue: 66 continue 67 case HookActionHalt: 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{} 71 } 72 } 73 74 return nil 75 } 76 77 func (ctx *BuiltinEvalContext) Input() UIInput { 78 return ctx.InputValue 79 } 80 81 func (ctx *BuiltinEvalContext) InitProvider(typeName, name string) (ResourceProvider, error) { 82 ctx.once.Do(ctx.init) 83 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) 87 } 88 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() 93 94 p, err := ctx.Components.ResourceProvider(typeName, name) 95 if err != nil { 96 return nil, err 97 } 98 99 ctx.ProviderCache[name] = p 100 return p, nil 101 } 102 103 func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider { 104 ctx.once.Do(ctx.init) 105 106 ctx.ProviderLock.Lock() 107 defer ctx.ProviderLock.Unlock() 108 109 return ctx.ProviderCache[n] 110 } 111 112 func (ctx *BuiltinEvalContext) CloseProvider(n string) error { 113 ctx.once.Do(ctx.init) 114 115 ctx.ProviderLock.Lock() 116 defer ctx.ProviderLock.Unlock() 117 118 var provider interface{} 119 provider = ctx.ProviderCache[n] 120 if provider != nil { 121 if p, ok := provider.(ResourceProviderCloser); ok { 122 delete(ctx.ProviderCache, n) 123 return p.Close() 124 } 125 } 126 127 return nil 128 } 129 130 func (ctx *BuiltinEvalContext) ConfigureProvider( 131 n string, cfg *ResourceConfig) error { 132 p := ctx.Provider(n) 133 if p == nil { 134 return fmt.Errorf("Provider '%s' not initialized", n) 135 } 136 return p.Configure(cfg) 137 } 138 139 func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} { 140 ctx.ProviderLock.Lock() 141 defer ctx.ProviderLock.Unlock() 142 143 // Make a copy of the path so we can safely edit it 144 path := ctx.Path() 145 pathCopy := make([]string, len(path)+1) 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 } 156 157 return nil 158 } 159 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 164 165 // Save the configuration 166 ctx.ProviderLock.Lock() 167 ctx.ProviderInputConfig[PathCacheKey(providerPath)] = c 168 ctx.ProviderLock.Unlock() 169 } 170 171 func (ctx *BuiltinEvalContext) InitProvisioner( 172 n string) (ResourceProvisioner, error) { 173 ctx.once.Do(ctx.init) 174 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) 178 } 179 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() 184 185 provPath := make([]string, len(ctx.Path())+1) 186 copy(provPath, ctx.Path()) 187 provPath[len(provPath)-1] = n 188 key := PathCacheKey(provPath) 189 190 p, err := ctx.Components.ResourceProvisioner(n, key) 191 if err != nil { 192 return nil, err 193 } 194 195 ctx.ProvisionerCache[key] = p 196 return p, nil 197 } 198 199 func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner { 200 ctx.once.Do(ctx.init) 201 202 ctx.ProvisionerLock.Lock() 203 defer ctx.ProvisionerLock.Unlock() 204 205 provPath := make([]string, len(ctx.Path())+1) 206 copy(provPath, ctx.Path()) 207 provPath[len(provPath)-1] = n 208 209 return ctx.ProvisionerCache[PathCacheKey(provPath)] 210 } 211 212 func (ctx *BuiltinEvalContext) CloseProvisioner(n string) error { 213 ctx.once.Do(ctx.init) 214 215 ctx.ProvisionerLock.Lock() 216 defer ctx.ProvisionerLock.Unlock() 217 218 provPath := make([]string, len(ctx.Path())+1) 219 copy(provPath, ctx.Path()) 220 provPath[len(provPath)-1] = n 221 222 var prov interface{} 223 prov = ctx.ProvisionerCache[PathCacheKey(provPath)] 224 if prov != nil { 225 if p, ok := prov.(ResourceProvisionerCloser); ok { 226 delete(ctx.ProvisionerCache, PathCacheKey(provPath)) 227 return p.Close() 228 } 229 } 230 231 return nil 232 } 233 234 func (ctx *BuiltinEvalContext) Interpolate( 235 cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) { 236 237 if cfg != nil { 238 scope := &InterpolationScope{ 239 Path: ctx.Path(), 240 Resource: r, 241 } 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 } 258 259 func (ctx *BuiltinEvalContext) InterpolateProvider( 260 pc *config.ProviderConfig, r *Resource) (*ResourceConfig, error) { 261 262 var cfg *config.RawConfig 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 277 // Do the interpolation 278 if err := cfg.Interpolate(vs); err != nil { 279 return nil, err 280 } 281 } 282 283 result := NewResourceConfig(cfg) 284 result.interpolateForce() 285 return result, nil 286 } 287 288 func (ctx *BuiltinEvalContext) Path() []string { 289 return ctx.PathValue 290 } 291 292 func (ctx *BuiltinEvalContext) SetVariables(n string, vs map[string]interface{}) { 293 ctx.InterpolaterVarLock.Lock() 294 defer ctx.InterpolaterVarLock.Unlock() 295 296 path := make([]string, len(ctx.Path())+1) 297 copy(path, ctx.Path()) 298 path[len(path)-1] = n 299 key := PathCacheKey(path) 300 301 vars := ctx.InterpolaterVars[key] 302 if vars == nil { 303 vars = make(map[string]interface{}) 304 ctx.InterpolaterVars[key] = vars 305 } 306 307 for k, v := range vs { 308 vars[k] = v 309 } 310 } 311 312 func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) { 313 return ctx.DiffValue, ctx.DiffLock 314 } 315 316 func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) { 317 return ctx.StateValue, ctx.StateLock 318 } 319 320 func (ctx *BuiltinEvalContext) init() { 321 }