From 35c6a4e89dd90b5490ea6426b4300200961ab90a Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 29 Sep 2017 11:12:57 -0400 Subject: [PATCH] add DestroyValueReferenceTransformer DestroyValueReferenceTransformer is used during destroy to reverse the edges for output and local values. Because destruction is going to remove these from the state, nodes that depend on their value need to be visited first. --- terraform/graph_builder_apply.go | 7 +++++++ terraform/transform_destroy_edge.go | 3 +++ terraform/transform_reference.go | 31 +++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index 4d7832772..430195c7f 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 22be1ab62..d9bd362f2 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 ce55e1d77..24ddc7a0a 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 {