From b52881d2323f5bdee52b8602187ed0a3ef8b6556 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Fri, 13 Feb 2015 22:58:41 -0800 Subject: [PATCH] terraform: clean up EvalNodes --- terraform/eval.go | 23 +------ terraform/eval_apply.go | 33 +-------- terraform/eval_count.go | 11 +-- terraform/eval_diff.go | 106 +++++------------------------ terraform/eval_filter_operation.go | 13 +--- terraform/eval_if.go | 11 +-- terraform/eval_interpolate.go | 21 +++--- terraform/eval_interpolate_test.go | 8 ++- terraform/eval_literal.go | 20 ------ terraform/eval_literal_test.go | 27 -------- terraform/eval_noop.go | 4 +- terraform/eval_output.go | 11 +-- terraform/eval_provider.go | 50 ++------------ terraform/eval_provider_test.go | 35 +++------- terraform/eval_provisioner.go | 29 +++----- terraform/eval_provisioner_test.go | 12 ++-- terraform/eval_refresh.go | 16 ++--- terraform/eval_resource.go | 11 +-- terraform/eval_sequence.go | 29 ++------ terraform/eval_state.go | 44 ++---------- terraform/eval_test.go | 36 +++------- terraform/eval_validate.go | 73 +++++--------------- terraform/eval_variable.go | 26 ++----- terraform/evaltree_provider.go | 18 +++-- terraform/graph_config_node.go | 8 ++- terraform/transform_orphan.go | 14 +++- terraform/transform_resource.go | 84 +++++++++++++++++------ terraform/transform_tainted.go | 16 ++--- 28 files changed, 222 insertions(+), 567 deletions(-) delete mode 100644 terraform/eval_literal.go delete mode 100644 terraform/eval_literal_test.go diff --git a/terraform/eval.go b/terraform/eval.go index 8dd1b1e8f..7b1afeb38 100644 --- a/terraform/eval.go +++ b/terraform/eval.go @@ -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) } diff --git a/terraform/eval_apply.go b/terraform/eval_apply.go index 069973855..cebf68265 100644 --- a/terraform/eval_apply.go +++ b/terraform/eval_apply.go @@ -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 diff --git a/terraform/eval_count.go b/terraform/eval_count.go index b87ce8bf6..f7886b8da 100644 --- a/terraform/eval_count.go +++ b/terraform/eval_count.go @@ -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 -} diff --git a/terraform/eval_diff.go b/terraform/eval_diff.go index 0bf3baa73..89a583918 100644 --- a/terraform/eval_diff.go +++ b/terraform/eval_diff.go @@ -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 -} diff --git a/terraform/eval_filter_operation.go b/terraform/eval_filter_operation.go index 7f30ea980..1a55f024a 100644 --- a/terraform/eval_filter_operation.go +++ b/terraform/eval_filter_operation.go @@ -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. diff --git a/terraform/eval_if.go b/terraform/eval_if.go index cc507ea99..c96e13229 100644 --- a/terraform/eval_if.go +++ b/terraform/eval_if.go @@ -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 -} diff --git a/terraform/eval_interpolate.go b/terraform/eval_interpolate.go index 654359c0d..063473079 100644 --- a/terraform/eval_interpolate.go +++ b/terraform/eval_interpolate.go @@ -9,17 +9,18 @@ import ( type EvalInterpolate struct { Config *config.RawConfig 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 } - -func (n *EvalInterpolate) Eval( - ctx EvalContext, args []interface{}) (interface{}, error) { - return ctx.Interpolate(n.Config, n.Resource) -} - -func (n *EvalInterpolate) Type() EvalType { - return EvalTypeConfig -} diff --git a/terraform/eval_interpolate_test.go b/terraform/eval_interpolate_test.go index e43ce249b..4b01ea462 100644 --- a/terraform/eval_interpolate_test.go +++ b/terraform/eval_interpolate_test.go @@ -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) } diff --git a/terraform/eval_literal.go b/terraform/eval_literal.go deleted file mode 100644 index 215929872..000000000 --- a/terraform/eval_literal.go +++ /dev/null @@ -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 -} diff --git a/terraform/eval_literal_test.go b/terraform/eval_literal_test.go deleted file mode 100644 index f82a5613d..000000000 --- a/terraform/eval_literal_test.go +++ /dev/null @@ -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) - } -} diff --git a/terraform/eval_noop.go b/terraform/eval_noop.go index cfcdb1fc8..f4bc8225c 100644 --- a/terraform/eval_noop.go +++ b/terraform/eval_noop.go @@ -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 } diff --git a/terraform/eval_output.go b/terraform/eval_output.go index 1e03faf44..0d9056d70 100644 --- a/terraform/eval_output.go +++ b/terraform/eval_output.go @@ -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 -} diff --git a/terraform/eval_provider.go b/terraform/eval_provider.go index 22dac3f55..bc9a2652c 100644 --- a/terraform/eval_provider.go +++ b/terraform/eval_provider.go @@ -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 -} diff --git a/terraform/eval_provider_test.go b/terraform/eval_provider_test.go index d83b9dcb6..849e434a6 100644 --- a/terraform/eval_provider_test.go +++ b/terraform/eval_provider_test.go @@ -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) } diff --git a/terraform/eval_provisioner.go b/terraform/eval_provisioner.go index ce7c657a9..362a26e84 100644 --- a/terraform/eval_provisioner.go +++ b/terraform/eval_provisioner.go @@ -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 + 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) } + if n.Output != nil { + *n.Output = result + } + return result, nil } - -func (n *EvalGetProvisioner) Type() EvalType { - return EvalTypeResourceProvisioner -} diff --git a/terraform/eval_provisioner_test.go b/terraform/eval_provisioner_test.go index 2c9ab4158..1225c5abb 100644 --- a/terraform/eval_provisioner_test.go +++ b/terraform/eval_provisioner_test.go @@ -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) } diff --git a/terraform/eval_refresh.go b/terraform/eval_refresh.go index 5188650d3..3d25ecc8b 100644 --- a/terraform/eval_refresh.go +++ b/terraform/eval_refresh.go @@ -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 } diff --git a/terraform/eval_resource.go b/terraform/eval_resource.go index 4b87e6794..5eca6782a 100644 --- a/terraform/eval_resource.go +++ b/terraform/eval_resource.go @@ -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 -} diff --git a/terraform/eval_sequence.go b/terraform/eval_sequence.go index fc2828f5d..6c3c6a620 100644 --- a/terraform/eval_sequence.go +++ b/terraform/eval_sequence.go @@ -5,31 +5,14 @@ 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() + return nil, nil } // EvalNodeFilterable impl. diff --git a/terraform/eval_state.go b/terraform/eval_state.go index 38bd1a594..bf8fec080 100644 --- a/terraform/eval_state.go +++ b/terraform/eval_state.go @@ -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 -} diff --git a/terraform/eval_test.go b/terraform/eval_test.go index 47154ef2c..29ae25843 100644 --- a/terraform/eval_test.go +++ b/terraform/eval_test.go @@ -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 } diff --git a/terraform/eval_validate.go b/terraform/eval_validate.go index 9be51fcf8..c6c1f20ba 100644 --- a/terraform/eval_validate.go +++ b/terraform/eval_validate.go @@ -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 -} diff --git a/terraform/eval_variable.go b/terraform/eval_variable.go index 6c8aade78..ebaf2eabb 100644 --- a/terraform/eval_variable.go +++ b/terraform/eval_variable.go @@ -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 -} diff --git a/terraform/evaltree_provider.go b/terraform/evaltree_provider.go index a4b3606b8..89937d562 100644 --- a/terraform/evaltree_provider.go +++ b/terraform/evaltree_provider.go @@ -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, }, }, }, diff --git a/terraform/graph_config_node.go b/terraform/graph_config_node.go index 4402a3751..9904b59e0 100644 --- a/terraform/graph_config_node.go +++ b/terraform/graph_config_node.go @@ -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, }, diff --git a/terraform/transform_orphan.go b/terraform/transform_orphan.go index e1c1f8a1e..780d8430b 100644 --- a/terraform/transform_orphan.go +++ b/terraform/transform_orphan.go @@ -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{ diff --git a/terraform/transform_resource.go b/terraform/transform_resource.go index 30143e961..14ea0a0e8 100644 --- a/terraform/transform_resource.go +++ b/terraform/transform_resource.go @@ -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, }, diff --git a/terraform/transform_tainted.go b/terraform/transform_tainted.go index 74e15cb45..37f6d60b5 100644 --- a/terraform/transform_tainted.go +++ b/terraform/transform_tainted.go @@ -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}, @@ -123,12 +127,8 @@ func (n *graphNodeTaintedResource) EvalTree() EvalNode { Output: &state, }, &EvalDiffDestroy{ - Info: info, - State: &EvalReadState{ - Name: n.ResourceName, - Tainted: true, - TaintedIndex: n.Index, - }, + Info: info, + State: &state, Output: &diff, }, &EvalApply{