From b2188d7fe8de7322136529c07125146167257c44 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Thu, 18 Sep 2014 14:31:27 -0700 Subject: [PATCH] terraform: properly handle diff generation with meta resources --- terraform/graph.go | 19 +++++++ terraform/graph_test.go | 114 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) diff --git a/terraform/graph.go b/terraform/graph.go index 65fcef650..303a6e659 100644 --- a/terraform/graph.go +++ b/terraform/graph.go @@ -447,6 +447,25 @@ func graphAddDiff(g *depgraph.Graph, d *Diff) error { i-- case *GraphNodeResourceMeta: + // Check if any of the resources part of the meta node + // are being destroyed, because we must be destroyed first. + for i := 0; i < target.Count; i++ { + id := fmt.Sprintf("%s.%d", target.ID, i) + for _, n2 := range nlist { + rn2 := n2.Meta.(*GraphNodeResource) + if id == rn2.Resource.Id { + newDep := &depgraph.Dependency{ + Name: n.Name, + Source: n2, + Target: n, + } + injected[newDep] = struct{}{} + n2.Deps = append(n2.Deps, newDep) + break + } + } + } + // Drop the dependency, since there is // nothing that needs to be done for a meta // resource on destroy. diff --git a/terraform/graph_test.go b/terraform/graph_test.go index fbf444759..3f64380df 100644 --- a/terraform/graph_test.go +++ b/terraform/graph_test.go @@ -354,6 +354,93 @@ func TestGraphAddDiff_destroy(t *testing.T) { } } +func TestGraphAddDiff_destroy_counts(t *testing.T) { + config := testConfig(t, "graph-count") + diff := &Diff{ + Resources: map[string]*InstanceDiff{ + "aws_instance.web.0": &InstanceDiff{ + Destroy: true, + }, + "aws_instance.web.1": &InstanceDiff{ + Destroy: true, + }, + "aws_instance.web.2": &InstanceDiff{ + Destroy: true, + }, + "aws_load_balancer.weblb": &InstanceDiff{ + Destroy: true, + }, + }, + } + state := &State{ + Modules: []*ModuleState{ + &ModuleState{ + Path: rootModulePath, + Resources: map[string]*ResourceState{ + "aws_instance.web.0": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_instance.web.1": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_instance.web.2": &ResourceState{ + Type: "aws_instance", + Primary: &InstanceState{ + ID: "foo", + }, + }, + "aws_load_balancer.weblb": &ResourceState{ + Type: "aws_load_balancer", + Dependencies: []string{"aws_instance.web.0", "aws_instance.web.1", "aws_instance.web.2"}, + Primary: &InstanceState{ + ID: "bar", + }, + }, + }, + }, + }, + } + + diffHash := checksumStruct(t, diff) + + g, err := Graph(&GraphOpts{ + Config: config, + Diff: diff, + State: state, + }) + if err != nil { + t.Fatalf("err: %s", err) + } + + actual := strings.TrimSpace(g.String()) + expected := strings.TrimSpace(testTerraformGraphDiffDestroyCountsStr) + if actual != expected { + t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected) + } + + // Verify that the state has been added + n := g.Noun("aws_instance.web.0 (destroy)") + rn := n.Meta.(*GraphNodeResource) + + expected2 := &InstanceDiff{Destroy: true} + actual2 := rn.Resource.Diff + if !reflect.DeepEqual(actual2, expected2) { + t.Fatalf("bad: %#v", actual2) + } + + // Verify that our original structure has not been modified + diffHash2 := checksumStruct(t, diff) + if diffHash != diffHash2 { + t.Fatal("diff has been modified") + } +} + func TestEncodeDependencies(t *testing.T) { config := testConfig(t, "graph-basic") state := &State{ @@ -530,6 +617,33 @@ root root -> aws_instance.foo ` +const testTerraformGraphDiffDestroyCountsStr = ` +root: root +aws_instance.web + aws_instance.web -> aws_instance.web.0 + aws_instance.web -> aws_instance.web.1 + aws_instance.web -> aws_instance.web.2 +aws_instance.web.0 + aws_instance.web.0 -> aws_instance.web.0 (destroy) +aws_instance.web.0 (destroy) + aws_instance.web.0 (destroy) -> aws_load_balancer.weblb (destroy) +aws_instance.web.1 + aws_instance.web.1 -> aws_instance.web.1 (destroy) +aws_instance.web.1 (destroy) + aws_instance.web.1 (destroy) -> aws_load_balancer.weblb (destroy) +aws_instance.web.2 + aws_instance.web.2 -> aws_instance.web.2 (destroy) +aws_instance.web.2 (destroy) + aws_instance.web.2 (destroy) -> aws_load_balancer.weblb (destroy) +aws_load_balancer.weblb + aws_load_balancer.weblb -> aws_instance.web + aws_load_balancer.weblb -> aws_load_balancer.weblb (destroy) +aws_load_balancer.weblb (destroy) +root + root -> aws_instance.web + root -> aws_load_balancer.weblb +` + const testTerraformGraphStateStr = ` root: root aws_instance.old