diff --git a/terraform/graph_builder.go b/terraform/graph_builder.go index 574181c42..28a76e513 100644 --- a/terraform/graph_builder.go +++ b/terraform/graph_builder.go @@ -153,7 +153,7 @@ func (b *BuiltinGraphBuilder) Steps(path []string) []GraphTransformer { if len(path) <= 1 { steps = append(steps, // Create the destruction nodes - &DestroyTransformer{}, + &DestroyTransformer{FullDestroy: b.Destroy}, &CreateBeforeDestroyTransformer{}, b.conditional(&conditionalOpts{ If: func() bool { return !b.Verbose }, diff --git a/terraform/graph_config_node_output.go b/terraform/graph_config_node_output.go index 0d84a7862..232d737ea 100644 --- a/terraform/graph_config_node_output.go +++ b/terraform/graph_config_node_output.go @@ -62,7 +62,7 @@ func (n *GraphNodeConfigOutput) Proxy() bool { } // GraphNodeDestroyEdgeInclude impl. -func (n *GraphNodeConfigOutput) DestroyEdgeInclude() bool { +func (n *GraphNodeConfigOutput) DestroyEdgeInclude(bool) bool { return false } diff --git a/terraform/graph_config_node_variable.go b/terraform/graph_config_node_variable.go index a3a7e77c8..569219c4a 100644 --- a/terraform/graph_config_node_variable.go +++ b/terraform/graph_config_node_variable.go @@ -56,11 +56,14 @@ func (n *GraphNodeConfigVariable) VariableName() string { } // GraphNodeDestroyEdgeInclude impl. -func (n *GraphNodeConfigVariable) DestroyEdgeInclude() bool { +func (n *GraphNodeConfigVariable) DestroyEdgeInclude(full bool) bool { // Don't include variables as dependencies in destroy nodes. // Destroy nodes don't interpolate anyways and this has a possibility // to create cycles. See GH-1835 - return false + // + // We include the variable on non-full destroys because it might + // be used for count interpolation. + return !full } // GraphNodeProxy impl. diff --git a/terraform/transform_destroy.go b/terraform/transform_destroy.go index a3fe737af..4fb076218 100644 --- a/terraform/transform_destroy.go +++ b/terraform/transform_destroy.go @@ -49,12 +49,14 @@ type GraphNodeDestroyPrunable interface { // as an edge within the destroy graph. This is usually done because it // might cause unnecessary cycles. type GraphNodeDestroyEdgeInclude interface { - DestroyEdgeInclude() bool + DestroyEdgeInclude(bool) bool } // DestroyTransformer is a GraphTransformer that creates the destruction // nodes for things that _might_ be destroyed. -type DestroyTransformer struct{} +type DestroyTransformer struct { + FullDestroy bool +} func (t *DestroyTransformer) Transform(g *Graph) error { var connect, remove []dag.Edge @@ -111,7 +113,8 @@ func (t *DestroyTransformer) transform( for _, edgeRaw := range downEdges { // If this thing specifically requests to not be depended on // by destroy nodes, then don't. - if i, ok := edgeRaw.(GraphNodeDestroyEdgeInclude); ok && !i.DestroyEdgeInclude() { + if i, ok := edgeRaw.(GraphNodeDestroyEdgeInclude); ok && + !i.DestroyEdgeInclude(t.FullDestroy) { continue }