github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/terraform/eval_context_builtin.go (about) 1 package terraform 2 3 import ( 4 "fmt" 5 "log" 6 "sync" 7 8 "github.com/hashicorp/terraform/config" 9 ) 10 11 // BuiltinEvalContext is an EvalContext implementation that is used by 12 // Terraform by default. 13 type BuiltinEvalContext struct { 14 PathValue []string 15 Interpolater *Interpolater 16 Hooks []Hook 17 InputValue UIInput 18 Providers map[string]ResourceProviderFactory 19 ProviderCache map[string]ResourceProvider 20 ProviderConfigCache map[string]*ResourceConfig 21 ProviderInputConfig map[string]map[string]interface{} 22 ProviderLock *sync.Mutex 23 Provisioners map[string]ResourceProvisionerFactory 24 ProvisionerCache map[string]ResourceProvisioner 25 ProvisionerLock *sync.Mutex 26 DiffValue *Diff 27 DiffLock *sync.RWMutex 28 StateValue *State 29 StateLock *sync.RWMutex 30 31 once sync.Once 32 } 33 34 func (ctx *BuiltinEvalContext) Hook(fn func(Hook) (HookAction, error)) error { 35 for _, h := range ctx.Hooks { 36 action, err := fn(h) 37 if err != nil { 38 return err 39 } 40 41 switch action { 42 case HookActionContinue: 43 continue 44 case HookActionHalt: 45 // Return an early exit error to trigger an early exit 46 log.Printf("[WARN] Early exit triggered by hook: %T", h) 47 return EvalEarlyExitError{} 48 } 49 } 50 51 return nil 52 } 53 54 func (ctx *BuiltinEvalContext) Input() UIInput { 55 return ctx.InputValue 56 } 57 58 func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) { 59 ctx.once.Do(ctx.init) 60 61 // If we already initialized, it is an error 62 if p := ctx.Provider(n); p != nil { 63 return nil, fmt.Errorf("Provider '%s' already initialized", n) 64 } 65 66 // Warning: make sure to acquire these locks AFTER the call to Provider 67 // above, since it also acquires locks. 68 ctx.ProviderLock.Lock() 69 defer ctx.ProviderLock.Unlock() 70 71 f, ok := ctx.Providers[n] 72 if !ok { 73 return nil, fmt.Errorf("Provider '%s' not found", n) 74 } 75 76 p, err := f() 77 if err != nil { 78 return nil, err 79 } 80 81 providerPath := make([]string, len(ctx.Path())+1) 82 copy(providerPath, ctx.Path()) 83 providerPath[len(providerPath)-1] = n 84 85 ctx.ProviderCache[PathCacheKey(providerPath)] = p 86 return p, nil 87 } 88 89 func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider { 90 ctx.once.Do(ctx.init) 91 92 ctx.ProviderLock.Lock() 93 defer ctx.ProviderLock.Unlock() 94 95 providerPath := make([]string, len(ctx.Path())+1) 96 copy(providerPath, ctx.Path()) 97 providerPath[len(providerPath)-1] = n 98 99 return ctx.ProviderCache[PathCacheKey(providerPath)] 100 } 101 102 func (ctx *BuiltinEvalContext) ConfigureProvider( 103 n string, cfg *ResourceConfig) error { 104 p := ctx.Provider(n) 105 if p == nil { 106 return fmt.Errorf("Provider '%s' not initialized", n) 107 } 108 109 providerPath := make([]string, len(ctx.Path())+1) 110 copy(providerPath, ctx.Path()) 111 providerPath[len(providerPath)-1] = n 112 113 // Save the configuration 114 ctx.ProviderLock.Lock() 115 ctx.ProviderConfigCache[PathCacheKey(providerPath)] = cfg 116 ctx.ProviderLock.Unlock() 117 118 return p.Configure(cfg) 119 } 120 121 func (ctx *BuiltinEvalContext) ProviderInput(n string) map[string]interface{} { 122 ctx.ProviderLock.Lock() 123 defer ctx.ProviderLock.Unlock() 124 125 return ctx.ProviderInputConfig[n] 126 } 127 128 func (ctx *BuiltinEvalContext) SetProviderInput(n string, c map[string]interface{}) { 129 ctx.ProviderLock.Lock() 130 defer ctx.ProviderLock.Unlock() 131 132 ctx.ProviderInputConfig[n] = c 133 } 134 135 func (ctx *BuiltinEvalContext) ParentProviderConfig(n string) *ResourceConfig { 136 ctx.ProviderLock.Lock() 137 defer ctx.ProviderLock.Unlock() 138 139 // Make a copy of the path so we can safely edit it 140 path := ctx.Path() 141 pathCopy := make([]string, len(path)+1) 142 copy(pathCopy, path) 143 144 // Go up the tree. 145 for i := len(path) - 1; i >= 0; i-- { 146 pathCopy[i+1] = n 147 k := PathCacheKey(pathCopy[:i+2]) 148 if v, ok := ctx.ProviderConfigCache[k]; ok { 149 return v 150 } 151 } 152 153 return nil 154 } 155 156 func (ctx *BuiltinEvalContext) InitProvisioner( 157 n string) (ResourceProvisioner, error) { 158 ctx.once.Do(ctx.init) 159 160 // If we already initialized, it is an error 161 if p := ctx.Provisioner(n); p != nil { 162 return nil, fmt.Errorf("Provisioner '%s' already initialized", n) 163 } 164 165 // Warning: make sure to acquire these locks AFTER the call to Provisioner 166 // above, since it also acquires locks. 167 ctx.ProvisionerLock.Lock() 168 defer ctx.ProvisionerLock.Unlock() 169 170 f, ok := ctx.Provisioners[n] 171 if !ok { 172 return nil, fmt.Errorf("Provisioner '%s' not found", n) 173 } 174 175 p, err := f() 176 if err != nil { 177 return nil, err 178 } 179 180 provPath := make([]string, len(ctx.Path())+1) 181 copy(provPath, ctx.Path()) 182 provPath[len(provPath)-1] = n 183 184 ctx.ProvisionerCache[PathCacheKey(provPath)] = p 185 return p, nil 186 } 187 188 func (ctx *BuiltinEvalContext) Provisioner(n string) ResourceProvisioner { 189 ctx.once.Do(ctx.init) 190 191 ctx.ProvisionerLock.Lock() 192 defer ctx.ProvisionerLock.Unlock() 193 194 provPath := make([]string, len(ctx.Path())+1) 195 copy(provPath, ctx.Path()) 196 provPath[len(provPath)-1] = n 197 198 return ctx.ProvisionerCache[PathCacheKey(provPath)] 199 } 200 201 func (ctx *BuiltinEvalContext) Interpolate( 202 cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) { 203 if cfg != nil { 204 scope := &InterpolationScope{ 205 Path: ctx.Path(), 206 Resource: r, 207 } 208 vs, err := ctx.Interpolater.Values(scope, cfg.Variables) 209 if err != nil { 210 return nil, err 211 } 212 213 // Do the interpolation 214 if err := cfg.Interpolate(vs); err != nil { 215 return nil, err 216 } 217 } 218 219 result := NewResourceConfig(cfg) 220 result.interpolateForce() 221 return result, nil 222 } 223 224 func (ctx *BuiltinEvalContext) Path() []string { 225 return ctx.PathValue 226 } 227 228 func (ctx *BuiltinEvalContext) SetVariables(vs map[string]string) { 229 for k, v := range vs { 230 ctx.Interpolater.Variables[k] = v 231 } 232 } 233 234 func (ctx *BuiltinEvalContext) Diff() (*Diff, *sync.RWMutex) { 235 return ctx.DiffValue, ctx.DiffLock 236 } 237 238 func (ctx *BuiltinEvalContext) State() (*State, *sync.RWMutex) { 239 return ctx.StateValue, ctx.StateLock 240 } 241 242 func (ctx *BuiltinEvalContext) init() { 243 // We nil-check the things below because they're meant to be configured, 244 // and we just default them to non-nil. 245 if ctx.Providers == nil { 246 ctx.Providers = make(map[string]ResourceProviderFactory) 247 } 248 }