github.com/bendemaree/terraform@v0.5.4-0.20150613200311-f50d97d6eee6/terraform/eval_context_builtin.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 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 // PathValue is the Path that this context is operating within. 16 PathValue []string 17 18 // Interpolater setting below affect the interpolation of variables. 19 // 20 // The InterpolaterVars are the exact value for ${var.foo} values. 21 // The map is shared between all contexts and is a mapping of 22 // PATH to KEY to VALUE. Because it is shared by all contexts as well 23 // as the Interpolater itself, it is protected by InterpolaterVarLock 24 // which must be locked during any access to the map. 25 Interpolater *Interpolater 26 InterpolaterVars map[string]map[string]string 27 InterpolaterVarLock *sync.Mutex 28 29 Hooks []Hook 30 InputValue UIInput 31 Providers map[string]ResourceProviderFactory 32 ProviderCache map[string]ResourceProvider 33 ProviderConfigCache map[string]*ResourceConfig 34 ProviderInputConfig map[string]map[string]interface{} 35 ProviderLock *sync.Mutex 36 Provisioners map[string]ResourceProvisionerFactory 37 ProvisionerCache map[string]ResourceProvisioner 38 ProvisionerLock *sync.Mutex 39 DiffValue *Diff 40 DiffLock *sync.RWMutex 41 StateValue *State 42 StateLock *sync.RWMutex 43 44 once sync.Once 45 } 46 47 func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error { 48 for _, h := range ctx.Hooks { 49 action, err := fn(h) 50 if err != nil { 51 return err 52 } 53 54 switch action { 55 case HookActionContinue: 56 continue 57 case HookActionHalt: 58 // Return an early exit error to trigger an early exit 59 log.Printf("[WARN] Early exit triggered by hook: %T", h) 60 return EvalEarlyExitError{} 61 } 62 } 63 64 return nil 65 } 66 67 func (ctx *BuiltinEvalContext) Input() UIInput { 68 return ctx.InputValue 69 } 70 71 func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) { 72 ctx.once.Do(ctx.init) 73 74 // If we already initialized, it is an error 75 if p := ctx.Provider(n); p != nil { 76 return nil, fmt.Errorf("Provider '%s' already initialized", n) 77 } 78 79 // Warning: make sure to acquire these locks AFTER the call to Provider 80 // above, since it also acquires locks. 81 ctx.ProviderLock.Lock() 82 defer ctx.ProviderLock.Unlock() 83 84 typeName := strings.SplitN(n, ".", 2)[0] 85 86 f, ok := ctx.Providers[typeName] 87 if !ok { 88 return nil, fmt.Errorf("Provider '%s' not found", typeName) 89 } 90 91 p, err := f() 92 if err != nil { 93 return nil, err 94 } 95 96 providerPath := make([]string, len(ctx.Path())+1) 97 copy(providerPath, ctx.Path()) 98 providerPath[len(providerPath)-1] = n 99 100 ctx.ProviderCache[PathCacheKey(providerPath)] = p 101 return p, nil 102 } 103 104 func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider { 105 ctx.once.Do(ctx.init) 106 107 ctx.ProviderLock.Lock() 108 defer ctx.ProviderLock.Unlock() 109 110 providerPath := make([]string, len(ctx.Path())+1) 111 copy(providerPath, ctx.Path()) 112 providerPath[len(providerPath)-1] = n 113 114 return ctx.ProviderCache[PathCacheKey(providerPath)] 115 } 116 117 func (ctx *BuiltinEvalContext) ConfigureProvider( 118 n string, cfg *ResourceConfig) error { 119 p := ctx.Provider(n) 120 if p == nil { 121 return fmt.Errorf("Provider '%s' not initialized", n) 122 } 123 124 if err := ctx.SetProviderConfig(n, cfg); err != nil { 125 return nil 126 } 127 128 return p.Configure(cfg) 129 } 130 131 func (ctx *BuiltinEvalContext) SetProviderConfig( 132 n string, cfg *ResourceConfig) error { 133 providerPath := make([]string, len(ctx.Path())+1) 134 copy(providerPath, ctx.Path()) 135 providerPath[len(providerPath)-1] = n 136 137 // Save the configuration 138 ctx.ProviderLock.Lock() 139 ctx.ProviderConfigCache[PathCacheKey(providerPath)] = cfg 140 ctx.ProviderLock.Unlock() 141 142 return nil 143 } 144 145 func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} { 146 ctx.ProviderLock.Lock() 147 defer ctx.ProviderLock.Unlock() 148 149 return ctx.ProviderInputConfig[n] 150 } 151 152 func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) { 153 ctx.ProviderLock.Lock() 154 defer ctx.ProviderLock.Unlock() 155 156 ctx.ProviderInputConfig[n] = c 157 } 158 159 func (ctx *BuiltinEvalContext) ParentProviderConfig(n string) *ResourceConfig { 160 ctx.ProviderLock.Lock() 161 defer ctx.ProviderLock.Unlock() 162 163 // Make a copy of the path so we can safely edit it 164 path := ctx.Path() 165 pathCopy := make([]string, len(path)+1) 166 copy(pathCopy, path) 167 168 // Go up the tree. 169 for i := len(path) - 1; i >= 0; i-- { 170 pathCopy[i+1] = n 171 k := PathCacheKey(pathCopy[:i+2]) 172 if v, ok := ctx.ProviderConfigCache[k]; ok { 173 return v 174 } 175 } 176 177 return nil 178 } 179 180 func (ctx *BuiltinEvalContext) InitProvisioner( 181 n string) (ResourceProvisioner, error) { 182 ctx.once.Do(ctx.init) 183 184 // If we already initialized, it is an error 185 if p := ctx.Provisioner(n); p != nil { 186 return nil, fmt.Errorf("Provisioner '%s' already initialized", n) 187 } 188 189 // Warning: make sure to acquire these locks AFTER the call to Provisioner 190 // above, since it also acquires locks. 191 ctx.ProvisionerLock.Lock() 192 defer ctx.ProvisionerLock.Unlock() 193 194 f, ok := ctx.Provisioners[n] 195 if !ok { 196 return nil, fmt.Errorf("Provisioner '%s' not found", n) 197 } 198 199 p, err := f() 200 if err != nil { 201 return nil, err 202 } 203 204 provPath := make([]string, len(ctx.Path())+1) 205 copy(provPath, ctx.Path()) 206 provPath[len(provPath)-1] = n 207 208 ctx.ProvisionerCache[PathCacheKey(provPath)] = p 209 return p, nil 210 } 211 212 func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner { 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 return ctx.ProvisionerCache[PathCacheKey(provPath)] 223 } 224 225 func (ctx *BuiltinEvalContext) Interpolate( 226 cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) { 227 if cfg != nil { 228 scope := &InterpolationScope{ 229 Path: ctx.Path(), 230 Resource: r, 231 } 232 vs, err := ctx.Interpolater.Values(scope, cfg.Variables) 233 if err != nil { 234 return nil, err 235 } 236 237 // Do the interpolation 238 if err := cfg.Interpolate(vs); err != nil { 239 return nil, err 240 } 241 } 242 243 result := NewResourceConfig(cfg) 244 result.interpolateForce() 245 return result, nil 246 } 247 248 func (ctx *BuiltinEvalContext) Path() []string { 249 return ctx.PathValue 250 } 251 252 func (ctx *BuiltinEvalContext) SetVariables(n string, vs map[string]string) { 253 ctx.InterpolaterVarLock.Lock() 254 defer ctx.InterpolaterVarLock.Unlock() 255 256 path := make([]string, len(ctx.Path())+1) 257 copy(path, ctx.Path()) 258 path[len(path)-1] = n 259 key := PathCacheKey(path) 260 261 vars := ctx.InterpolaterVars[key] 262 if vars == nil { 263 vars = make(map[string]string) 264 ctx.InterpolaterVars[key] = vars 265 } 266 267 for k, v := range vs { 268 vars[k] = v 269 } 270 } 271 272 func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) { 273 return ctx.DiffValue, ctx.DiffLock 274 } 275 276 func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) { 277 return ctx.StateValue, ctx.StateLock 278 } 279 280 func (ctx *BuiltinEvalContext) init() { 281 // We nil-check the things below because they're meant to be configured, 282 // and we just default them to non-nil. 283 if ctx.Providers == nil { 284 ctx.Providers = make(map[string]ResourceProviderFactory) 285 } 286 }