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 // EvalNode is the interface that must be implemented by graph nodes to
// evaluate/execute. // evaluate/execute.
type EvalNode interface { 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 // 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 // are the argument values. These will match in order and 1-1 with the
// results of the Args() return value. // results of the Args() return value.
Eval(EvalContext, []interface{}) (interface{}, error) Eval(EvalContext) (interface{}, error)
// Type returns the type that will be returned by this node.
Type() EvalType
} }
// GraphNodeEvalable is the interface that graph nodes must implement // 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 // EvalRaw is like Eval except that it returns all errors, even if they
// signal something normal such as EvalEarlyExitError. // signal something normal such as EvalEarlyExitError.
func EvalRaw(n EvalNode, ctx EvalContext) (interface{}, error) { 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) log.Printf("[DEBUG] eval: %T", n)
output, err := n.Eval(ctx, args) output, err := n.Eval(ctx)
if err != nil { if err != nil {
log.Printf("[ERROR] eval: %T, err: %s", n, err) log.Printf("[ERROR] eval: %T, err: %s", n, err)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,17 +9,18 @@ import (
type EvalInterpolate struct { type EvalInterpolate struct {
Config *config.RawConfig Config *config.RawConfig
Resource *Resource Resource *Resource
Output **ResourceConfig
} }
func (n *EvalInterpolate) Args() ([]EvalNode, []EvalType) { 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
}
return nil, nil 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) t.Fatalf("err: %s", err)
} }
n := &EvalInterpolate{Config: config} var actual *ResourceConfig
n := &EvalInterpolate{Config: config, Output: &actual}
result := testResourceConfig(t, map[string]interface{}{}) result := testResourceConfig(t, map[string]interface{}{})
ctx := &MockEvalContext{InterpolateConfigResult: result} 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) t.Fatalf("err: %s", err)
} else if actual != result { }
if actual != result {
t.Fatalf("bad: %#v", actual) 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. // EvalNoop is an EvalNode that does nothing.
type EvalNoop struct{} type EvalNoop struct{}
func (EvalNoop) Args() ([]EvalNode, []EvalType) { return nil, nil } func (EvalNoop) Eval(EvalContext) (interface{}, error) {
func (EvalNoop) Eval(EvalContext, []interface{}) (interface{}, error) {
return nil, nil return nil, nil
} }
func (EvalNoop) Type() EvalType { return EvalTypeNull }

View File

@ -13,13 +13,8 @@ type EvalWriteOutput struct {
Value *config.RawConfig Value *config.RawConfig
} }
func (n *EvalWriteOutput) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test // TODO: test
func (n *EvalWriteOutput) Eval( func (n *EvalWriteOutput) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
cfg, err := ctx.Interpolate(n.Value, nil) cfg, err := ctx.Interpolate(n.Value, nil)
if err != nil { if err != nil {
// Ignore it // Ignore it
@ -66,7 +61,3 @@ func (n *EvalWriteOutput) Eval(
return nil, nil 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. // a provider that is already initialized and retrieved.
type EvalConfigProvider struct { type EvalConfigProvider struct {
Provider string Provider string
Config EvalNode Config **ResourceConfig
} }
func (n *EvalConfigProvider) Args() ([]EvalNode, []EvalType) { func (n *EvalConfigProvider) Eval(ctx EvalContext) (interface{}, error) {
return []EvalNode{n.Config}, []EvalType{EvalTypeConfig} cfg := *n.Config
}
func (n *EvalConfigProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
cfg := args[0].(*ResourceConfig)
// If we have a configuration set, then use that // If we have a configuration set, then use that
if input := ctx.ProviderInput(n.Provider); input != nil { if input := ctx.ProviderInput(n.Provider); input != nil {
@ -41,10 +36,6 @@ func (n *EvalConfigProvider) Eval(
return nil, ctx.ConfigureProvider(n.Provider, cfg) return nil, ctx.ConfigureProvider(n.Provider, cfg)
} }
func (n *EvalConfigProvider) Type() EvalType {
return EvalTypeNull
}
// EvalInitProvider is an EvalNode implementation that initializes a provider // EvalInitProvider is an EvalNode implementation that initializes a provider
// and returns nothing. The provider can be retrieved again with the // and returns nothing. The provider can be retrieved again with the
// EvalGetProvider node. // EvalGetProvider node.
@ -52,19 +43,10 @@ type EvalInitProvider struct {
Name string Name string
} }
func (n *EvalInitProvider) Args() ([]EvalNode, []EvalType) { func (n *EvalInitProvider) Eval(ctx EvalContext) (interface{}, error) {
return nil, nil
}
func (n *EvalInitProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
return ctx.InitProvider(n.Name) return ctx.InitProvider(n.Name)
} }
func (n *EvalInitProvider) Type() EvalType {
return EvalTypeNull
}
// EvalGetProvider is an EvalNode implementation that retrieves an already // EvalGetProvider is an EvalNode implementation that retrieves an already
// initialized provider instance for the given name. // initialized provider instance for the given name.
type EvalGetProvider struct { type EvalGetProvider struct {
@ -72,12 +54,7 @@ type EvalGetProvider struct {
Output *ResourceProvider Output *ResourceProvider
} }
func (n *EvalGetProvider) Args() ([]EvalNode, []EvalType) { func (n *EvalGetProvider) Eval(ctx EvalContext) (interface{}, error) {
return nil, nil
}
func (n *EvalGetProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
result := ctx.Provider(n.Name) result := ctx.Provider(n.Name)
if result == nil { if result == nil {
return nil, fmt.Errorf("provider %s not initialized", n.Name) return nil, fmt.Errorf("provider %s not initialized", n.Name)
@ -87,11 +64,7 @@ func (n *EvalGetProvider) Eval(
*n.Output = result *n.Output = result
} }
return result, nil return nil, nil
}
func (n *EvalGetProvider) Type() EvalType {
return EvalTypeResourceProvider
} }
// EvalInputProvider is an EvalNode implementation that asks for input // EvalInputProvider is an EvalNode implementation that asks for input
@ -102,12 +75,7 @@ type EvalInputProvider struct {
Config *config.RawConfig Config *config.RawConfig
} }
func (n *EvalInputProvider) Args() ([]EvalNode, []EvalType) { func (n *EvalInputProvider) Eval(ctx EvalContext) (interface{}, error) {
return nil, nil
}
func (n *EvalInputProvider) Eval(
ctx EvalContext, args []interface{}) (interface{}, error) {
// If we already configured this provider, then don't do this again // If we already configured this provider, then don't do this again
if v := ctx.ProviderInput(n.Name); v != nil { if v := ctx.ProviderInput(n.Name); v != nil {
return nil, nil return nil, nil
@ -138,7 +106,3 @@ func (n *EvalInputProvider) Eval(
return nil, nil 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) { func TestEvalConfigProvider(t *testing.T) {
config := testResourceConfig(t, map[string]interface{}{}) config := testResourceConfig(t, map[string]interface{}{})
provider := &MockResourceProvider{} provider := &MockResourceProvider{}
n := &EvalConfigProvider{} n := &EvalConfigProvider{Config: &config}
ctx := &MockEvalContext{ProviderProvider: provider} ctx := &MockEvalContext{ProviderProvider: provider}
args := []interface{}{config} if _, err := n.Eval(ctx); err != nil {
if actual, err := n.Eval(ctx, args); err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} else if actual != nil {
t.Fatalf("bad: %#v", actual)
} }
if !ctx.ConfigureProviderCalled { 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) { func TestEvalInitProvider_impl(t *testing.T) {
var _ EvalNode = new(EvalInitProvider) var _ EvalNode = new(EvalInitProvider)
} }
@ -54,10 +35,8 @@ func TestEvalInitProvider(t *testing.T) {
n := &EvalInitProvider{Name: "foo"} n := &EvalInitProvider{Name: "foo"}
provider := &MockResourceProvider{} provider := &MockResourceProvider{}
ctx := &MockEvalContext{InitProviderProvider: provider} 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) t.Fatalf("err: %s", err)
} else if actual != provider {
t.Fatalf("bad: %#v", actual)
} }
if !ctx.InitProviderCalled { if !ctx.InitProviderCalled {
@ -73,12 +52,14 @@ func TestEvalGetProvider_impl(t *testing.T) {
} }
func TestEvalGetProvider(t *testing.T) { func TestEvalGetProvider(t *testing.T) {
n := &EvalGetProvider{Name: "foo"} var actual ResourceProvider
n := &EvalGetProvider{Name: "foo", Output: &actual}
provider := &MockResourceProvider{} provider := &MockResourceProvider{}
ctx := &MockEvalContext{ProviderProvider: provider} 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) t.Fatalf("err: %s", err)
} else if actual != provider { }
if actual != provider {
t.Fatalf("bad: %#v", actual) t.Fatalf("bad: %#v", actual)
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -5,31 +5,14 @@ type EvalSequence struct {
Nodes []EvalNode Nodes []EvalNode
} }
func (n *EvalSequence) Args() ([]EvalNode, []EvalType) { func (n *EvalSequence) Eval(ctx EvalContext) (interface{}, error) {
types := make([]EvalType, len(n.Nodes)) for _, n := range n.Nodes {
for i, n := range n.Nodes { if _, err := EvalRaw(n, ctx); err != nil {
types[i] = n.Type() return nil, err
}
} }
return n.Nodes, types return nil, nil
}
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. // EvalNodeFilterable impl.

View File

@ -13,13 +13,8 @@ type EvalReadState struct {
Output **InstanceState Output **InstanceState
} }
func (n *EvalReadState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test // TODO: test
func (n *EvalReadState) Eval( func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
state, lock := ctx.State() state, lock := ctx.State()
// Get a read lock so we can access this instance // Get a read lock so we can access this instance
@ -63,10 +58,6 @@ func (n *EvalReadState) Eval(
return result, nil return result, nil
} }
func (n *EvalReadState) Type() EvalType {
return EvalTypeInstanceState
}
// EvalWriteState is an EvalNode implementation that reads the // EvalWriteState is an EvalNode implementation that reads the
// InstanceState for a specific resource out of the state. // InstanceState for a specific resource out of the state.
type EvalWriteState struct { type EvalWriteState struct {
@ -79,13 +70,8 @@ type EvalWriteState struct {
TaintedClearPrimary bool TaintedClearPrimary bool
} }
func (n *EvalWriteState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test // TODO: test
func (n *EvalWriteState) Eval( func (n *EvalWriteState) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
state, lock := ctx.State() state, lock := ctx.State()
if state == nil { if state == nil {
return nil, fmt.Errorf("cannot write state to nil state") return nil, fmt.Errorf("cannot write state to nil state")
@ -130,10 +116,6 @@ func (n *EvalWriteState) Eval(
return nil, nil return nil, nil
} }
func (n *EvalWriteState) Type() EvalType {
return EvalTypeNull
}
// EvalDeposeState is an EvalNode implementation that takes the primary // EvalDeposeState is an EvalNode implementation that takes the primary
// out of a state and makes it tainted. This is done at the beggining of // 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 // create-before-destroy calls so that the create can create while preserving
@ -142,13 +124,8 @@ type EvalDeposeState struct {
Name string Name string
} }
func (n *EvalDeposeState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test // TODO: test
func (n *EvalDeposeState) Eval( func (n *EvalDeposeState) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
state, lock := ctx.State() state, lock := ctx.State()
// Get a read lock so we can access this instance // Get a read lock so we can access this instance
@ -179,23 +156,14 @@ func (n *EvalDeposeState) Eval(
return nil, nil return nil, nil
} }
func (n *EvalDeposeState) Type() EvalType {
return EvalTypeNull
}
// EvalUndeposeState is an EvalNode implementation that reads the // EvalUndeposeState is an EvalNode implementation that reads the
// InstanceState for a specific resource out of the state. // InstanceState for a specific resource out of the state.
type EvalUndeposeState struct { type EvalUndeposeState struct {
Name string Name string
} }
func (n *EvalUndeposeState) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test // TODO: test
func (n *EvalUndeposeState) Eval( func (n *EvalUndeposeState) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
state, lock := ctx.State() state, lock := ctx.State()
// Get a read lock so we can access this instance // Get a read lock so we can access this instance
@ -226,7 +194,3 @@ func (n *EvalUndeposeState) Eval(
return nil, nil 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) { func TestEval(t *testing.T) {
var result int
n := &testEvalAdd{ n := &testEvalAdd{
Items: []EvalNode{ Items: []int{10, 32},
&EvalLiteral{Value: 10}, Result: &result,
&EvalLiteral{Value: 32},
},
} }
result, err := Eval(n, nil) if _, err := Eval(n, nil); err != nil {
if err != nil {
t.Fatalf("err: %s", err) t.Fatalf("err: %s", err)
} }
@ -27,28 +25,16 @@ func TestEval(t *testing.T) {
} }
type testEvalAdd struct { type testEvalAdd struct {
Items []EvalNode Items []int
Result *int
} }
func (n *testEvalAdd) Args() ([]EvalNode, []EvalType) { func (n *testEvalAdd) Eval(ctx EvalContext) (interface{}, error) {
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 result := 0
for _, arg := range args { for _, item := range n.Items {
result += arg.(int) result += item
} }
return result, nil *n.Result = result
} return nil, nil
func (n *testEvalAdd) Type() EvalType {
return EvalTypeInvalid
} }

View File

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

View File

@ -10,43 +10,29 @@ type EvalSetVariables struct {
Variables map[string]string Variables map[string]string
} }
func (n *EvalSetVariables) Args() ([]EvalNode, []EvalType) {
return nil, nil
}
// TODO: test // TODO: test
func (n *EvalSetVariables) Eval( func (n *EvalSetVariables) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
ctx.SetVariables(n.Variables) ctx.SetVariables(n.Variables)
return nil, nil return nil, nil
} }
func (n *EvalSetVariables) Type() EvalType {
return EvalTypeNull
}
// EvalVariableBlock is an EvalNode implementation that evaluates the // EvalVariableBlock is an EvalNode implementation that evaluates the
// given configuration, and uses the final values as a way to set the // given configuration, and uses the final values as a way to set the
// mapping. // mapping.
type EvalVariableBlock struct { type EvalVariableBlock struct {
Config EvalNode Config **ResourceConfig
Variables map[string]string Variables map[string]string
} }
func (n *EvalVariableBlock) Args() ([]EvalNode, []EvalType) {
return []EvalNode{n.Config}, []EvalType{EvalTypeConfig}
}
// TODO: test // TODO: test
func (n *EvalVariableBlock) Eval( func (n *EvalVariableBlock) Eval(ctx EvalContext) (interface{}, error) {
ctx EvalContext, args []interface{}) (interface{}, error) {
// Clear out the existing mapping // Clear out the existing mapping
for k, _ := range n.Variables { for k, _ := range n.Variables {
delete(n.Variables, k) delete(n.Variables, k)
} }
// Get our configuration // Get our configuration
rc := args[0].(*ResourceConfig) rc := *n.Config
for k, v := range rc.Config { for k, v := range rc.Config {
n.Variables[k] = v.(string) n.Variables[k] = v.(string)
} }
@ -58,7 +44,3 @@ func (n *EvalVariableBlock) Eval(
return nil, nil 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 // ProviderEvalTree returns the evaluation tree for initializing and
// configuring providers. // configuring providers.
func ProviderEvalTree(n string, config *config.RawConfig) EvalNode { func ProviderEvalTree(n string, config *config.RawConfig) EvalNode {
var provider ResourceProvider
var resourceConfig *ResourceConfig
seq := make([]EvalNode, 0, 5) seq := make([]EvalNode, 0, 5)
seq = append(seq, &EvalInitProvider{Name: n}) seq = append(seq, &EvalInitProvider{Name: n})
// Input stuff // Input stuff
var provider ResourceProvider
seq = append(seq, &EvalOpFilter{ seq = append(seq, &EvalOpFilter{
Ops: []walkOperation{walkInput}, Ops: []walkOperation{walkInput},
Node: &EvalSequence{ Node: &EvalSequence{
@ -34,14 +36,22 @@ func ProviderEvalTree(n string, config *config.RawConfig) EvalNode {
Ops: []walkOperation{walkValidate, walkRefresh, walkPlan, walkApply}, Ops: []walkOperation{walkValidate, walkRefresh, walkPlan, walkApply},
Node: &EvalSequence{ Node: &EvalSequence{
Nodes: []EvalNode{ Nodes: []EvalNode{
&EvalGetProvider{
Name: n,
Output: &provider,
},
&EvalInterpolate{
Config: config,
Output: &resourceConfig,
},
&EvalValidateProvider{ &EvalValidateProvider{
ProviderName: n, ProviderName: n,
Provider: &EvalGetProvider{Name: n}, Provider: &provider,
Config: &EvalInterpolate{Config: config}, Config: &resourceConfig,
}, },
&EvalConfigProvider{ &EvalConfigProvider{
Provider: n, Provider: n,
Config: &EvalInterpolate{Config: config}, Config: &resourceConfig,
}, },
}, },
}, },

View File

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

View File

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

View File

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

View File

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