diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index 4d7832772e..430195c7f2 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -120,6 +120,13 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { // Connect references so ordering is correct &ReferenceTransformer{}, + // Reverse the edges to outputs and locals, so that + // interpolations don't fail during destroy. + GraphTransformIf( + func() bool { return b.Destroy }, + &DestroyValueReferenceTransformer{}, + ), + // Add the node to fix the state count boundaries &CountBoundaryTransformer{}, diff --git a/terraform/transform_destroy_edge.go b/terraform/transform_destroy_edge.go index 22be1ab62a..d9bd362f2f 100644 --- a/terraform/transform_destroy_edge.go +++ b/terraform/transform_destroy_edge.go @@ -119,6 +119,9 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { return &NodeApplyableProvider{NodeAbstractProvider: a} } steps := []GraphTransformer{ + // Add the local values + &LocalTransformer{Module: t.Module}, + // Add outputs and metadata &OutputTransformer{Module: t.Module}, &AttachResourceConfigTransformer{Module: t.Module}, diff --git a/terraform/transform_reference.go b/terraform/transform_reference.go index ce55e1d775..24ddc7a0a4 100644 --- a/terraform/transform_reference.go +++ b/terraform/transform_reference.go @@ -76,6 +76,37 @@ func (t *ReferenceTransformer) Transform(g *Graph) error { return nil } +// DestroyReferenceTransformer is a GraphTransformer that reverses the edges +// for nodes that depend on an Output or Local value. Output and local nodes are +// removed during destroy, so anything which depends on them must be evaluated +// first. These can't be interpolated during destroy, so the stored value must +// be used anyway hence they don't need to be re-evaluated. +type DestroyValueReferenceTransformer struct{} + +func (t *DestroyValueReferenceTransformer) Transform(g *Graph) error { + vs := g.Vertices() + + for _, v := range vs { + switch v.(type) { + case *NodeApplyableOutput, *NodeLocal: + // OK + default: + continue + } + + // reverse any incoming edges so that the value is removed last + for _, e := range g.EdgesTo(v) { + source := e.Source() + log.Printf("[TRACE] output dep: %s", dag.VertexName(source)) + + g.RemoveEdge(e) + g.Connect(&DestroyEdge{S: v, T: source}) + } + } + + return nil +} + // ReferenceMap is a structure that can be used to efficiently check // for references on a graph. type ReferenceMap struct {