terraform/terraform/eval_context_builtin.go

114 lines
2.7 KiB
Go
Raw Normal View History

2015-02-04 02:46:11 +01:00
package terraform
import (
"crypto/md5"
"encoding/hex"
2015-02-04 02:46:11 +01:00
"fmt"
"sync"
"github.com/hashicorp/terraform/config"
)
// BuiltinEvalContext is an EvalContext implementation that is used by
// Terraform by default.
type BuiltinEvalContext struct {
PathValue []string
Interpolater *Interpolater
Providers map[string]ResourceProviderFactory
ProviderCache map[string]ResourceProvider
ProviderLock *sync.Mutex
2015-02-04 02:46:11 +01:00
once sync.Once
2015-02-04 02:46:11 +01:00
}
func (ctx *BuiltinEvalContext) InitProvider(n string) (ResourceProvider, error) {
ctx.once.Do(ctx.init)
// If we already initialized, it is an error
2015-02-04 02:46:11 +01:00
if p := ctx.Provider(n); p != nil {
return nil, fmt.Errorf("Provider '%s' already initialized", n)
}
// Warning: make sure to acquire these locks AFTER the call to Provider
// above, since it also acquires locks.
ctx.ProviderLock.Lock()
defer ctx.ProviderLock.Unlock()
2015-02-04 02:46:11 +01:00
f, ok := ctx.Providers[n]
if !ok {
return nil, fmt.Errorf("Provider '%s' not found", n)
}
2015-02-05 02:02:18 +01:00
p, err := f()
if err != nil {
return nil, err
}
ctx.ProviderCache[ctx.pathCacheKey()] = p
2015-02-05 02:02:18 +01:00
return p, nil
2015-02-04 02:46:11 +01:00
}
func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
ctx.once.Do(ctx.init)
ctx.ProviderLock.Lock()
defer ctx.ProviderLock.Unlock()
return ctx.ProviderCache[ctx.pathCacheKey()]
2015-02-04 02:46:11 +01:00
}
func (ctx *BuiltinEvalContext) Interpolate(
cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) {
if cfg != nil {
scope := &InterpolationScope{
Path: ctx.Path(),
Resource: r,
}
vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
if err != nil {
return nil, err
2015-02-04 17:30:53 +01:00
}
// Do the interpolation
if err := cfg.Interpolate(vs); err != nil {
return nil, err
}
2015-02-04 17:30:53 +01:00
}
result := NewResourceConfig(cfg)
result.interpolateForce()
return result, nil
2015-02-04 02:46:11 +01:00
}
func (ctx *BuiltinEvalContext) Path() []string {
return ctx.PathValue
}
2015-02-04 02:46:11 +01:00
func (ctx *BuiltinEvalContext) init() {
// We nil-check the things below because they're meant to be configured,
// and we just default them to non-nil.
if ctx.Providers == nil {
ctx.Providers = make(map[string]ResourceProviderFactory)
}
}
2015-02-09 03:00:38 +01:00
// pathCacheKey returns a cache key for the current module path, unique to
// the module path.
//
// This is used because there is a variety of information that needs to be
// cached per-path, rather than per-context.
func (ctx *BuiltinEvalContext) pathCacheKey() string {
2015-02-09 03:00:38 +01:00
// There is probably a better way to do this, but this is working for now.
// We just create an MD5 hash of all the MD5 hashes of all the path
// elements. This gets us the property that it is unique per ordering.
hash := md5.New()
for _, p := range ctx.Path() {
2015-02-09 03:00:38 +01:00
single := md5.Sum([]byte(p))
if _, err := hash.Write(single[:]); err != nil {
panic(err)
}
}
2015-02-04 02:46:11 +01:00
return hex.EncodeToString(hash.Sum(nil))
2015-02-04 02:46:11 +01:00
}