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