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,34 +399,54 @@ 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.
// Thus we must flip our depedency and instead inject
// it on B.
for _, n2 := range nlist { for _, n2 := range nlist {
// Don't ever depend on ourselves
if n2.Name == n.Name {
continue
}
for _, dep := range deps {
rn2 := n2.Meta.(*GraphNodeResource) rn2 := n2.Meta.(*GraphNodeResource)
if rn2.Resource.Id == dep { if target.Resource.Id == rn2.Resource.Id {
n2.Deps = append(n2.Deps, &depgraph.Dependency{ n2.Deps = append(n2.Deps, &depgraph.Dependency{
Name: n.Name, Name: n.Name,
Source: n2, Source: n2,
Target: n, Target: n,
}) })
break
} }
} }
// 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
g.Nouns = append(g.Nouns, nlist...) g.Nouns = append(g.Nouns, nlist...)