core: Local and output values must reference destroy nodes too

Because we currently rely on the ReferenceTransformer to introduce the
necessary edges between local/output values and resource destroy nodes, we
must include the destroy phase of any resource we depend on in the
references of these.

This works in conjunction with the changes in the prior commit to restore
correct handling of dependencies for local and output values during
destroy.

With the current design, several seemingly-separate parts of the code must
all coincidentally agree with one another for destroy edges to be created
properly, which makes this code very hard to maintain. In future we should
refactor this so that ReferenceTransformer doesn't create edges for
destroy nodes at all, and have _all_ destroy edges (including
create_before_destroy) be dealt with in the single DestroyEdgeTransformer,
where they can be maintained and unit tested together.
This commit is contained in:
Martin Atkins 2018-05-30 13:16:39 -07:00
parent 6bbfbab93e
commit de7b834de7
3 changed files with 25 additions and 2 deletions

View File

@ -47,7 +47,7 @@ func (n *NodeLocal) ReferenceableAddrs() []addrs.Referenceable {
// GraphNodeReferencer
func (n *NodeLocal) References() []*addrs.Reference {
refs, _ := lang.ReferencesInExpr(n.Config.Expr)
return refs
return appendResourceDestroyReferences(refs)
}
// GraphNodeEvalable

View File

@ -108,7 +108,7 @@ func referencesForOutput(c *configs.Output) []*addrs.Reference {
// GraphNodeReferencer
func (n *NodeApplyableOutput) References() []*addrs.Reference {
return referencesForOutput(n.Config)
return appendResourceDestroyReferences(referencesForOutput(n.Config))
}
// GraphNodeEvalable

View File

@ -453,6 +453,29 @@ func ReferenceFromInterpolatedVar(v config.InterpolatedVariable) []string {
}
}
// appendResourceDestroyReferences identifies resource and resource instance
// references in the given slice and appends to it the "destroy-phase"
// equivalents of those references, returning the result.
//
// This can be used in the References implementation for a node which must also
// depend on the destruction of anything it references.
func appendResourceDestroyReferences(refs []*addrs.Reference) []*addrs.Reference {
given := refs
for _, ref := range given {
switch tr := ref.Subject.(type) {
case addrs.Resource:
newRef := *ref // shallow copy
newRef.Subject = tr.Phase(addrs.ResourceInstancePhaseDestroy)
refs = append(refs, &newRef)
case addrs.ResourceInstance:
newRef := *ref // shallow copy
newRef.Subject = tr.Phase(addrs.ResourceInstancePhaseDestroy)
refs = append(refs, &newRef)
}
}
return refs
}
func modulePrefixStr(p addrs.ModuleInstance) string {
return p.String()
}