mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
terraform: graph can add "destroy" nodes
This commit is contained in:
parent
6f274eb7a9
commit
2d72164c6a
@ -111,9 +111,8 @@ func GraphFull(g *depgraph.Graph, ps map[string]ResourceProviderFactory) error {
|
|||||||
// destroying the VPC's subnets first, whereas creating a VPC requires
|
// destroying the VPC's subnets first, whereas creating a VPC requires
|
||||||
// doing it before the subnets are created. This function handles inserting
|
// doing it before the subnets are created. This function handles inserting
|
||||||
// these nodes for you.
|
// these nodes for you.
|
||||||
//
|
|
||||||
// Note that all nodes modifying the same resource will have the same name.
|
|
||||||
func GraphAddDiff(g *depgraph.Graph, d *Diff) error {
|
func GraphAddDiff(g *depgraph.Graph, d *Diff) error {
|
||||||
|
var nlist []*depgraph.Noun
|
||||||
for _, n := range g.Nouns {
|
for _, n := range g.Nouns {
|
||||||
rn, ok := n.Meta.(*GraphNodeResource)
|
rn, ok := n.Meta.(*GraphNodeResource)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -124,10 +123,79 @@ func GraphAddDiff(g *depgraph.Graph, d *Diff) error {
|
|||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if rd.Empty() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if rd.Destroy || rd.RequiresNew() {
|
||||||
|
// If we're destroying, we create a new destroy node with
|
||||||
|
// the proper dependencies. Perform a dirty copy operation.
|
||||||
|
newNode := new(GraphNodeResource)
|
||||||
|
*newNode = *rn
|
||||||
|
newNode.Resource = new(Resource)
|
||||||
|
*newNode.Resource = *rn.Resource
|
||||||
|
|
||||||
|
// Make the diff _just_ the destroy.
|
||||||
|
newNode.Resource.Diff = &ResourceDiff{Destroy: true}
|
||||||
|
|
||||||
|
// Append it to the list so we handle it later
|
||||||
|
deps := make([]*depgraph.Dependency, len(n.Deps))
|
||||||
|
copy(deps, n.Deps)
|
||||||
|
newN := &depgraph.Noun{
|
||||||
|
Name: fmt.Sprintf("%s (destroy)", newNode.Resource.Id),
|
||||||
|
Meta: newNode,
|
||||||
|
Deps: deps,
|
||||||
|
}
|
||||||
|
nlist = append(nlist, newN)
|
||||||
|
|
||||||
|
// Mark the old diff to not destroy since we handle that in
|
||||||
|
// the dedicated node.
|
||||||
|
rd.Destroy = false
|
||||||
|
|
||||||
|
// Add to the new noun to our dependencies so that the destroy
|
||||||
|
// happens before the apply.
|
||||||
|
n.Deps = append(n.Deps, &depgraph.Dependency{
|
||||||
|
Name: newN.Name,
|
||||||
|
Source: n,
|
||||||
|
Target: newN,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
rn.Resource.Diff = rd
|
rn.Resource.Diff = rd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through each noun and make sure we calculate all the dependencies
|
||||||
|
// properly.
|
||||||
|
for _, n := range nlist {
|
||||||
|
rn := n.Meta.(*GraphNodeResource)
|
||||||
|
|
||||||
|
// If we have no dependencies, then just continue
|
||||||
|
deps := rn.Resource.State.Dependencies
|
||||||
|
if len(deps) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have dependencies. We must be destroyed BEFORE those
|
||||||
|
// dependencies. Look to see if they're managed.
|
||||||
|
for _, dep := range deps {
|
||||||
|
for _, n2 := range nlist {
|
||||||
|
rn2 := n2.Meta.(*GraphNodeResource)
|
||||||
|
if rn2.Resource.State.ID == dep.ID {
|
||||||
|
n2.Deps = append(n2.Deps, &depgraph.Dependency{
|
||||||
|
Name: n.Name,
|
||||||
|
Source: n2,
|
||||||
|
Target: n,
|
||||||
|
})
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the nouns to the graph
|
||||||
|
g.Nouns = append(g.Nouns, nlist...)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,6 +154,67 @@ func TestGraphAddDiff(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGraphAddDiff_destroy(t *testing.T) {
|
||||||
|
config := testConfig(t, "graph-diff-destroy")
|
||||||
|
state := &State{
|
||||||
|
Resources: map[string]*ResourceState{
|
||||||
|
"aws_instance.foo": &ResourceState{
|
||||||
|
ID: "foo",
|
||||||
|
Type: "aws_instance",
|
||||||
|
},
|
||||||
|
|
||||||
|
"aws_instance.bar": &ResourceState{
|
||||||
|
ID: "bar",
|
||||||
|
Type: "aws_instance",
|
||||||
|
Dependencies: []ResourceDependency{
|
||||||
|
ResourceDependency{
|
||||||
|
ID: "foo",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
g := Graph(config, state)
|
||||||
|
if err := g.Validate(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := &Diff{
|
||||||
|
Resources: map[string]*ResourceDiff{
|
||||||
|
"aws_instance.foo": &ResourceDiff{
|
||||||
|
Destroy: true,
|
||||||
|
},
|
||||||
|
"aws_instance.bar": &ResourceDiff{
|
||||||
|
Destroy: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := GraphAddDiff(g, diff); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
if err := g.Validate(); err != nil {
|
||||||
|
t.Fatalf("err: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual := strings.TrimSpace(g.String())
|
||||||
|
expected := strings.TrimSpace(testTerraformGraphDiffDestroyStr)
|
||||||
|
if actual != expected {
|
||||||
|
t.Fatalf("bad:\n\n%s", actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the state has been added
|
||||||
|
n := g.Noun("aws_instance.foo")
|
||||||
|
rn := n.Meta.(*GraphNodeResource)
|
||||||
|
|
||||||
|
expected2 := diff.Resources["aws_instance.foo"]
|
||||||
|
actual2 := rn.Resource.Diff
|
||||||
|
if !reflect.DeepEqual(actual2, expected2) {
|
||||||
|
t.Fatalf("bad: %#v", actual2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const testTerraformGraphStr = `
|
const testTerraformGraphStr = `
|
||||||
root: root
|
root: root
|
||||||
aws_instance.web
|
aws_instance.web
|
||||||
@ -182,6 +243,20 @@ root
|
|||||||
root -> aws_instance.foo
|
root -> aws_instance.foo
|
||||||
`
|
`
|
||||||
|
|
||||||
|
const testTerraformGraphDiffDestroyStr = `
|
||||||
|
root: root
|
||||||
|
aws_instance.bar
|
||||||
|
aws_instance.bar -> aws_instance.bar (destroy)
|
||||||
|
aws_instance.bar (destroy)
|
||||||
|
aws_instance.foo
|
||||||
|
aws_instance.foo -> aws_instance.foo (destroy)
|
||||||
|
aws_instance.foo (destroy)
|
||||||
|
aws_instance.foo (destroy) -> aws_instance.bar (destroy)
|
||||||
|
root
|
||||||
|
root -> aws_instance.bar
|
||||||
|
root -> aws_instance.foo
|
||||||
|
`
|
||||||
|
|
||||||
const testTerraformGraphStateStr = `
|
const testTerraformGraphStateStr = `
|
||||||
root: root
|
root: root
|
||||||
aws_instance.old
|
aws_instance.old
|
||||||
|
2
terraform/test-fixtures/graph-diff-destroy/main.tf
Normal file
2
terraform/test-fixtures/graph-diff-destroy/main.tf
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
resource "aws_instance" "foo" {
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user