diff --git a/terraform/context_apply_test.go b/terraform/context_apply_test.go index 841530aee..b77d5b0e0 100644 --- a/terraform/context_apply_test.go +++ b/terraform/context_apply_test.go @@ -2297,6 +2297,7 @@ func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { checkStateString(t, state, ` aws_instance.web: (1 deposed) ID = bar + provider = aws Deposed ID 1 = foo `) @@ -2321,6 +2322,7 @@ aws_instance.web: (1 deposed) checkStateString(t, state, ` aws_instance.web: (2 deposed) ID = baz + provider = aws Deposed ID 1 = foo Deposed ID 2 = bar `) @@ -2348,6 +2350,7 @@ aws_instance.web: (2 deposed) checkStateString(t, state, ` aws_instance.web: (1 deposed) ID = qux + provider = aws Deposed ID 1 = bar `) @@ -2369,6 +2372,7 @@ aws_instance.web: (1 deposed) checkStateString(t, state, ` aws_instance.web: ID = quux + provider = aws `) } @@ -4746,8 +4750,10 @@ func TestContext2Apply_createBefore_depends(t *testing.T) { State: state, }) - if _, err := ctx.Plan(); err != nil { + if p, err := ctx.Plan(); err != nil { t.Fatalf("err: %s", err) + } else { + t.Logf("plan: %s", p) } h.Active = true @@ -4764,7 +4770,7 @@ func TestContext2Apply_createBefore_depends(t *testing.T) { actual := strings.TrimSpace(state.String()) expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) if actual != expected { - t.Fatalf("bad: \n%s\n%s", actual, expected) + t.Fatalf("bad: \n%s\n\n%s", actual, expected) } // Test that things were managed _in the right order_ diff --git a/terraform/graph.go b/terraform/graph.go index 97214f809..d056bab1f 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -263,10 +263,11 @@ func (g *Graph) walk(walker GraphWalker) error { rerr = err return } - - // Walk the subgraph - if rerr = g.walk(walker); rerr != nil { - return + if g != nil { + // Walk the subgraph + if rerr = g.walk(walker); rerr != nil { + return + } } } diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index 598e33adb..e53b7caaf 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -27,6 +27,9 @@ type ApplyGraphBuilder struct { // Provisioners is the list of provisioners supported. Provisioners []string + + // DisableReduce, if true, will not reduce the graph. Great for testing. + DisableReduce bool } // See GraphBuilder @@ -103,10 +106,12 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { // Single root &RootTransformer{}, + } + if !b.DisableReduce { // Perform the transitive reduction to make our graph a bit // more sane if possible (it usually is possible). - &TransitiveReductionTransformer{}, + steps = append(steps, &TransitiveReductionTransformer{}) } return steps diff --git a/terraform/graph_builder_apply_test.go b/terraform/graph_builder_apply_test.go index ff6d71e28..f224e53f1 100644 --- a/terraform/graph_builder_apply_test.go +++ b/terraform/graph_builder_apply_test.go @@ -65,10 +65,11 @@ func TestApplyGraphBuilder(t *testing.T) { } b := &ApplyGraphBuilder{ - Module: testModule(t, "graph-builder-apply-basic"), - Diff: diff, - Providers: []string{"aws"}, - Provisioners: []string{"exec"}, + Module: testModule(t, "graph-builder-apply-basic"), + Diff: diff, + Providers: []string{"aws"}, + Provisioners: []string{"exec"}, + DisableReduce: true, } g, err := b.Build(RootModulePath) @@ -93,6 +94,14 @@ aws_instance.create aws_instance.other aws_instance.create provider.aws +meta.count-boundary (count boundary fixup) + aws_instance.create + aws_instance.other + module.child.aws_instance.create + module.child.aws_instance.other + module.child.provider.aws + provider.aws + provisioner.exec module.child.aws_instance.create module.child.provider.aws provisioner.exec @@ -103,7 +112,4 @@ module.child.provider.aws provider.aws provider.aws provisioner.exec -root - aws_instance.other - module.child.aws_instance.other ` diff --git a/terraform/node_resource_destroy.go b/terraform/node_resource_destroy.go index 9021d77e3..640f5d158 100644 --- a/terraform/node_resource_destroy.go +++ b/terraform/node_resource_destroy.go @@ -6,7 +6,7 @@ import ( // NodeDestroyResource represents a resource that is to be destroyed. type NodeDestroyResource struct { - *NodeAbstractResource + NodeAbstractResource } func (n *NodeDestroyResource) Name() string { @@ -38,6 +38,34 @@ func (n *NodeDestroyResource) References() []string { return nil } +// GraphNodeDynamicExpandable +func (n *NodeDestroyResource) DynamicExpand(ctx EvalContext) (*Graph, error) { + // If we have no config we do nothing + if n.Config == nil { + return nil, nil + } + + state, lock := ctx.State() + lock.RLock() + defer lock.RUnlock() + + // Start creating the steps + steps := make([]GraphTransformer, 0, 5) + + // We want deposed resources in the state to be destroyed + steps = append(steps, &DeposedTransformer{ + State: state, + View: n.Config.Id(), + }) + + // Always end with the root being added + steps = append(steps, &RootTransformer{}) + + // Build the graph + b := &BasicGraphBuilder{Steps: steps} + return b.Build(ctx.Path()) +} + // GraphNodeEvalable func (n *NodeDestroyResource) EvalTree() EvalNode { // stateId is the ID to put into the state diff --git a/terraform/terraform_test.go b/terraform/terraform_test.go index dd6185613..379bccd80 100644 --- a/terraform/terraform_test.go +++ b/terraform/terraform_test.go @@ -298,6 +298,7 @@ aws_instance.lb: aws_instance.web aws_instance.web: ID = foo + provider = aws require_new = ami-new type = aws_instance ` @@ -305,6 +306,7 @@ aws_instance.web: const testTerraformApplyCreateBeforeStr = ` aws_instance.bar: ID = foo + provider = aws require_new = xyz type = aws_instance ` @@ -591,6 +593,7 @@ aws_instance.bar: const testTerraformApplyErrorDestroyCreateBeforeDestroyStr = ` aws_instance.bar: (1 deposed) ID = foo + provider = aws Deposed ID 1 = bar ` diff --git a/terraform/transform_diff.go b/terraform/transform_diff.go index 68e905346..7943af685 100644 --- a/terraform/transform_diff.go +++ b/terraform/transform_diff.go @@ -59,7 +59,7 @@ func (t *DiffTransformer) Transform(g *Graph) error { // If we're destroying, add the destroy node if inst.Destroy { - abstract := &NodeAbstractResource{Addr: addr} + abstract := NodeAbstractResource{Addr: addr} g.Add(&NodeDestroyResource{NodeAbstractResource: abstract}) }