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.
This commit is contained in:
James Bardin 2018-06-01 09:13:14 -04:00 committed by Martin Atkins
parent fb70eaa7d1
commit fa87397f50
3 changed files with 49 additions and 3 deletions

View File

@ -12,6 +12,8 @@ import (
// it is ready to be applied and is represented by a diff. // it is ready to be applied and is represented by a diff.
type NodeApplyableResourceInstance struct { type NodeApplyableResourceInstance struct {
*NodeAbstractResourceInstance *NodeAbstractResourceInstance
destroyNode GraphNodeDestroyerCBD
} }
var ( var (
@ -22,6 +24,27 @@ var (
_ GraphNodeEvalable = (*NodeApplyableResourceInstance)(nil) _ 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 // GraphNodeCreator
func (n *NodeApplyableResourceInstance) CreateAddr() *addrs.AbsResourceInstance { func (n *NodeApplyableResourceInstance) CreateAddr() *addrs.AbsResourceInstance {
addr := n.ResourceInstanceAddr() 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 // 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 // changes to be updated across two applies in this case, since the first
// plan will use the old values. // plan will use the old values.
cbd := n.Config != nil && n.Config.Managed != nil && n.Config.Managed.CreateBeforeDestroy if !n.createBeforeDestroy() {
if !cbd {
for _, ref := range ret { for _, ref := range ret {
switch tr := ref.Subject.(type) { switch tr := ref.Subject.(type) {
case addrs.ResourceInstance: case addrs.ResourceInstance:
@ -214,7 +236,7 @@ func (n *NodeApplyableResourceInstance) evalTreeManagedResource(addr addrs.AbsRe
destroy = diffApply.GetDestroy() || diffApply.RequiresNew() destroy = diffApply.GetDestroy() || diffApply.RequiresNew()
} }
if destroy && n.Config.Managed != nil && n.Config.Managed.CreateBeforeDestroy { if destroy && n.createBeforeDestroy() {
createBeforeDestroyEnabled = true createBeforeDestroyEnabled = true
} }

View File

@ -23,6 +23,20 @@ type GraphNodeDestroyerCBD interface {
ModifyCreateBeforeDestroy(bool) error 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 // CBDEdgeTransformer modifies the edges of CBD nodes that went through
// the DestroyEdgeTransformer to have the right dependencies. There are // the DestroyEdgeTransformer to have the right dependencies. There are
// two real tasks here: // two real tasks here:

View File

@ -110,6 +110,16 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error {
dag.VertexName(a), dag.VertexName(a_d)) dag.VertexName(a), dag.VertexName(a_d))
g.Connect(&DestroyEdge{S: a, T: 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)
}
}
} }
} }