terraform: Eval
This commit is contained in:
parent
d59ced3c57
commit
012d68923c
|
@ -22,3 +22,20 @@ type EvalNode interface {
|
||||||
type GraphNodeEvalable interface {
|
type GraphNodeEvalable interface {
|
||||||
EvalTree() EvalNode
|
EvalTree() EvalNode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Eval evaluates the given EvalNode with the given context, properly
|
||||||
|
// evaluating all args in the correct order.
|
||||||
|
func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
|
||||||
|
argNodes, _ := n.Args()
|
||||||
|
args := make([]interface{}, len(argNodes))
|
||||||
|
for i, n := range argNodes {
|
||||||
|
v, err := Eval(n, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
args[i] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return n.Eval(ctx, args)
|
||||||
|
}
|
||||||
|
|
|
@ -5,12 +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
|
Providers map[string]ResourceProviderFactory
|
||||||
|
ComputeMissing bool
|
||||||
|
|
||||||
providers map[string]ResourceProvider
|
providers map[string]ResourceProvider
|
||||||
once sync.Once
|
once sync.Once
|
||||||
|
@ -37,9 +39,45 @@ func (ctx *BuiltinEvalContext) Provider(n string) ResourceProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) Interpolate(
|
func (ctx *BuiltinEvalContext) Interpolate(
|
||||||
config *config.RawConfig) (*ResourceConfig, error) {
|
cfg *config.RawConfig) (*ResourceConfig, error) {
|
||||||
// TODO: Actual interpolation, for now we just return it as-is
|
vs := make(map[string]ast.Variable)
|
||||||
return NewResourceConfig(config), nil
|
|
||||||
|
// If we don't have a config, use the blank config
|
||||||
|
if cfg == nil {
|
||||||
|
goto INTERPOLATE_RESULT
|
||||||
|
}
|
||||||
|
|
||||||
|
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.interpolateForce()
|
||||||
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *BuiltinEvalContext) init() {
|
func (ctx *BuiltinEvalContext) init() {
|
||||||
|
|
|
@ -7,3 +7,48 @@ import (
|
||||||
func TestMockEvalContext_impl(t *testing.T) {
|
func TestMockEvalContext_impl(t *testing.T) {
|
||||||
var _ EvalContext = new(MockEvalContext)
|
var _ EvalContext = new(MockEvalContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEval(t *testing.T) {
|
||||||
|
n := &testEvalAdd{
|
||||||
|
Items: []EvalNode{
|
||||||
|
&EvalLiteral{Value: 10},
|
||||||
|
&EvalLiteral{Value: 32},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := Eval(n, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != 42 {
|
||||||
|
t.Fatalf("bad: %#v", result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type testEvalAdd struct {
|
||||||
|
Items []EvalNode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *testEvalAdd) Args() ([]EvalNode, []EvalType) {
|
||||||
|
types := make([]EvalType, len(n.Items))
|
||||||
|
for i, _ := range n.Items {
|
||||||
|
types[i] = EvalTypeInvalid
|
||||||
|
}
|
||||||
|
|
||||||
|
return n.Items, types
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *testEvalAdd) Eval(
|
||||||
|
ctx EvalContext, args []interface{}) (interface{}, error) {
|
||||||
|
result := 0
|
||||||
|
for _, arg := range args {
|
||||||
|
result += arg.(int)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *testEvalAdd) Type() EvalType {
|
||||||
|
return EvalTypeInvalid
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ var RootModulePath = []string{RootModuleName}
|
||||||
type Graph struct {
|
type Graph struct {
|
||||||
// Graph is the actual DAG. This is embedded so you can call the DAG
|
// Graph is the actual DAG. This is embedded so you can call the DAG
|
||||||
// methods directly.
|
// methods directly.
|
||||||
*dag.Graph
|
dag.AcyclicGraph
|
||||||
|
|
||||||
// Path is the path in the module tree that this Graph represents.
|
// Path is the path in the module tree that this Graph represents.
|
||||||
// The root is represented by a single element list containing
|
// The root is represented by a single element list containing
|
||||||
|
@ -112,10 +112,6 @@ func (g *Graph) Dependable(n string) dag.Vertex {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Graph) init() {
|
func (g *Graph) init() {
|
||||||
if g.Graph == nil {
|
|
||||||
g.Graph = new(dag.Graph)
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.dependableMap == nil {
|
if g.dependableMap == nil {
|
||||||
g.dependableMap = make(map[string]dag.Vertex)
|
g.dependableMap = make(map[string]dag.Vertex)
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,3 +226,12 @@ func (c *ResourceConfig) interpolate(
|
||||||
c.Config = c.raw.Config()
|
c.Config = c.raw.Config()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// interpolateForce is a temporary thing. We want to get rid of interpolate
|
||||||
|
// above and likewise this, but it can only be done after the f-ast-graph
|
||||||
|
// refactor is complete.
|
||||||
|
func (c *ResourceConfig) interpolateForce() {
|
||||||
|
c.ComputedKeys = c.raw.UnknownKeys()
|
||||||
|
c.Raw = c.raw.Raw
|
||||||
|
c.Config = c.raw.Config()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue