terraform: clean up EvalNodes

This commit is contained in:
Mitchell Hashimoto 2015-02-13 22:58:41 -08:00
parent af1778cd5e
commit b52881d232
28 changed files with 222 additions and 567 deletions

View File

@ -7,18 +7,10 @@ import (
// EvalNode is the interface that must be implemented by graph nodes to
// evaluate/execute.
type EvalNode interface {
// Args returns the arguments for this node as well as the list of
// expected types. The expected types are only used for type checking
// and not used at runtime.
Args() ([]EvalNode, []EvalType)
// Eval evaluates this node with the given context. The second parameter
// are the argument values. These will match in order and 1-1 with the
// results of the Args() return value.
Eval(EvalContext, []interface{}) (interface{}, error)
// Type returns the type that will be returned by this node.
Type() EvalType
Eval(EvalContext) (interface{}, error)
}
// GraphNodeEvalable is the interface that graph nodes must implement
@ -51,19 +43,8 @@ func Eval(n EvalNode, ctx EvalContext) (interface{}, error) {
// EvalRaw is like Eval except that it returns all errors, even if they
// signal something normal such as EvalEarlyExitError.
func EvalRaw(n EvalNode, ctx EvalContext) (interface{}, error) {
argNodes, _ := n.Args()
args := make([]interface{}, len(argNodes))
for i, n := range argNodes {
v, err := EvalRaw(n, ctx)
if err != nil {
return nil, err
}
args[i] = v
}
log.Printf("[DEBUG] eval: %T", n)
output, err := n.Eval(ctx, args)
output, err := n.Eval(ctx)
if err != nil {
log.Printf("[ERROR] eval: %T, err: %s", n, err)
}

View File

@ -21,13 +21,8 @@ type EvalApply struct {
Error *error
}
func (n *EvalApply) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalApply) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
diff := *n.Diff
provider := *n.Provider
state := *n.State
@ -108,10 +103,6 @@ func (n *EvalApply) Eval(
return nil, nil
}
func (n *EvalApply) Type() EvalType {
return EvalTypeNull
}
// EvalApplyPost is an EvalNode implementation that does the post-Apply work
type EvalApplyPost struct {
Info *InstanceInfo
@ -119,13 +110,8 @@ type EvalApplyPost struct {
Error *error
}
func (n *EvalApplyPost) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalApplyPost) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalApplyPost) Eval(ctx EvalContext) (interface{}, error) {
state := *n.State
{
@ -141,10 +127,6 @@ func (n *EvalApplyPost) Eval(
return nil, *n.Error
}
func (n *EvalApplyPost) Type() EvalType {
return EvalTypeNull
}
// EvalApplyProvisioners is an EvalNode implementation that executes
// the provisioners for a resource.
//
@ -160,13 +142,8 @@ type EvalApplyProvisioners struct {
Error *error
}
func (n *EvalApplyProvisioners) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalApplyProvisioners) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalApplyProvisioners) Eval(ctx EvalContext) (interface{}, error) {
state := *n.State
if !*n.CreateNew {
@ -226,10 +203,6 @@ func (n *EvalApplyProvisioners) Eval(
return nil, nil
}
func (n *EvalApplyProvisioners) Type() EvalType {
return EvalTypeNull
}
func (n *EvalApplyProvisioners) apply(ctx EvalContext) error {
state := *n.State

View File

@ -11,13 +11,8 @@ type EvalCountFixZeroOneBoundary struct {
Resource *config.Resource
}
func (n *EvalCountFixZeroOneBoundary) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalCountFixZeroOneBoundary) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalCountFixZeroOneBoundary) Eval(ctx EvalContext) (interface{}, error) {
// Get the count, important for knowing whether we're supposed to
// be adding the zero, or trimming it.
count, err := n.Resource.Count()
@ -53,7 +48,3 @@ func (n *EvalCountFixZeroOneBoundary) Eval(
return nil, nil
}
func (n *EvalCountFixZeroOneBoundary) Type() EvalType {
return EvalTypeNull
}

View File

@ -12,13 +12,8 @@ type EvalCompareDiff struct {
One, Two **InstanceDiff
}
func (n *EvalCompareDiff) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalCompareDiff) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalCompareDiff) Eval(ctx EvalContext) (interface{}, error) {
one, two := *n.One, *n.Two
// If either are nil, let them be empty
@ -55,37 +50,22 @@ func (n *EvalCompareDiff) Eval(
return nil, nil
}
func (n *EvalCompareDiff) Type() EvalType {
return EvalTypeNull
}
// EvalDiff is an EvalNode implementation that does a refresh for
// a resource.
type EvalDiff struct {
Info *InstanceInfo
Config EvalNode
Provider EvalNode
State EvalNode
Config **ResourceConfig
Provider *ResourceProvider
State **InstanceState
Output **InstanceDiff
OutputState **InstanceState
}
func (n *EvalDiff) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Config, n.Provider, n.State},
[]EvalType{EvalTypeConfig, EvalTypeResourceProvider,
EvalTypeInstanceState}
}
// TODO: test
func (n *EvalDiff) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
// Extract our arguments
var state *InstanceState
config := args[0].(*ResourceConfig)
provider := args[1].(ResourceProvider)
if args[2] != nil {
state = args[2].(*InstanceState)
}
func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
state := *n.State
config := *n.Config
provider := *n.Provider
// Call pre-diff hook
err := ctx.Hook(func(h Hook) (HookAction, error) {
@ -154,33 +134,20 @@ func (n *EvalDiff) Eval(
}
}
return state, nil
}
func (n *EvalDiff) Type() EvalType {
return EvalTypeInstanceState
return nil, nil
}
// EvalDiffDestroy is an EvalNode implementation that returns a plain
// destroy diff.
type EvalDiffDestroy struct {
Info *InstanceInfo
State EvalNode
State **InstanceState
Output **InstanceDiff
}
func (n *EvalDiffDestroy) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.State}, []EvalType{EvalTypeInstanceState}
}
// TODO: test
func (n *EvalDiffDestroy) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
// Extract our arguments
var state *InstanceState
if args[0] != nil {
state = args[0].(*InstanceState)
}
func (n *EvalDiffDestroy) Eval(ctx EvalContext) (interface{}, error) {
state := *n.State
// If there is no state or we don't have an ID, we're already destroyed
if state == nil || state.ID == "" {
@ -212,23 +179,14 @@ func (n *EvalDiffDestroy) Eval(
return nil, nil
}
func (n *EvalDiffDestroy) Type() EvalType {
return EvalTypeNull
}
// EvalDiffDestroyModule is an EvalNode implementation that writes the diff to
// the full diff.
type EvalDiffDestroyModule struct {
Path []string
}
func (n *EvalDiffDestroyModule) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalDiffDestroyModule) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalDiffDestroyModule) Eval(ctx EvalContext) (interface{}, error) {
diff, lock := ctx.Diff()
// Acquire the lock so that we can do this safely concurrently
@ -245,10 +203,6 @@ func (n *EvalDiffDestroyModule) Eval(
return nil, nil
}
func (n *EvalDiffDestroyModule) Type() EvalType {
return EvalTypeNull
}
// EvalDiffTainted is an EvalNode implementation that writes the diff to
// the full diff.
type EvalDiffTainted struct {
@ -256,13 +210,8 @@ type EvalDiffTainted struct {
Diff **InstanceDiff
}
func (n *EvalDiffTainted) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalDiffTainted) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalDiffTainted) Eval(ctx EvalContext) (interface{}, error) {
state, lock := ctx.State()
// Get a read lock so we can access this instance
@ -289,10 +238,6 @@ func (n *EvalDiffTainted) Eval(
return nil, nil
}
func (n *EvalDiffTainted) Type() EvalType {
return EvalTypeNull
}
// EvalReadDiff is an EvalNode implementation that writes the diff to
// the full diff.
type EvalReadDiff struct {
@ -300,13 +245,7 @@ type EvalReadDiff struct {
Diff **InstanceDiff
}
func (n *EvalReadDiff) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalReadDiff) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalReadDiff) Eval(ctx EvalContext) (interface{}, error) {
diff, lock := ctx.Diff()
// Acquire the lock so that we can do this safely concurrently
@ -324,10 +263,6 @@ func (n *EvalReadDiff) Eval(
return nil, nil
}
func (n *EvalReadDiff) Type() EvalType {
return EvalTypeNull
}
// EvalWriteDiff is an EvalNode implementation that writes the diff to
// the full diff.
type EvalWriteDiff struct {
@ -335,13 +270,8 @@ type EvalWriteDiff struct {
Diff **InstanceDiff
}
func (n *EvalWriteDiff) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalWriteDiff) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
diff, lock := ctx.Diff()
// The diff to write, if its empty it should write nil
@ -367,7 +297,3 @@ func (n *EvalWriteDiff) Eval(
return nil, nil
}
func (n *EvalWriteDiff) Type() EvalType {
return EvalTypeNull
}

View File

@ -32,18 +32,9 @@ type EvalOpFilter struct {
Node EvalNode
}
func (n *EvalOpFilter) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Node}, []EvalType{n.Node.Type()}
}
// TODO: test
func (n *EvalOpFilter) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
return args[0], nil
}
func (n *EvalOpFilter) Type() EvalType {
return n.Node.Type()
func (n *EvalOpFilter) Eval(ctx EvalContext) (interface{}, error) {
return EvalRaw(n.Node, ctx)
}
// EvalNodeOpFilterable impl.

View File

@ -6,13 +6,8 @@ type EvalIf struct {
Node EvalNode
}
func (n *EvalIf) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalIf) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalIf) Eval(ctx EvalContext) (interface{}, error) {
yes, err := n.If(ctx)
if err != nil {
return nil, err
@ -24,7 +19,3 @@ func (n *EvalIf) Eval(
return nil, nil
}
func (n *EvalIf) Type() EvalType {
return EvalTypeNull
}

View File

@ -9,17 +9,18 @@ import (
type EvalInterpolate struct {
Config *config.RawConfig
Resource *Resource
Output **ResourceConfig
}
func (n *EvalInterpolate) Eval(ctx EvalContext) (interface{}, error) {
rc, err := ctx.Interpolate(n.Config, n.Resource)
if err != nil {
return nil, err
}
if n.Output != nil {
*n.Output = rc
}
func (n *EvalInterpolate) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalInterpolate) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
return ctx.Interpolate(n.Config, n.Resource)
}
func (n *EvalInterpolate) Type() EvalType {
return EvalTypeConfig
}

View File

@ -17,12 +17,14 @@ func TestEvalInterpolate(t *testing.T) {
t.Fatalf("err: %s", err)
}
n := &EvalInterpolate{Config: config}
var actual *ResourceConfig
n := &EvalInterpolate{Config: config, Output: &actual}
result := testResourceConfig(t, map[string]interface{}{})
ctx := &MockEvalContext{InterpolateConfigResult: result}
if actual, err := n.Eval(ctx, nil); err != nil {
if _, err := n.Eval(ctx); err != nil {
t.Fatalf("err: %s", err)
} else if actual != result {
}
if actual != result {
t.Fatalf("bad: %#v", actual)
}

View File

@ -1,20 +0,0 @@
package terraform
// EvalLiteral is an EvalNode implementation that returns a literal
// value. This is very useful for testing as well as in practice.
type EvalLiteral struct {
Value interface{}
ValueType EvalType
}
func (n *EvalLiteral) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalLiteral) Eval(EvalContext, []interface{}) (interface{}, error) {
return n.Value, nil
}
func (n *EvalLiteral) Type() EvalType {
return n.ValueType
}

View File

@ -1,27 +0,0 @@
package terraform
import (
"testing"
)
func TestEvalLiteral_impl(t *testing.T) {
var _ EvalNode = new(EvalLiteral)
}
func TestEvalLiteralEval(t *testing.T) {
n := &EvalLiteral{Value: 42}
actual, err := n.Eval(nil, nil)
if err != nil {
t.Fatalf("err: %s", err)
}
if actual != 42 {
t.Fatalf("bad: %#v", actual)
}
}
func TestEvalLiteralType(t *testing.T) {
n := &EvalLiteral{Value: 42, ValueType: EvalTypeConfig}
if actual := n.Type(); actual != EvalTypeConfig {
t.Fatalf("bad: %#v", actual)
}
}

View File

@ -3,8 +3,6 @@ package terraform
// EvalNoop is an EvalNode that does nothing.
type EvalNoop struct{}
func (EvalNoop) Args() ([]EvalNode, []EvalType) { return nil, nil }
func (EvalNoop) Eval(EvalContext, []interface{}) (interface{}, error) {
func (EvalNoop) Eval(EvalContext) (interface{}, error) {
return nil, nil
}
func (EvalNoop) Type() EvalType { return EvalTypeNull }

View File

@ -13,13 +13,8 @@ type EvalWriteOutput struct {
Value *config.RawConfig
}
func (n *EvalWriteOutput) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalWriteOutput) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
cfg, err := ctx.Interpolate(n.Value, nil)
if err != nil {
// Ignore it
@ -66,7 +61,3 @@ func (n *EvalWriteOutput) Eval(
return nil, nil
}
func (n *EvalWriteOutput) Type() EvalType {
return EvalTypeNull
}

View File

@ -10,16 +10,11 @@ import (
// a provider that is already initialized and retrieved.
type EvalConfigProvider struct {
Provider string
Config EvalNode
Config **ResourceConfig
}
func (n *EvalConfigProvider) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Config}, []EvalType{EvalTypeConfig}
}
func (n *EvalConfigProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
cfg := args[0].(*ResourceConfig)
func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) {
cfg := *n.Config
// If we have a configuration set, then use that
if input := ctx.ProviderInput(n.Provider); input != nil {
@ -41,10 +36,6 @@ func (n *EvalConfigProvider) Eval(
return nil, ctx.ConfigureProvider(n.Provider, cfg)
}
func (n *EvalConfigProvider) Type() EvalType {
return EvalTypeNull
}
// EvalInitProvider is an EvalNode implementation that initializes a provider
// and returns nothing. The provider can be retrieved again with the
// EvalGetProvider node.
@ -52,19 +43,10 @@ type EvalInitProvider struct {
Name string
}
func (n *EvalInitProvider) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalInitProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) {
return ctx.InitProvider(n.Name)
}
func (n *EvalInitProvider) Type() EvalType {
return EvalTypeNull
}
// EvalGetProvider is an EvalNode implementation that retrieves an already
// initialized provider instance for the given name.
type EvalGetProvider struct {
@ -72,12 +54,7 @@ type EvalGetProvider struct {
Output *ResourceProvider
}
func (n *EvalGetProvider) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalGetProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) {
result := ctx.Provider(n.Name)
if result == nil {
return nil, fmt.Errorf("provider %s not initialized", n.Name)
@ -87,11 +64,7 @@ func (n *EvalGetProvider) Eval(
*n.Output = result
}
return result, nil
}
func (n *EvalGetProvider) Type() EvalType {
return EvalTypeResourceProvider
return nil, nil
}
// EvalInputProvider is an EvalNode implementation that asks for input
@ -102,12 +75,7 @@ type EvalInputProvider struct {
Config *config.RawConfig
}
func (n *EvalInputProvider) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalInputProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalInputProvider) Eval(ctx EvalContext) (interface{}, error) {
// If we already configured this provider, then don't do this again
if v := ctx.ProviderInput(n.Name); v != nil {
return nil, nil
@ -138,7 +106,3 @@ func (n *EvalInputProvider) Eval(
return nil, nil
}
func (n *EvalInputProvider) Type() EvalType {
return EvalTypeNull
}

View File

@ -12,14 +12,11 @@ func TestEvalConfigProvider_impl(t *testing.T) {
func TestEvalConfigProvider(t *testing.T) {
config := testResourceConfig(t, map[string]interface{}{})
provider := &MockResourceProvider{}
n := &EvalConfigProvider{}
n := &EvalConfigProvider{Config: &config}
ctx := &MockEvalContext{ProviderProvider: provider}
args := []interface{}{config}
if actual, err := n.Eval(ctx, args); err != nil {
if _, err := n.Eval(ctx); err != nil {
t.Fatalf("err: %s", err)
} else if actual != nil {
t.Fatalf("bad: %#v", actual)
}
if !ctx.ConfigureProviderCalled {
@ -30,22 +27,6 @@ func TestEvalConfigProvider(t *testing.T) {
}
}
func TestEvalConfigProvider_args(t *testing.T) {
config := testResourceConfig(t, map[string]interface{}{})
configNode := &EvalLiteral{Value: config}
n := &EvalConfigProvider{Provider: "foo", Config: configNode}
args, types := n.Args()
expectedArgs := []EvalNode{configNode}
expectedTypes := []EvalType{EvalTypeConfig}
if !reflect.DeepEqual(args, expectedArgs) {
t.Fatalf("bad: %#v", args)
}
if !reflect.DeepEqual(types, expectedTypes) {
t.Fatalf("bad: %#v", args)
}
}
func TestEvalInitProvider_impl(t *testing.T) {
var _ EvalNode = new(EvalInitProvider)
}
@ -54,10 +35,8 @@ func TestEvalInitProvider(t *testing.T) {
n := &EvalInitProvider{Name: "foo"}
provider := &MockResourceProvider{}
ctx := &MockEvalContext{InitProviderProvider: provider}
if actual, err := n.Eval(ctx, nil); err != nil {
if _, err := n.Eval(ctx); err != nil {
t.Fatalf("err: %s", err)
} else if actual != provider {
t.Fatalf("bad: %#v", actual)
}
if !ctx.InitProviderCalled {
@ -73,12 +52,14 @@ func TestEvalGetProvider_impl(t *testing.T) {
}
func TestEvalGetProvider(t *testing.T) {
n := &EvalGetProvider{Name: "foo"}
var actual ResourceProvider
n := &EvalGetProvider{Name: "foo", Output: &actual}
provider := &MockResourceProvider{}
ctx := &MockEvalContext{ProviderProvider: provider}
if actual, err := n.Eval(ctx, nil); err != nil {
if _, err := n.Eval(ctx); err != nil {
t.Fatalf("err: %s", err)
} else if actual != provider {
}
if actual != provider {
t.Fatalf("bad: %#v", actual)
}

View File

@ -11,39 +11,26 @@ type EvalInitProvisioner struct {
Name string
}
func (n *EvalInitProvisioner) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalInitProvisioner) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalInitProvisioner) Eval(ctx EvalContext) (interface{}, error) {
return ctx.InitProvisioner(n.Name)
}
func (n *EvalInitProvisioner) Type() EvalType {
return EvalTypeNull
}
// EvalGetProvisioner is an EvalNode implementation that retrieves an already
// initialized provisioner instance for the given name.
type EvalGetProvisioner struct {
Name string
Output *ResourceProvisioner
}
func (n *EvalGetProvisioner) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
func (n *EvalGetProvisioner) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalGetProvisioner) Eval(ctx EvalContext) (interface{}, error) {
result := ctx.Provisioner(n.Name)
if result == nil {
return nil, fmt.Errorf("provisioner %s not initialized", n.Name)
}
return result, nil
if n.Output != nil {
*n.Output = result
}
func (n *EvalGetProvisioner) Type() EvalType {
return EvalTypeResourceProvisioner
return result, nil
}

View File

@ -12,10 +12,8 @@ func TestEvalInitProvisioner(t *testing.T) {
n := &EvalInitProvisioner{Name: "foo"}
provisioner := &MockResourceProvisioner{}
ctx := &MockEvalContext{InitProvisionerProvisioner: provisioner}
if actual, err := n.Eval(ctx, nil); err != nil {
if _, err := n.Eval(ctx); err != nil {
t.Fatalf("err: %s", err)
} else if actual != provisioner {
t.Fatalf("bad: %#v", actual)
}
if !ctx.InitProvisionerCalled {
@ -31,12 +29,14 @@ func TestEvalGetProvisioner_impl(t *testing.T) {
}
func TestEvalGetProvisioner(t *testing.T) {
n := &EvalGetProvisioner{Name: "foo"}
var actual ResourceProvisioner
n := &EvalGetProvisioner{Name: "foo", Output: &actual}
provisioner := &MockResourceProvisioner{}
ctx := &MockEvalContext{ProvisionerProvisioner: provisioner}
if actual, err := n.Eval(ctx, nil); err != nil {
if _, err := n.Eval(ctx); err != nil {
t.Fatalf("err: %s", err)
} else if actual != provisioner {
}
if actual != provisioner {
t.Fatalf("bad: %#v", actual)
}

View File

@ -7,20 +7,15 @@ import (
// EvalRefresh is an EvalNode implementation that does a refresh for
// a resource.
type EvalRefresh struct {
Provider EvalNode
Provider *ResourceProvider
State **InstanceState
Info *InstanceInfo
Output **InstanceState
}
func (n *EvalRefresh) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Provider}, []EvalType{EvalTypeResourceProvider}
}
// TODO: test
func (n *EvalRefresh) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
provider := args[0].(ResourceProvider)
func (n *EvalRefresh) Eval(ctx EvalContext) (interface{}, error) {
provider := *n.Provider
state := *n.State
// If we have no state, we don't do any refreshing
@ -54,9 +49,6 @@ func (n *EvalRefresh) Eval(
if n.Output != nil {
*n.Output = state
}
return state, nil
}
func (n *EvalRefresh) Type() EvalType {
return EvalTypeInstanceState
return nil, nil
}

View File

@ -6,17 +6,8 @@ type EvalInstanceInfo struct {
Info *InstanceInfo
}
func (n *EvalInstanceInfo) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalInstanceInfo) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalInstanceInfo) Eval(ctx EvalContext) (interface{}, error) {
n.Info.ModulePath = ctx.Path()
return nil, nil
}
func (n *EvalInstanceInfo) Type() EvalType {
return EvalTypeNull
}

View File

@ -5,33 +5,16 @@ type EvalSequence struct {
Nodes []EvalNode
}
func (n *EvalSequence) Args() ([]EvalNode, []EvalType) {
types := make([]EvalType, len(n.Nodes))
for i, n := range n.Nodes {
types[i] = n.Type()
func (n *EvalSequence) Eval(ctx EvalContext) (interface{}, error) {
for _, n := range n.Nodes {
if _, err := EvalRaw(n, ctx); err != nil {
return nil, err
}
}
return n.Nodes, types
}
func (n *EvalSequence) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
// TODO: test
if len(args) == 0 {
return nil, nil
}
return args[len(args)-1], nil
}
func (n *EvalSequence) Type() EvalType {
if len(n.Nodes) == 0 {
return EvalTypeNull
}
return n.Nodes[len(n.Nodes)-1].Type()
}
// EvalNodeFilterable impl.
func (n *EvalSequence) Filter(fn EvalNodeFilterFunc) {
for i, node := range n.Nodes {

View File

@ -13,13 +13,8 @@ type EvalReadState struct {
Output **InstanceState
}
func (n *EvalReadState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalReadState) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
state, lock := ctx.State()
// Get a read lock so we can access this instance
@ -63,10 +58,6 @@ func (n *EvalReadState) Eval(
return result, nil
}
func (n *EvalReadState) Type() EvalType {
return EvalTypeInstanceState
}
// EvalWriteState is an EvalNode implementation that reads the
// InstanceState for a specific resource out of the state.
type EvalWriteState struct {
@ -79,13 +70,8 @@ type EvalWriteState struct {
TaintedClearPrimary bool
}
func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalWriteState) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
state, lock := ctx.State()
if state == nil {
return nil, fmt.Errorf("cannot write state to nil state")
@ -130,10 +116,6 @@ func (n *EvalWriteState) Eval(
return nil, nil
}
func (n *EvalWriteState) Type() EvalType {
return EvalTypeNull
}
// EvalDeposeState is an EvalNode implementation that takes the primary
// out of a state and makes it tainted. This is done at the beggining of
// create-before-destroy calls so that the create can create while preserving
@ -142,13 +124,8 @@ type EvalDeposeState struct {
Name string
}
func (n *EvalDeposeState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalDeposeState) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalDeposeState) Eval(ctx EvalContext) (interface{}, error) {
state, lock := ctx.State()
// Get a read lock so we can access this instance
@ -179,23 +156,14 @@ func (n *EvalDeposeState) Eval(
return nil, nil
}
func (n *EvalDeposeState) Type() EvalType {
return EvalTypeNull
}
// EvalUndeposeState is an EvalNode implementation that reads the
// InstanceState for a specific resource out of the state.
type EvalUndeposeState struct {
Name string
}
func (n *EvalUndeposeState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalUndeposeState) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalUndeposeState) Eval(ctx EvalContext) (interface{}, error) {
state, lock := ctx.State()
// Get a read lock so we can access this instance
@ -226,7 +194,3 @@ func (n *EvalUndeposeState) Eval(
return nil, nil
}
func (n *EvalUndeposeState) Type() EvalType {
return EvalTypeNull
}

View File

@ -9,15 +9,13 @@ func TestMockEvalContext_impl(t *testing.T) {
}
func TestEval(t *testing.T) {
var result int
n := &testEvalAdd{
Items: []EvalNode{
&EvalLiteral{Value: 10},
&EvalLiteral{Value: 32},
},
Items: []int{10, 32},
Result: &result,
}
result, err := Eval(n, nil)
if err != nil {
if _, err := Eval(n, nil); err != nil {
t.Fatalf("err: %s", err)
}
@ -27,28 +25,16 @@ func TestEval(t *testing.T) {
}
type testEvalAdd struct {
Items []EvalNode
Items []int
Result *int
}
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) {
func (n *testEvalAdd) Eval(ctx EvalContext) (interface{}, error) {
result := 0
for _, arg := range args {
result += arg.(int)
for _, item := range n.Items {
result += item
}
return result, nil
}
func (n *testEvalAdd) Type() EvalType {
return EvalTypeInvalid
*n.Result = result
return nil, nil
}

View File

@ -23,13 +23,8 @@ type EvalValidateCount struct {
Resource *config.Resource
}
func (n *EvalValidateCount) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalValidateCount) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalValidateCount) Eval(ctx EvalContext) (interface{}, error) {
var count int
var errs []error
var err error
@ -59,27 +54,17 @@ RETURN:
}
}
func (n *EvalValidateCount) Type() EvalType {
return EvalTypeNull
}
// EvalValidateProvider is an EvalNode implementation that validates
// the configuration of a resource.
type EvalValidateProvider struct {
ProviderName string
Provider EvalNode
Config EvalNode
Provider *ResourceProvider
Config **ResourceConfig
}
func (n *EvalValidateProvider) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Provider, n.Config},
[]EvalType{EvalTypeResourceProvider, EvalTypeConfig}
}
func (n *EvalValidateProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
provider := args[0].(ResourceProvider)
config := args[1].(*ResourceConfig)
func (n *EvalValidateProvider) Eval(ctx EvalContext) (interface{}, error) {
provider := *n.Provider
config := *n.Config
// Get the parent configuration if there is one
if parent := ctx.ParentProviderConfig(n.ProviderName); parent != nil {
@ -98,27 +83,17 @@ func (n *EvalValidateProvider) Eval(
}
}
func (n *EvalValidateProvider) Type() EvalType {
return EvalTypeNull
}
// EvalValidateProvisioner is an EvalNode implementation that validates
// the configuration of a resource.
type EvalValidateProvisioner struct {
Provisioner EvalNode
Config EvalNode
Provisioner *ResourceProvisioner
Config **ResourceConfig
}
func (n *EvalValidateProvisioner) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Provisioner, n.Config},
[]EvalType{EvalTypeResourceProvisioner, EvalTypeConfig}
}
func (n *EvalValidateProvisioner) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
provider := args[0].(ResourceProvisioner)
config := args[1].(*ResourceConfig)
warns, errs := provider.Validate(config)
func (n *EvalValidateProvisioner) Eval(ctx EvalContext) (interface{}, error) {
provisioner := *n.Provisioner
config := *n.Config
warns, errs := provisioner.Validate(config)
if len(warns) == 0 && len(errs) == 0 {
return nil, nil
}
@ -129,30 +104,20 @@ func (n *EvalValidateProvisioner) Eval(
}
}
func (n *EvalValidateProvisioner) Type() EvalType {
return EvalTypeNull
}
// EvalValidateResource is an EvalNode implementation that validates
// the configuration of a resource.
type EvalValidateResource struct {
Provider EvalNode
Config EvalNode
Provider *ResourceProvider
Config **ResourceConfig
ResourceName string
ResourceType string
}
func (n *EvalValidateResource) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Provider, n.Config},
[]EvalType{EvalTypeResourceProvider, EvalTypeConfig}
}
func (n *EvalValidateResource) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalValidateResource) Eval(ctx EvalContext) (interface{}, error) {
// TODO: test
provider := args[0].(ResourceProvider)
cfg := args[1].(*ResourceConfig)
provider := *n.Provider
cfg := *n.Config
warns, errs := provider.ValidateResource(n.ResourceType, cfg)
// If the resouce name doesn't match the name regular
@ -174,7 +139,3 @@ func (n *EvalValidateResource) Eval(
Errors: errs,
}
}
func (n *EvalValidateResource) Type() EvalType {
return EvalTypeNull
}

View File

@ -10,43 +10,29 @@ type EvalSetVariables struct {
Variables map[string]string
}
func (n *EvalSetVariables) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test
func (n *EvalSetVariables) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalSetVariables) Eval(ctx EvalContext) (interface{}, error) {
ctx.SetVariables(n.Variables)
return nil, nil
}
func (n *EvalSetVariables) Type() EvalType {
return EvalTypeNull
}
// EvalVariableBlock is an EvalNode implementation that evaluates the
// given configuration, and uses the final values as a way to set the
// mapping.
type EvalVariableBlock struct {
Config EvalNode
Config **ResourceConfig
Variables map[string]string
}
func (n *EvalVariableBlock) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Config}, []EvalType{EvalTypeConfig}
}
// TODO: test
func (n *EvalVariableBlock) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
func (n *EvalVariableBlock) Eval(ctx EvalContext) (interface{}, error) {
// Clear out the existing mapping
for k, _ := range n.Variables {
delete(n.Variables, k)
}
// Get our configuration
rc := args[0].(*ResourceConfig)
rc := *n.Config
for k, v := range rc.Config {
n.Variables[k] = v.(string)
}
@ -58,7 +44,3 @@ func (n *EvalVariableBlock) Eval(
return nil, nil
}
func (n *EvalVariableBlock) Type() EvalType {
return EvalTypeNull
}

View File

@ -7,11 +7,13 @@ import (
// ProviderEvalTree returns the evaluation tree for initializing and
// configuring providers.
func ProviderEvalTree(n string, config *config.RawConfig) EvalNode {
var provider ResourceProvider
var resourceConfig *ResourceConfig
seq := make([]EvalNode, 0, 5)
seq = append(seq, &EvalInitProvider{Name: n})
// Input stuff
var provider ResourceProvider
seq = append(seq, &EvalOpFilter{
Ops: []walkOperation{walkInput},
Node: &EvalSequence{
@ -34,14 +36,22 @@ func ProviderEvalTree(n string, config *config.RawConfig) EvalNode {
Ops: []walkOperation{walkValidate, walkRefresh, walkPlan, walkApply},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalGetProvider{
Name: n,
Output: &provider,
},
&EvalInterpolate{
Config: config,
Output: &resourceConfig,
},
&EvalValidateProvider{
ProviderName: n,
Provider: &EvalGetProvider{Name: n},
Config: &EvalInterpolate{Config: config},
Provider: &provider,
Config: &resourceConfig,
},
&EvalConfigProvider{
Provider: n,
Config: &EvalInterpolate{Config: config},
Config: &resourceConfig,
},
},
},

View File

@ -359,10 +359,16 @@ func (n *graphNodeModuleExpanded) Name() string {
// GraphNodeEvalable impl.
func (n *graphNodeModuleExpanded) EvalTree() EvalNode {
var resourceConfig *ResourceConfig
return &EvalSequence{
Nodes: []EvalNode{
&EvalInterpolate{
Config: n.InputConfig,
Output: &resourceConfig,
},
&EvalVariableBlock{
Config: &EvalInterpolate{Config: n.InputConfig},
Config: &resourceConfig,
Variables: n.Variables,
},

View File

@ -171,6 +171,7 @@ func (n *graphNodeOrphanResource) ProvidedBy() []string {
// GraphNodeEvalable impl.
func (n *graphNodeOrphanResource) EvalTree() EvalNode {
var provider ResourceProvider
var state *InstanceState
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
@ -184,13 +185,17 @@ func (n *graphNodeOrphanResource) EvalTree() EvalNode {
Ops: []walkOperation{walkRefresh},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalGetProvider{
Name: n.ProvidedBy()[0],
Output: &provider,
},
&EvalReadState{
Name: n.ResourceName,
Output: &state,
},
&EvalRefresh{
Info: info,
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
Provider: &provider,
State: &state,
Output: &state,
},
@ -210,9 +215,13 @@ func (n *graphNodeOrphanResource) EvalTree() EvalNode {
Ops: []walkOperation{walkPlan, walkPlanDestroy},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalReadState{
Name: n.ResourceName,
Output: &state,
},
&EvalDiffDestroy{
Info: info,
State: &EvalReadState{Name: n.ResourceName},
State: &state,
Output: &diff,
},
&EvalWriteDiff{
@ -224,7 +233,6 @@ func (n *graphNodeOrphanResource) EvalTree() EvalNode {
})
// Apply
var provider ResourceProvider
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
Ops: []walkOperation{walkApply},
Node: &EvalSequence{

View File

@ -99,6 +99,8 @@ func (n *graphNodeExpandedResource) ProvidedBy() []string {
// GraphNodeEvalable impl.
func (n *graphNodeExpandedResource) EvalTree() EvalNode {
var diff *InstanceDiff
var provider ResourceProvider
var resourceConfig *ResourceConfig
var state *InstanceState
// Build the resource. If we aren't part of a multi-resource, then
@ -109,29 +111,35 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
}
resource := &Resource{CountIndex: index}
// Shared node for interpolation of configuration
interpolateNode := &EvalInterpolate{
Config: n.Resource.RawConfig,
Resource: resource,
}
seq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
// Validate the resource
vseq := &EvalSequence{Nodes: make([]EvalNode, 0, 5)}
vseq.Nodes = append(vseq.Nodes, &EvalGetProvider{
Name: n.ProvidedBy()[0],
Output: &provider,
})
vseq.Nodes = append(vseq.Nodes, &EvalInterpolate{
Config: n.Resource.RawConfig,
Resource: resource,
Output: &resourceConfig,
})
vseq.Nodes = append(vseq.Nodes, &EvalValidateResource{
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
Config: interpolateNode,
Provider: &provider,
Config: &resourceConfig,
ResourceName: n.Resource.Name,
ResourceType: n.Resource.Type,
})
// Validate all the provisioners
for _, p := range n.Resource.Provisioners {
vseq.Nodes = append(vseq.Nodes, &EvalValidateProvisioner{
Provisioner: &EvalGetProvisioner{Name: p.Type},
Config: &EvalInterpolate{
Config: p.RawConfig, Resource: resource},
var provisioner ResourceProvisioner
vseq.Nodes = append(vseq.Nodes, &EvalGetProvisioner{
Name: p.Type,
Output: &provisioner,
}, &EvalValidateProvisioner{
Provisioner: &provisioner,
Config: &resourceConfig,
})
}
@ -150,13 +158,17 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Ops: []walkOperation{walkRefresh},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalGetProvider{
Name: n.ProvidedBy()[0],
Output: &provider,
},
&EvalReadState{
Name: n.stateId(),
Output: &state,
},
&EvalRefresh{
Info: info,
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
Provider: &provider,
State: &state,
Output: &state,
},
@ -175,11 +187,24 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Ops: []walkOperation{walkPlan},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalInterpolate{
Config: n.Resource.RawConfig,
Resource: resource,
Output: &resourceConfig,
},
&EvalGetProvider{
Name: n.ProvidedBy()[0],
Output: &provider,
},
&EvalReadState{
Name: n.stateId(),
Output: &state,
},
&EvalDiff{
Info: info,
Config: interpolateNode,
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
State: &EvalReadState{Name: n.stateId()},
Config: &resourceConfig,
Provider: &provider,
State: &state,
Output: &diff,
OutputState: &state,
},
@ -206,9 +231,13 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
Ops: []walkOperation{walkPlanDestroy},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalReadState{
Name: n.stateId(),
Output: &state,
},
&EvalDiffDestroy{
Info: info,
State: &EvalReadState{Name: n.stateId()},
State: &state,
Output: &diff,
},
&EvalWriteDiff{
@ -220,7 +249,6 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
})
// Diff the resource for destruction
var provider ResourceProvider
var diffApply *InstanceDiff
var err error
var createNew, tainted bool
@ -260,11 +288,25 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
},
},
&EvalInterpolate{
Config: n.Resource.RawConfig,
Resource: resource,
Output: &resourceConfig,
},
&EvalGetProvider{
Name: n.ProvidedBy()[0],
Output: &provider,
},
&EvalReadState{
Name: n.stateId(),
Output: &state,
},
&EvalDiff{
Info: info,
Config: interpolateNode,
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
State: &EvalReadState{Name: n.stateId()},
Config: &resourceConfig,
Provider: &provider,
State: &state,
Output: &diffApply,
},

View File

@ -68,6 +68,7 @@ func (n *graphNodeTaintedResource) ProvidedBy() []string {
// GraphNodeEvalable impl.
func (n *graphNodeTaintedResource) EvalTree() EvalNode {
var provider ResourceProvider
var state *InstanceState
tainted := true
@ -82,6 +83,10 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
Ops: []walkOperation{walkRefresh},
Node: &EvalSequence{
Nodes: []EvalNode{
&EvalGetProvider{
Name: n.ProvidedBy()[0],
Output: &provider,
},
&EvalReadState{
Name: n.ResourceName,
Tainted: true,
@ -90,7 +95,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
},
&EvalRefresh{
Info: info,
Provider: &EvalGetProvider{Name: n.ProvidedBy()[0]},
Provider: &provider,
State: &state,
Output: &state,
},
@ -106,7 +111,6 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
})
// Apply
var provider ResourceProvider
var diff *InstanceDiff
seq.Nodes = append(seq.Nodes, &EvalOpFilter{
Ops: []walkOperation{walkApply},
@ -124,11 +128,7 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode {
},
&EvalDiffDestroy{
Info: info,
State: &EvalReadState{
Name: n.ResourceName,
Tainted: true,
TaintedIndex: n.Index,
},
State: &state,
Output: &diff,
},
&EvalApply{