terraform: evaluation interpolater connect

This commit is contained in:
Mitchell Hashimoto 2015-02-05 20:09:57 -05:00
parent 3908b6319a
commit de3d9fb9d9
5 changed files with 40 additions and 43 deletions

View File

@ -30,6 +30,8 @@ type Context2 struct {
module *module.Tree module *module.Tree
providers map[string]ResourceProviderFactory providers map[string]ResourceProviderFactory
state *State state *State
stateLock sync.RWMutex
variables map[string]string
} }
// NewContext creates a new Context structure. // NewContext creates a new Context structure.
@ -42,6 +44,7 @@ func NewContext2(opts *ContextOpts) *Context2 {
module: opts.Module, module: opts.Module,
providers: opts.Providers, providers: opts.Providers,
state: opts.State, state: opts.State,
variables: opts.Variables,
} }
} }
@ -71,8 +74,7 @@ func (c *Context2) Validate() ([]string, []error) {
errs = append(errs, err) errs = append(errs, err)
} }
evalCtx := c.evalContext() evalCtx := c.evalContext(walkValidate)
evalCtx.ComputeMissing = true
// Build the graph // Build the graph
graph, err := c.GraphBuilder().Build(RootModulePath) graph, err := c.GraphBuilder().Build(RootModulePath)
@ -114,8 +116,17 @@ func (c *Context2) Validate() ([]string, []error) {
return warns, errs return warns, errs
} }
func (c *Context2) evalContext() *BuiltinEvalContext { func (c *Context2) evalContext(op walkOperation) *BuiltinEvalContext {
return &BuiltinEvalContext{ return &BuiltinEvalContext{
Path: RootModulePath,
Providers: c.providers, Providers: c.providers,
Interpolater: &Interpolater{
Operation: op,
Module: c.module,
State: c.state,
StateLock: &c.stateLock,
Variables: nil,
},
} }
} }

View File

@ -162,7 +162,6 @@ func TestContext2Validate_requiredVar(t *testing.T) {
if len(w) > 0 { if len(w) > 0 {
t.Fatalf("bad: %#v", w) t.Fatalf("bad: %#v", w)
} }
// TODO: fail
if len(e) == 0 { if len(e) == 0 {
t.Fatalf("bad: %s", e) t.Fatalf("bad: %s", e)
} }

View File

@ -18,7 +18,10 @@ type EvalContext interface {
// Interpolate takes the given raw configuration and completes // Interpolate takes the given raw configuration and completes
// the interpolations, returning the processed ResourceConfig. // the interpolations, returning the processed ResourceConfig.
Interpolate(*config.RawConfig) (*ResourceConfig, error) //
// The resource argument is optional. If given, it is the resource
// that is currently being acted upon.
Interpolate(*config.RawConfig, *Resource) (*ResourceConfig, error)
} }
// MockEvalContext is a mock version of EvalContext that can be used // MockEvalContext is a mock version of EvalContext that can be used
@ -35,6 +38,7 @@ type MockEvalContext struct {
InterpolateCalled bool InterpolateCalled bool
InterpolateConfig *config.RawConfig InterpolateConfig *config.RawConfig
InterpolateResource *Resource
InterpolateConfigResult *ResourceConfig InterpolateConfigResult *ResourceConfig
InterpolateError error InterpolateError error
} }
@ -52,8 +56,9 @@ func (c *MockEvalContext) Provider(n string) ResourceProvider {
} }
func (c *MockEvalContext) Interpolate( func (c *MockEvalContext) Interpolate(
config *config.RawConfig) (*ResourceConfig, error) { config *config.RawConfig, resource *Resource) (*ResourceConfig, error) {
c.InterpolateCalled = true c.InterpolateCalled = true
c.InterpolateConfig = config c.InterpolateConfig = config
c.InterpolateResource = resource
return c.InterpolateConfigResult, c.InterpolateError return c.InterpolateConfigResult, c.InterpolateError
} }

View File

@ -5,14 +5,14 @@ import (
"sync" "sync"
"github.com/hashicorp/terraform/config" "github.com/hashicorp/terraform/config"
"github.com/hashicorp/terraform/config/lang/ast"
) )
// BuiltinEvalContext is an EvalContext implementation that is used by // BuiltinEvalContext is an EvalContext implementation that is used by
// Terraform by default. // Terraform by default.
type BuiltinEvalContext struct { type BuiltinEvalContext struct {
Providers map[string]ResourceProviderFactory Path []string
ComputeMissing bool Interpolater *Interpolater
Providers map[string]ResourceProviderFactory
providers map[string]ResourceProvider providers map[string]ResourceProvider
once sync.Once once sync.Once
@ -45,42 +45,23 @@ func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
} }
func (ctx *BuiltinEvalContext) Interpolate( func (ctx *BuiltinEvalContext) Interpolate(
cfg *config.RawConfig) (*ResourceConfig, error) { cfg *config.RawConfig, r *Resource) (*ResourceConfig, error) {
vs := make(map[string]ast.Variable) if cfg != nil {
scope := &InterpolationScope{
Path: ctx.Path,
Resource: r,
}
vs, err := ctx.Interpolater.Values(scope, cfg.Variables)
if err != nil {
return nil, err
}
// If we don't have a config, use the blank config // Do the interpolation
if cfg == nil { if err := cfg.Interpolate(vs); err != nil {
goto INTERPOLATE_RESULT return nil, err
}
for n, rawV := range cfg.Variables {
switch rawV.(type) {
case *config.ModuleVariable:
if ctx.ComputeMissing {
vs[n] = ast.Variable{
Value: config.UnknownVariableValue,
Type: ast.TypeString,
}
}
case *config.ResourceVariable:
if ctx.ComputeMissing {
vs[n] = ast.Variable{
Value: config.UnknownVariableValue,
Type: ast.TypeString,
}
}
default:
return nil, fmt.Errorf(
"unknown interpolation type: %#v", rawV)
} }
} }
// Do the interpolation
if err := cfg.Interpolate(vs); err != nil {
return nil, err
}
INTERPOLATE_RESULT:
result := NewResourceConfig(cfg) result := NewResourceConfig(cfg)
result.interpolateForce() result.interpolateForce()
return result, nil return result, nil

View File

@ -7,7 +7,8 @@ import (
// EvalInterpolate is an EvalNode implementation that takes a raw // EvalInterpolate is an EvalNode implementation that takes a raw
// configuration and interpolates it. // configuration and interpolates it.
type EvalInterpolate struct { type EvalInterpolate struct {
Config *config.RawConfig Config *config.RawConfig
Resource *Resource
} }
func (n *EvalInterpolate) Args() ([]EvalNode, []EvalType) { func (n *EvalInterpolate) Args() ([]EvalNode, []EvalType) {
@ -16,7 +17,7 @@ func (n *EvalInterpolate) Args() ([]EvalNode, []EvalType) {
func (n *EvalInterpolate) Eval( func (n *EvalInterpolate) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) { ctx EvalContext, args []interface{}) (interface{}, error) {
return ctx.Interpolate(n.Config) return ctx.Interpolate(n.Config, n.Resource)
} }
func (n *EvalInterpolate) Type() EvalType { func (n *EvalInterpolate) Type() EvalType {