From 48757bcbe012981050871f0b560259e678fed06c Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 22 May 2020 09:51:25 -0400 Subject: [PATCH] get rid of the NodeOutputOrphan We don't need another node type for orphaned outptus, they are just outputs being removed for a different reason than destroy. Use the NodeDestroyableOutput implementation. Destroy outputs also don't need to be referencers, since they are being removed. Rename DestroyOutputTransformer to destroyRootOutputTransformer, and add an explanation as to why it is the only transformer that requires an exception to know when it's involved from the destroy command. --- terraform/graph_builder_apply.go | 12 +++++-- terraform/node_output.go | 6 ---- terraform/node_output_orphan.go | 53 ---------------------------- terraform/transform_orphan_output.go | 2 +- terraform/transform_output.go | 6 ++-- 5 files changed, 14 insertions(+), 65 deletions(-) delete mode 100644 terraform/node_output_orphan.go diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index f40827859..5b96d6af6 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -160,8 +160,16 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { Schemas: b.Schemas, }, - // Create a destroy node for outputs to remove them from the state. - &DestroyOutputTransformer{Destroy: b.Destroy}, + // Create a destroy node for root outputs to remove them from the + // state. This does nothing unless invoked via the destroy command + // directly. A destroy is identical to a normal apply, except for the + // fact that we also have configuration to evaluate. While the rest of + // the unused nodes can be programmatically pruned (via + // pruneUnusedNodesTransformer), root module outputs only have an + // implied dependency on remote state. This means that if they exist in + // the configuration, the only signal to remove them is via the destroy + // command itself. + &destroyRootOutputTransformer{Destroy: b.Destroy}, // We need to remove configuration nodes that are not used at all, as // they may not be able to evaluate, especially during destroy. diff --git a/terraform/node_output.go b/terraform/node_output.go index ef5e6cd5e..729710f22 100644 --- a/terraform/node_output.go +++ b/terraform/node_output.go @@ -257,7 +257,6 @@ type NodeDestroyableOutput struct { var ( _ RemovableIfNotTargeted = (*NodeDestroyableOutput)(nil) _ GraphNodeTargetDownstream = (*NodeDestroyableOutput)(nil) - _ GraphNodeReferencer = (*NodeDestroyableOutput)(nil) _ GraphNodeEvalable = (*NodeDestroyableOutput)(nil) _ dag.GraphNodeDotter = (*NodeDestroyableOutput)(nil) ) @@ -284,11 +283,6 @@ func (n *NodeDestroyableOutput) TargetDownstream(targetedDeps, untargetedDeps da return true } -// GraphNodeReferencer -func (n *NodeDestroyableOutput) References() []*addrs.Reference { - return referencesForOutput(n.Config) -} - // GraphNodeEvalable func (n *NodeDestroyableOutput) EvalTree() EvalNode { return &EvalDeleteOutput{ diff --git a/terraform/node_output_orphan.go b/terraform/node_output_orphan.go deleted file mode 100644 index bb13234b6..000000000 --- a/terraform/node_output_orphan.go +++ /dev/null @@ -1,53 +0,0 @@ -package terraform - -import ( - "fmt" - - "github.com/hashicorp/terraform/addrs" -) - -// NodeOutputOrphan represents an output that is an orphan. -type NodeOutputOrphan struct { - Addr addrs.AbsOutputValue -} - -var ( - _ GraphNodeModuleInstance = (*NodeOutputOrphan)(nil) - _ GraphNodeReferenceable = (*NodeOutputOrphan)(nil) - _ GraphNodeReferenceOutside = (*NodeOutputOrphan)(nil) - _ GraphNodeEvalable = (*NodeOutputOrphan)(nil) -) - -func (n *NodeOutputOrphan) Name() string { - return fmt.Sprintf("%s (orphan)", n.Addr.String()) -} - -// GraphNodeReferenceOutside implementation -func (n *NodeOutputOrphan) ReferenceOutside() (selfPath, referencePath addrs.Module) { - return referenceOutsideForOutput(n.Addr) -} - -// GraphNodeReferenceable -func (n *NodeOutputOrphan) ReferenceableAddrs() []addrs.Referenceable { - return referenceableAddrsForOutput(n.Addr) -} - -// GraphNodeModuleInstance -func (n *NodeOutputOrphan) Path() addrs.ModuleInstance { - return n.Addr.Module -} - -// GraphNodeModulePath -func (n *NodeOutputOrphan) ModulePath() addrs.Module { - return n.Addr.Module.Module() -} - -// GraphNodeEvalable -func (n *NodeOutputOrphan) EvalTree() EvalNode { - return &EvalOpFilter{ - Ops: []walkOperation{walkRefresh, walkApply, walkDestroy}, - Node: &EvalDeleteOutput{ - Addr: n.Addr, - }, - } -} diff --git a/terraform/transform_orphan_output.go b/terraform/transform_orphan_output.go index c67540934..ba1bce932 100644 --- a/terraform/transform_orphan_output.go +++ b/terraform/transform_orphan_output.go @@ -51,7 +51,7 @@ func (t *OrphanOutputTransformer) transform(g *Graph, ms *states.Module) error { continue } - g.Add(&NodeOutputOrphan{ + g.Add(&NodeDestroyableOutput{ Addr: addrs.OutputValue{Name: name}.Absolute(moduleAddr), }) } diff --git a/terraform/transform_output.go b/terraform/transform_output.go index 2582448c9..4d51dabd6 100644 --- a/terraform/transform_output.go +++ b/terraform/transform_output.go @@ -53,14 +53,14 @@ func (t *OutputTransformer) transform(g *Graph, c *configs.Config) error { return nil } -// DestroyOutputTransformer is a GraphTransformer that adds nodes to delete +// destroyRootOutputTransformer is a GraphTransformer that adds nodes to delete // outputs during destroy. We need to do this to ensure that no stale outputs // are ever left in the state. -type DestroyOutputTransformer struct { +type destroyRootOutputTransformer struct { Destroy bool } -func (t *DestroyOutputTransformer) Transform(g *Graph) error { +func (t *destroyRootOutputTransformer) Transform(g *Graph) error { // Only clean root outputs on a full destroy if !t.Destroy { return nil