From 480a414c4008d610cf1ff65c6cc8a2bd1f6ecf37 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Wed, 19 Oct 2016 10:02:07 -0700 Subject: [PATCH] terraform: destroy module nodes show up in plan destroy --- terraform/context_plan_test.go | 6 +- terraform/graph_builder_destroy_plan.go | 3 + terraform/graph_config_node_module.go | 2 +- terraform/node_module_destroy.go | 29 ++++++++ terraform/transform_module_destroy.go | 81 ++++++++--------------- terraform/transform_module_destroy_old.go | 62 +++++++++++++++++ 6 files changed, 126 insertions(+), 57 deletions(-) create mode 100644 terraform/node_module_destroy.go create mode 100644 terraform/transform_module_destroy_old.go diff --git a/terraform/context_plan_test.go b/terraform/context_plan_test.go index e58dbdf9f..c0fc555b9 100644 --- a/terraform/context_plan_test.go +++ b/terraform/context_plan_test.go @@ -1582,7 +1582,7 @@ func TestContext2Plan_moduleDestroy(t *testing.T) { actual := strings.TrimSpace(plan.String()) expected := strings.TrimSpace(testTerraformPlanModuleDestroyStr) if actual != expected { - t.Fatalf("bad:\n%s", actual) + t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) } } @@ -1634,7 +1634,7 @@ func TestContext2Plan_moduleDestroyCycle(t *testing.T) { actual := strings.TrimSpace(plan.String()) expected := strings.TrimSpace(testTerraformPlanModuleDestroyCycleStr) if actual != expected { - t.Fatalf("bad:\n%s", actual) + t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) } } @@ -1684,7 +1684,7 @@ func TestContext2Plan_moduleDestroyMultivar(t *testing.T) { actual := strings.TrimSpace(plan.String()) expected := strings.TrimSpace(testTerraformPlanModuleDestroyMultivarStr) if actual != expected { - t.Fatalf("bad:\n%s", actual) + t.Fatalf("bad:\n%s\n\nexpected:\n\n%s", actual, expected) } } diff --git a/terraform/graph_builder_destroy_plan.go b/terraform/graph_builder_destroy_plan.go index a48c2bb92..64a7d1c2f 100644 --- a/terraform/graph_builder_destroy_plan.go +++ b/terraform/graph_builder_destroy_plan.go @@ -44,6 +44,9 @@ func (b *DestroyPlanGraphBuilder) Steps() []GraphTransformer { // Attach the configuration to any resources &AttachResourceConfigTransformer{Module: b.Module}, + // Module destroy nodes + &ModuleDestroyTransformer{State: b.State}, + // Single root &RootTransformer{}, } diff --git a/terraform/graph_config_node_module.go b/terraform/graph_config_node_module.go index 3e36e1ea5..8da8fb6cd 100644 --- a/terraform/graph_config_node_module.go +++ b/terraform/graph_config_node_module.go @@ -59,7 +59,7 @@ func (n *GraphNodeConfigModule) Expand(b GraphBuilder) (GraphNodeSubgraph, error { // Add the destroy marker to the graph - t := &ModuleDestroyTransformer{} + t := &ModuleDestroyTransformerOld{} if err := t.Transform(graph); err != nil { return nil, err } diff --git a/terraform/node_module_destroy.go b/terraform/node_module_destroy.go new file mode 100644 index 000000000..319df1e3a --- /dev/null +++ b/terraform/node_module_destroy.go @@ -0,0 +1,29 @@ +package terraform + +import ( + "fmt" +) + +// NodeDestroyableModule represents a module destruction. +type NodeDestroyableModuleVariable struct { + PathValue []string +} + +func (n *NodeDestroyableModuleVariable) Name() string { + result := "plan-destroy" + if len(n.PathValue) > 1 { + result = fmt.Sprintf("%s.%s", modulePrefixStr(n.PathValue), result) + } + + return result +} + +// GraphNodeSubPath +func (n *NodeDestroyableModuleVariable) Path() []string { + return n.PathValue +} + +// GraphNodeEvalable +func (n *NodeDestroyableModuleVariable) EvalTree() EvalNode { + return &EvalDiffDestroyModule{Path: n.PathValue} +} diff --git a/terraform/transform_module_destroy.go b/terraform/transform_module_destroy.go index 609873c44..bf6e450f1 100644 --- a/terraform/transform_module_destroy.go +++ b/terraform/transform_module_destroy.go @@ -1,62 +1,37 @@ package terraform -import ( - "fmt" - - "github.com/hashicorp/terraform/dag" -) - // ModuleDestroyTransformer is a GraphTransformer that adds a node -// to the graph that will just mark the full module for destroy in -// the destroy scenario. -type ModuleDestroyTransformer struct{} +// to the graph that will add a module destroy node for all modules in +// the state. +// +// NOTE: This is _completely unnecessary_ in the new graph worlds. This is +// only done to make old tests pass. However, this node does nothing in +// the new apply graph. +type ModuleDestroyTransformer struct { + State *State +} func (t *ModuleDestroyTransformer) Transform(g *Graph) error { - // Create the node - n := &graphNodeModuleDestroy{Path: g.Path} + // If empty do nothing + if t.State.Empty() { + return nil + } - // Add it to the graph. We don't need any edges because - // it can happen whenever. - g.Add(n) + for _, ms := range t.State.Modules { + // Just a silly edge case that is required to get old tests to pass. + // It is probably a bug with the old graph but we mimic it here + // so that old tests pass. + if len(ms.Path) <= 1 { + continue + } + + // Create the node + n := &NodeDestroyableModuleVariable{PathValue: ms.Path} + + // Add it to the graph. We don't need any edges because + // it can happen whenever. + g.Add(n) + } return nil } - -type graphNodeModuleDestroy struct { - Path []string -} - -func (n *graphNodeModuleDestroy) Name() string { - return "plan-destroy" -} - -// GraphNodeEvalable impl. -func (n *graphNodeModuleDestroy) EvalTree() EvalNode { - return &EvalOpFilter{ - Ops: []walkOperation{walkPlanDestroy}, - Node: &EvalDiffDestroyModule{Path: n.Path}, - } -} - -// GraphNodeFlattenable impl. -func (n *graphNodeModuleDestroy) Flatten(p []string) (dag.Vertex, error) { - return &graphNodeModuleDestroyFlat{ - graphNodeModuleDestroy: n, - PathValue: p, - }, nil -} - -type graphNodeModuleDestroyFlat struct { - *graphNodeModuleDestroy - - PathValue []string -} - -func (n *graphNodeModuleDestroyFlat) Name() string { - return fmt.Sprintf( - "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeModuleDestroy.Name()) -} - -func (n *graphNodeModuleDestroyFlat) Path() []string { - return n.PathValue -} diff --git a/terraform/transform_module_destroy_old.go b/terraform/transform_module_destroy_old.go new file mode 100644 index 000000000..e971838f1 --- /dev/null +++ b/terraform/transform_module_destroy_old.go @@ -0,0 +1,62 @@ +package terraform + +import ( + "fmt" + + "github.com/hashicorp/terraform/dag" +) + +// ModuleDestroyTransformer is a GraphTransformer that adds a node +// to the graph that will just mark the full module for destroy in +// the destroy scenario. +type ModuleDestroyTransformerOld struct{} + +func (t *ModuleDestroyTransformerOld) Transform(g *Graph) error { + // Create the node + n := &graphNodeModuleDestroy{Path: g.Path} + + // Add it to the graph. We don't need any edges because + // it can happen whenever. + g.Add(n) + + return nil +} + +type graphNodeModuleDestroy struct { + Path []string +} + +func (n *graphNodeModuleDestroy) Name() string { + return "plan-destroy" +} + +// GraphNodeEvalable impl. +func (n *graphNodeModuleDestroy) EvalTree() EvalNode { + return &EvalOpFilter{ + Ops: []walkOperation{walkPlanDestroy}, + Node: &EvalDiffDestroyModule{Path: n.Path}, + } +} + +// GraphNodeFlattenable impl. +func (n *graphNodeModuleDestroy) Flatten(p []string) (dag.Vertex, error) { + return &graphNodeModuleDestroyFlat{ + graphNodeModuleDestroy: n, + PathValue: p, + }, nil +} + +type graphNodeModuleDestroyFlat struct { + *graphNodeModuleDestroy + + PathValue []string +} + +func (n *graphNodeModuleDestroyFlat) Name() string { + return fmt.Sprintf( + "%s.%s", modulePrefixStr(n.PathValue), n.graphNodeModuleDestroy.Name()) +} + +func (n *graphNodeModuleDestroyFlat) Path() []string { + return n.PathValue +}