From fa87397f50c92bdc247110b8de3219122854c74d Mon Sep 17 00:00:00 2001 From: James Bardin Date: Fri, 1 Jun 2018 09:13:14 -0400 Subject: [PATCH] core: GraphNodeAttachDestroyer Add a graphNodeAttachDestroy interface, so destroy nodes can be attached to their companion create node. The creator can then reference the CreateBeforeDestroy status of the destroyer, determining if the current state needs to be replaced or deposed. This is needed when a node is forced to become CreateBeforeDestroy by a dependency rather than the config, since because the config is immutable, only the destroyer is aware that it has been forced CreateBeforeDestroy. --- terraform/node_resource_apply.go | 28 +++++++++++++++++++++++++--- terraform/transform_destroy_cbd.go | 14 ++++++++++++++ terraform/transform_destroy_edge.go | 10 ++++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/terraform/node_resource_apply.go b/terraform/node_resource_apply.go index c72865e9f..52c9af40b 100644 --- a/terraform/node_resource_apply.go +++ b/terraform/node_resource_apply.go @@ -12,6 +12,8 @@ import ( // it is ready to be applied and is represented by a diff. type NodeApplyableResourceInstance struct { *NodeAbstractResourceInstance + + destroyNode GraphNodeDestroyerCBD } var ( @@ -22,6 +24,27 @@ var ( _ GraphNodeEvalable = (*NodeApplyableResourceInstance)(nil) ) +// GraphNodeAttachDestroyer +func (n *NodeApplyableResourceInstance) AttachDestroyNode(d GraphNodeDestroyerCBD) { + n.destroyNode = d +} + +// createBeforeDestroy checks this nodes config status and the status af any +// companion destroy node for CreateBeforeDestroy. +func (n *NodeApplyableResourceInstance) createBeforeDestroy() bool { + cbd := false + + if n.Config != nil && n.Config.Managed != nil { + cbd = n.Config.Managed.CreateBeforeDestroy + } + + if n.destroyNode != nil { + cbd = cbd || n.destroyNode.CreateBeforeDestroy() + } + + return cbd +} + // GraphNodeCreator func (n *NodeApplyableResourceInstance) CreateAddr() *addrs.AbsResourceInstance { addr := n.ResourceInstanceAddr() @@ -42,8 +65,7 @@ func (n *NodeApplyableResourceInstance) References() []*addrs.Reference { // would create a dependency cycle. We make a compromise here of requiring // changes to be updated across two applies in this case, since the first // plan will use the old values. - cbd := n.Config != nil && n.Config.Managed != nil && n.Config.Managed.CreateBeforeDestroy - if !cbd { + if !n.createBeforeDestroy() { for _, ref := range ret { switch tr := ref.Subject.(type) { case addrs.ResourceInstance: @@ -214,7 +236,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe destroy = diffApply.GetDestroy() || diffApply.RequiresNew() } - if destroy && n.Config.Managed != nil && n.Config.Managed.CreateBeforeDestroy { + if destroy && n.createBeforeDestroy() { createBeforeDestroyEnabled = true } diff --git a/terraform/transform_destroy_cbd.go b/terraform/transform_destroy_cbd.go index 3470e1804..f4cc75ced 100644 --- a/terraform/transform_destroy_cbd.go +++ b/terraform/transform_destroy_cbd.go @@ -23,6 +23,20 @@ type GraphNodeDestroyerCBD interface { ModifyCreateBeforeDestroy(bool) error } +// GraphNodeAttachDestroyer is implemented by applyable nodes that have a +// companion destroy node. This allows the creation node to look up the status +// of the destroy node and determine if it needs to depose the existing state, +// or replace it. +// If a node is not marked as create-before-destroy in the configuration, but a +// dependency forces that status, only the destroy node will be aware of that +// status. +type GraphNodeAttachDestroyer interface { + // AttachDestroyNode takes a destroy node and saves a reference to that + // node in the receiver, so it can later check the status of + // CreateBeforeDestroy(). + AttachDestroyNode(n GraphNodeDestroyerCBD) +} + // CBDEdgeTransformer modifies the edges of CBD nodes that went through // the DestroyEdgeTransformer to have the right dependencies. There are // two real tasks here: diff --git a/terraform/transform_destroy_edge.go b/terraform/transform_destroy_edge.go index 80adf666a..bda93bec7 100644 --- a/terraform/transform_destroy_edge.go +++ b/terraform/transform_destroy_edge.go @@ -110,6 +110,16 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { dag.VertexName(a), dag.VertexName(a_d)) g.Connect(&DestroyEdge{S: a, T: a_d}) + + // Attach the destroy node to the creator + // There really shouldn't be more than one destroyer, but even if + // there are, any of them will represent the correct + // CreateBeforeDestroy status. + if n, ok := cn.(GraphNodeAttachDestroyer); ok { + if d, ok := d.(GraphNodeDestroyerCBD); ok { + n.AttachDestroyNode(d) + } + } } }