terraform: handle logical dependencies during a delete

This commit is contained in:
Armon Dadgar 2014-09-17 17:29:54 -07:00
parent cb8e581731
commit af3c55096c
1 changed files with 47 additions and 37 deletions

View File

@ -360,20 +360,10 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error {
Name: fmt.Sprintf("%s (destroy)", newNode.Resource.Id), Name: fmt.Sprintf("%s (destroy)", newNode.Resource.Id),
Meta: newNode, Meta: newNode,
} }
newN.Deps = make([]*depgraph.Dependency, 0, len(n.Deps)) newN.Deps = make([]*depgraph.Dependency, len(n.Deps))
for _, d := range n.Deps {
// We don't want to copy any resource dependencies
if _, ok := d.Target.Meta.(*GraphNodeResource); ok {
continue
}
// TODO: Maybe GraphNodeResourceMeta should be omitted?
newN.Deps = append(newN.Deps, &depgraph.Dependency{ // Copy all the dependencies and do a fixup later
Name: d.Name, copy(newN.Deps, n.Deps)
Source: newN,
Target: d.Target,
})
}
// Append it to the list so we handle it later // Append it to the list so we handle it later
nlist = append(nlist, newN) nlist = append(nlist, newN)
@ -409,33 +399,53 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error {
// Go through each noun and make sure we calculate all the dependencies // Go through each noun and make sure we calculate all the dependencies
// properly. // properly.
for _, n := range nlist { for _, n := range nlist {
rn := n.Meta.(*GraphNodeResource) deps := n.Deps
num := len(deps)
// If we have no dependencies, then just continue for i := 0; i < num; i++ {
deps := rn.Resource.State.Dependencies dep := deps[i]
if len(deps) == 0 { switch target := dep.Target.Meta.(type) {
continue case *GraphNodeResource:
} // If the other node is also being deleted,
// we must be deleted first. E.g. if A -> B,
// We have dependencies. We must be destroyed BEFORE those // then when we create, B is created first then A.
// dependencies. Look to see if they're managed. // On teardown, A is destroyed first, then B.
for _, n2 := range nlist { // Thus we must flip our depedency and instead inject
// Don't ever depend on ourselves // it on B.
if n2.Name == n.Name { for _, n2 := range nlist {
continue rn2 := n2.Meta.(*GraphNodeResource)
} if target.Resource.Id == rn2.Resource.Id {
n2.Deps = append(n2.Deps, &depgraph.Dependency{
for _, dep := range deps { Name: n.Name,
rn2 := n2.Meta.(*GraphNodeResource) Source: n2,
if rn2.Resource.Id == dep { Target: n,
n2.Deps = append(n2.Deps, &depgraph.Dependency{ })
Name: n.Name, break
Source: n2, }
Target: n,
})
} }
// Drop the dependency. We may have created
// an inverse depedency if the dependent resource
// is also being deleted, but this dependence is
// no longer required.
deps[i], deps[num-1] = deps[num-1], nil
num--
i--
case *GraphNodeResourceMeta:
// Drop the dependency, since there is
// nothing that needs to be done for a meta
// resource on destroy.
deps[i], deps[num-1] = deps[num-1], nil
num--
i--
case *GraphNodeResourceProvider:
// Keep these around
default:
panic(fmt.Errorf("Unhandled depedency type: %#v", dep.Meta))
} }
} }
n.Deps = deps[:num]
} }
// Add the nouns to the graph // Add the nouns to the graph