diff --git a/terraform/context.go b/terraform/context.go index afe1c2e11..0841223e9 100644 --- a/terraform/context.go +++ b/terraform/context.go @@ -289,10 +289,11 @@ func (c *Context) Graph(typ GraphType, opts *ContextGraphOpts) (*Graph, tfdiags. case GraphTypePlanDestroy: return (&DestroyPlanGraphBuilder{ - Config: c.config, - State: c.state, - Targets: c.targets, - Validate: opts.Validate, + Config: c.config, + State: c.state, + Components: c.components, + Targets: c.targets, + Validate: opts.Validate, }).Build(addrs.RootModuleInstance) case GraphTypeRefresh: diff --git a/terraform/graph_builder_apply.go b/terraform/graph_builder_apply.go index 6eca326e7..2721e7113 100644 --- a/terraform/graph_builder_apply.go +++ b/terraform/graph_builder_apply.go @@ -88,10 +88,18 @@ func (b *ApplyGraphBuilder) Steps() []GraphTransformer { TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config), // Destruction ordering - &DestroyEdgeTransformer{Config: b.Config, State: b.State}, + &DestroyEdgeTransformer{ + Config: b.Config, + State: b.State, + Components: b.Components, + }, GraphTransformIf( func() bool { return !b.Destroy }, - &CBDEdgeTransformer{Config: b.Config, State: b.State}, + &CBDEdgeTransformer{ + Config: b.Config, + State: b.State, + Components: b.Components, + }, ), // Provisioner-related transformations diff --git a/terraform/graph_builder_destroy_plan.go b/terraform/graph_builder_destroy_plan.go index 9d524554b..dbf43e0e9 100644 --- a/terraform/graph_builder_destroy_plan.go +++ b/terraform/graph_builder_destroy_plan.go @@ -22,6 +22,10 @@ type DestroyPlanGraphBuilder struct { // Targets are resources to target Targets []addrs.Targetable + // Components is a factory for the plug-in components (providers and + // provisioners) available for use. + Components contextComponentFactory + // Validate will do structural validation of the graph. Validate bool } @@ -55,7 +59,11 @@ func (b *DestroyPlanGraphBuilder) Steps() []GraphTransformer { // Destruction ordering. We require this only so that // targeting below will prune the correct things. - &DestroyEdgeTransformer{Config: b.Config, State: b.State}, + &DestroyEdgeTransformer{ + Config: b.Config, + State: b.State, + Components: b.Components, + }, // Target. Note we don't set "Destroy: true" here since we already // created proper destroy ordering. diff --git a/terraform/test-fixtures/transform-destroy-edge-basic/main.tf b/terraform/test-fixtures/transform-destroy-edge-basic/main.tf index 50f87223a..8afeda4fe 100644 --- a/terraform/test-fixtures/transform-destroy-edge-basic/main.tf +++ b/terraform/test-fixtures/transform-destroy-edge-basic/main.tf @@ -1,5 +1,5 @@ -resource "test" "A" {} +resource "test_object" "A" {} -resource "test" "B" { - value = "${test.A.value}" +resource "test_object" "B" { + test_string = "${test_object.A.test_string}" } diff --git a/terraform/test-fixtures/transform-destroy-edge-module-only/child/main.tf b/terraform/test-fixtures/transform-destroy-edge-module-only/child/main.tf index 2ae3859a8..242bb3359 100644 --- a/terraform/test-fixtures/transform-destroy-edge-module-only/child/main.tf +++ b/terraform/test-fixtures/transform-destroy-edge-module-only/child/main.tf @@ -1,8 +1,9 @@ -resource "aws_instance" "a" {} -resource "aws_instance" "b" { - value = "${aws_instance.a.id}" +resource "test_object" "a" {} + +resource "test_object" "b" { + test_string = "${test_object.a.test_string}" } -resource "aws_instance" "c" { - value = "${aws_instance.b.id}" +resource "test_object" "c" { + test_string = "${test_object.b.test_string}" } diff --git a/terraform/test-fixtures/transform-destroy-edge-module/child/main.tf b/terraform/test-fixtures/transform-destroy-edge-module/child/main.tf index 22a0ce4fd..337bbe754 100644 --- a/terraform/test-fixtures/transform-destroy-edge-module/child/main.tf +++ b/terraform/test-fixtures/transform-destroy-edge-module/child/main.tf @@ -1,7 +1,7 @@ -resource "aws_instance" "b" { - value = "foo" +resource "test_object" "b" { + test_string = "foo" } output "output" { - value = "${aws_instance.b.value}" + value = "${test_object.b.test_string}" } diff --git a/terraform/test-fixtures/transform-destroy-edge-module/main.tf b/terraform/test-fixtures/transform-destroy-edge-module/main.tf index 207e6d043..2a42635e4 100644 --- a/terraform/test-fixtures/transform-destroy-edge-module/main.tf +++ b/terraform/test-fixtures/transform-destroy-edge-module/main.tf @@ -1,7 +1,7 @@ -resource "aws_instance" "a" { - value = "${module.child.output}" +resource "test_object" "a" { + test_string = "${module.child.output}" } module "child" { - source = "./child" + source = "./child" } diff --git a/terraform/test-fixtures/transform-destroy-edge-multi/main.tf b/terraform/test-fixtures/transform-destroy-edge-multi/main.tf index 632d21318..3474bf60a 100644 --- a/terraform/test-fixtures/transform-destroy-edge-multi/main.tf +++ b/terraform/test-fixtures/transform-destroy-edge-multi/main.tf @@ -1,9 +1,9 @@ -resource "test" "A" {} +resource "test_object" "A" {} -resource "test" "B" { - value = "${test.A.value}" +resource "test_object" "B" { + test_string = "${test_object.A.test_string}" } -resource "test" "C" { - value = "${test.B.value}" +resource "test_object" "C" { + test_string = "${test_object.B.test_string}" } diff --git a/terraform/test-fixtures/transform-destroy-edge-splat/main.tf b/terraform/test-fixtures/transform-destroy-edge-splat/main.tf index 3ed06ae1b..88d8b840b 100644 --- a/terraform/test-fixtures/transform-destroy-edge-splat/main.tf +++ b/terraform/test-fixtures/transform-destroy-edge-splat/main.tf @@ -1,5 +1,6 @@ -resource "test" "A" {} -resource "test" "B" { - count = 2 - value = "${test.A.*.value}" +resource "test_object" "A" {} + +resource "test_object" "B" { + count = 2 + test_string = "${test_object.A.*.test_string}" } diff --git a/terraform/transform_destroy_cbd.go b/terraform/transform_destroy_cbd.go index c489adad4..6134e5a55 100644 --- a/terraform/transform_destroy_cbd.go +++ b/terraform/transform_destroy_cbd.go @@ -40,11 +40,14 @@ type CBDEdgeTransformer struct { // any way possible. Either can be nil if not availabile. Config *configs.Config State *State + + // If configuration is present then Components is required in order to + // obtain schema information from providers and provisioners in order + // to properly resolve implicit dependencies. + Components contextComponentFactory } func (t *CBDEdgeTransformer) Transform(g *Graph) error { - log.Printf("[TRACE] CBDEdgeTransformer: Beginning CBD transformation...") - // Go through and reverse any destroy edges destroyMap := make(map[string][]dag.Vertex) for _, v := range g.Vertices() { @@ -64,6 +67,7 @@ func (t *CBDEdgeTransformer) Transform(g *Graph) error { // and we need to auto-upgrade this node to CBD. We do this because // a CBD node depending on non-CBD will result in cycles. To avoid this, // we always attempt to upgrade it. + log.Printf("[TRACE] CBDEdgeTransformer: forcing create_before_destroy on for %q (%T)", dag.VertexName(v), v) if err := dn.ModifyCreateBeforeDestroy(true); err != nil { return fmt.Errorf( "%s: must have create before destroy enabled because "+ @@ -174,6 +178,7 @@ func (t *CBDEdgeTransformer) depMap(destroyMap map[string][]dag.Vertex) (map[str &FlatConfigTransformer{Config: t.Config}, &AttachResourceConfigTransformer{Config: t.Config}, &AttachStateTransformer{State: t.State}, + &AttachSchemaTransformer{Components: t.Components}, &ReferenceTransformer{}, }, Name: "CBDEdgeTransformer", diff --git a/terraform/transform_destroy_cbd_test.go b/terraform/transform_destroy_cbd_test.go index 07d30810b..6def3fff4 100644 --- a/terraform/transform_destroy_cbd_test.go +++ b/terraform/transform_destroy_cbd_test.go @@ -9,15 +9,16 @@ import ( func TestCBDEdgeTransformer(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeCreatorTest{AddrString: "test.A"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.B"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.A", CBD: true}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.B"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A", CBD: true}) module := testModule(t, "transform-destroy-edge-basic") { tf := &DestroyEdgeTransformer{ - Config: module, + Config: module, + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -25,7 +26,10 @@ func TestCBDEdgeTransformer(t *testing.T) { } { - tf := &CBDEdgeTransformer{Config: module} + tf := &CBDEdgeTransformer{ + Config: module, + Components: simpleMockComponentFactory(), + } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) } @@ -34,22 +38,23 @@ func TestCBDEdgeTransformer(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformCBDEdgeBasicStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestCBDEdgeTransformer_depNonCBD(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeCreatorTest{AddrString: "test.A"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.B"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.A"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.B", CBD: true}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.B"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B", CBD: true}) module := testModule(t, "transform-destroy-edge-basic") { tf := &DestroyEdgeTransformer{ - Config: module, + Config: module, + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -57,7 +62,10 @@ func TestCBDEdgeTransformer_depNonCBD(t *testing.T) { } { - tf := &CBDEdgeTransformer{Config: module} + tf := &CBDEdgeTransformer{ + Config: module, + Components: simpleMockComponentFactory(), + } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) } @@ -66,22 +74,23 @@ func TestCBDEdgeTransformer_depNonCBD(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformCBDEdgeDepNonCBDStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeCreatorTest{AddrString: "test.A"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.B[0]"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.B[1]"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.A", CBD: true}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[0]"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[1]"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A", CBD: true}) module := testModule(t, "transform-destroy-edge-splat") { tf := &DestroyEdgeTransformer{ - Config: module, + Config: module, + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -89,7 +98,10 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) { } { - tf := &CBDEdgeTransformer{Config: module} + tf := &CBDEdgeTransformer{ + Config: module, + Components: simpleMockComponentFactory(), + } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) } @@ -97,33 +109,34 @@ func TestCBDEdgeTransformer_depNonCBDCount(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(` -test.A -test.A (destroy) - test.A - test.B[0] - test.B[1] -test.B[0] -test.B[1] +test_object.A +test_object.A (destroy) + test_object.A + test_object.B[0] + test_object.B[1] +test_object.B[0] +test_object.B[1] `) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeCreatorTest{AddrString: "test.A[0]"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.A[1]"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.B[0]"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.B[1]"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.A[0]", CBD: true}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.A[1]", CBD: true}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.A[0]"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.A[1]"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[0]"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.B[1]"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A[0]", CBD: true}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A[1]", CBD: true}) module := testModule(t, "transform-destroy-edge-splat") { tf := &DestroyEdgeTransformer{ - Config: module, + Config: module, + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -131,7 +144,10 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) { } { - tf := &CBDEdgeTransformer{Config: module} + tf := &CBDEdgeTransformer{ + Config: module, + Components: simpleMockComponentFactory(), + } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) } @@ -139,39 +155,39 @@ func TestCBDEdgeTransformer_depNonCBDCountBoth(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(` -test.A[0] -test.A[0] (destroy) - test.A[0] - test.B[0] - test.B[1] -test.A[1] -test.A[1] (destroy) - test.A[1] - test.B[0] - test.B[1] -test.B[0] -test.B[1] +test_object.A[0] +test_object.A[0] (destroy) + test_object.A[0] + test_object.B[0] + test_object.B[1] +test_object.A[1] +test_object.A[1] (destroy) + test_object.A[1] + test_object.B[0] + test_object.B[1] +test_object.B[0] +test_object.B[1] `) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } const testTransformCBDEdgeBasicStr = ` -test.A -test.A (destroy) - test.A - test.B -test.B +test_object.A +test_object.A (destroy) + test_object.A + test_object.B +test_object.B ` const testTransformCBDEdgeDepNonCBDStr = ` -test.A -test.A (destroy) (modified) - test.A - test.B - test.B (destroy) -test.B -test.B (destroy) - test.B +test_object.A +test_object.A (destroy) (modified) + test_object.A + test_object.B + test_object.B (destroy) +test_object.B +test_object.B (destroy) + test_object.B ` diff --git a/terraform/transform_destroy_edge.go b/terraform/transform_destroy_edge.go index dfed29606..a04b3ae7e 100644 --- a/terraform/transform_destroy_edge.go +++ b/terraform/transform_destroy_edge.go @@ -44,11 +44,14 @@ type DestroyEdgeTransformer struct { // to determine what a destroy node depends on. Any of these can be nil. Config *configs.Config State *State + + // If configuration is present then Components is required in order to + // obtain schema information from providers and provisioners in order + // to properly resolve implicit dependencies. + Components contextComponentFactory } func (t *DestroyEdgeTransformer) Transform(g *Graph) error { - log.Printf("[TRACE] DestroyEdgeTransformer: Beginning destroy edge transformation...") - // Build a map of what is being destroyed (by address string) to // the list of destroyers. In general there will only be one destroyer // but to make it more robust we support multiple. @@ -67,7 +70,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { addr := *addrP key := addr.String() - log.Printf("[TRACE] DestroyEdgeTransformer: %s will destroy %s", dag.VertexName(dn), key) + log.Printf("[TRACE] DestroyEdgeTransformer: %q (%T) destroys %s", dag.VertexName(dn), v, key) destroyers[key] = append(destroyers[key], dn) destroyerAddrs[key] = addr } @@ -103,7 +106,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { a := v log.Printf( - "[TRACE] DestroyEdgeTransformer: connecting creator/destroyer: %s, %s", + "[TRACE] DestroyEdgeTransformer: connecting creator %q with destroyer %q", dag.VertexName(a), dag.VertexName(a_d)) g.Connect(&DestroyEdge{S: a, T: a_d}) @@ -138,6 +141,10 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { &RootVariableTransformer{Config: t.Config}, &ModuleVariableTransformer{Config: t.Config}, + // Must be before ReferenceTransformer, since schema is required to + // extract references from config. + &AttachSchemaTransformer{Components: t.Components}, + &ReferenceTransformer{}, } @@ -157,12 +164,7 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { // This part is a little bit weird but is the best way to // find the dependencies we need to: build a graph and use the // attach config and state transformers then ask for references. - abstract := &NodeAbstractResourceInstance{ - NodeAbstractResource: NodeAbstractResource{ - Addr: addr.ContainingResource(), - }, - InstanceKey: addr.Resource.Key, - } + abstract := NewNodeAbstractResourceInstance(addr) tempG.Add(abstract) tempDestroyed = append(tempDestroyed, abstract) @@ -175,13 +177,15 @@ func (t *DestroyEdgeTransformer) Transform(g *Graph) error { // Run the graph transforms so we have the information we need to // build references. + log.Println("[TRACE] DestroyEdgeTransformer: constructing temporary graph for analysis of references") for _, s := range steps { + log.Printf("[TRACE] DestroyEdgeTransformer: running %T on temporary graph", s) if err := s.Transform(&tempG); err != nil { + log.Printf("[TRACE] DestroyEdgeTransformer: %T failed: %s", s, err) return err } } - - log.Printf("[TRACE] DestroyEdgeTransformer: reference graph: %s", tempG.String()) + log.Printf("[TRACE] DestroyEdgeTransformer: temporary reference graph: %s", tempG.String()) // Go through all the nodes in the graph and determine what they // depend on. diff --git a/terraform/transform_destroy_edge_test.go b/terraform/transform_destroy_edge_test.go index 73acc15db..b3debd366 100644 --- a/terraform/transform_destroy_edge_test.go +++ b/terraform/transform_destroy_edge_test.go @@ -9,10 +9,11 @@ import ( func TestDestroyEdgeTransformer_basic(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeDestroyerTest{AddrString: "test.A"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.B"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B"}) tf := &DestroyEdgeTransformer{ - Config: testModule(t, "transform-destroy-edge-basic"), + Config: testModule(t, "transform-destroy-edge-basic"), + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -21,17 +22,18 @@ func TestDestroyEdgeTransformer_basic(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformDestroyEdgeBasicStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestDestroyEdgeTransformer_create(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeDestroyerTest{AddrString: "test.A"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.B"}) - g.Add(&graphNodeCreatorTest{AddrString: "test.A"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B"}) + g.Add(&graphNodeCreatorTest{AddrString: "test_object.A"}) tf := &DestroyEdgeTransformer{ - Config: testModule(t, "transform-destroy-edge-basic"), + Config: testModule(t, "transform-destroy-edge-basic"), + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -40,17 +42,18 @@ func TestDestroyEdgeTransformer_create(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformDestroyEdgeCreatorStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestDestroyEdgeTransformer_multi(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeDestroyerTest{AddrString: "test.A"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.B"}) - g.Add(&graphNodeDestroyerTest{AddrString: "test.C"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.B"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.C"}) tf := &DestroyEdgeTransformer{ - Config: testModule(t, "transform-destroy-edge-multi"), + Config: testModule(t, "transform-destroy-edge-multi"), + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -59,15 +62,16 @@ func TestDestroyEdgeTransformer_multi(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformDestroyEdgeMultiStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestDestroyEdgeTransformer_selfRef(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeDestroyerTest{AddrString: "test.A"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.A"}) tf := &DestroyEdgeTransformer{ - Config: testModule(t, "transform-destroy-edge-self-ref"), + Config: testModule(t, "transform-destroy-edge-self-ref"), + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -76,16 +80,17 @@ func TestDestroyEdgeTransformer_selfRef(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformDestroyEdgeSelfRefStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestDestroyEdgeTransformer_module(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.b"}) - g.Add(&graphNodeDestroyerTest{AddrString: "aws_instance.a"}) + g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.b"}) + g.Add(&graphNodeDestroyerTest{AddrString: "test_object.a"}) tf := &DestroyEdgeTransformer{ - Config: testModule(t, "transform-destroy-edge-module"), + Config: testModule(t, "transform-destroy-edge-module"), + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -94,17 +99,18 @@ func TestDestroyEdgeTransformer_module(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(testTransformDestroyEdgeModuleStr) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) { g := Graph{Path: addrs.RootModuleInstance} - g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.a"}) - g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.b"}) - g.Add(&graphNodeDestroyerTest{AddrString: "module.child.aws_instance.c"}) + g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.a"}) + g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.b"}) + g.Add(&graphNodeDestroyerTest{AddrString: "module.child.test_object.c"}) tf := &DestroyEdgeTransformer{ - Config: testModule(t, "transform-destroy-edge-module-only"), + Config: testModule(t, "transform-destroy-edge-module-only"), + Components: simpleMockComponentFactory(), } if err := tf.Transform(&g); err != nil { t.Fatalf("err: %s", err) @@ -112,15 +118,15 @@ func TestDestroyEdgeTransformer_moduleOnly(t *testing.T) { actual := strings.TrimSpace(g.String()) expected := strings.TrimSpace(` -module.child.aws_instance.a (destroy) - module.child.aws_instance.b (destroy) - module.child.aws_instance.c (destroy) -module.child.aws_instance.b (destroy) - module.child.aws_instance.c (destroy) -module.child.aws_instance.c (destroy) +module.child.test_object.a (destroy) + module.child.test_object.b (destroy) + module.child.test_object.c (destroy) +module.child.test_object.b (destroy) + module.child.test_object.c (destroy) +module.child.test_object.c (destroy) `) if actual != expected { - t.Fatalf("bad:\n\n%s", actual) + t.Fatalf("wrong result\n\ngot:\n%s\n\nwant:\n%s", actual, expected) } } @@ -129,17 +135,43 @@ type graphNodeCreatorTest struct { Refs []string } -func (n *graphNodeCreatorTest) Name() string { return n.CreateAddr().String() } -func (n *graphNodeCreatorTest) CreateAddr() *ResourceAddress { - addr, err := ParseResourceAddress(n.AddrString) - if err != nil { - panic(err) - } +var ( + _ GraphNodeCreator = (*graphNodeCreatorTest)(nil) + _ GraphNodeReferencer = (*graphNodeCreatorTest)(nil) +) +func (n *graphNodeCreatorTest) Name() string { + return n.CreateAddr().String() +} + +func (n *graphNodeCreatorTest) mustAddr() addrs.AbsResourceInstance { + addr, diags := addrs.ParseAbsResourceInstanceStr(n.AddrString) + if diags.HasErrors() { + panic(diags.Err()) + } return addr } -func (n *graphNodeCreatorTest) References() []string { return n.Refs } +func (n *graphNodeCreatorTest) Path() addrs.ModuleInstance { + return n.mustAddr().Module +} + +func (n *graphNodeCreatorTest) CreateAddr() *addrs.AbsResourceInstance { + addr := n.mustAddr() + return &addr +} + +func (n *graphNodeCreatorTest) References() []*addrs.Reference { + ret := make([]*addrs.Reference, len(n.Refs)) + for i, str := range n.Refs { + ref, diags := addrs.ParseRefStr(str) + if diags.HasErrors() { + panic(diags.Err()) + } + ret[i] = ref + } + return ret +} type graphNodeDestroyerTest struct { AddrString string @@ -147,6 +179,8 @@ type graphNodeDestroyerTest struct { Modified bool } +var _ GraphNodeDestroyer = (*graphNodeDestroyerTest)(nil) + func (n *graphNodeDestroyerTest) Name() string { result := n.DestroyAddr().String() + " (destroy)" if n.Modified { @@ -156,51 +190,57 @@ func (n *graphNodeDestroyerTest) Name() string { return result } -func (n *graphNodeDestroyerTest) CreateBeforeDestroy() bool { return n.CBD } +func (n *graphNodeDestroyerTest) mustAddr() addrs.AbsResourceInstance { + addr, diags := addrs.ParseAbsResourceInstanceStr(n.AddrString) + if diags.HasErrors() { + panic(diags.Err()) + } + return addr +} + +func (n *graphNodeDestroyerTest) CreateBeforeDestroy() bool { + return n.CBD +} func (n *graphNodeDestroyerTest) ModifyCreateBeforeDestroy(v bool) error { n.Modified = true return nil } -func (n *graphNodeDestroyerTest) DestroyAddr() *ResourceAddress { - addr, err := ParseResourceAddress(n.AddrString) - if err != nil { - panic(err) - } - - return addr +func (n *graphNodeDestroyerTest) DestroyAddr() *addrs.AbsResourceInstance { + addr := n.mustAddr() + return &addr } const testTransformDestroyEdgeBasicStr = ` -test.A (destroy) - test.B (destroy) -test.B (destroy) +test_object.A (destroy) + test_object.B (destroy) +test_object.B (destroy) ` const testTransformDestroyEdgeCreatorStr = ` -test.A - test.A (destroy) -test.A (destroy) - test.B (destroy) -test.B (destroy) +test_object.A + test_object.A (destroy) +test_object.A (destroy) + test_object.B (destroy) +test_object.B (destroy) ` const testTransformDestroyEdgeMultiStr = ` -test.A (destroy) - test.B (destroy) - test.C (destroy) -test.B (destroy) - test.C (destroy) -test.C (destroy) +test_object.A (destroy) + test_object.B (destroy) + test_object.C (destroy) +test_object.B (destroy) + test_object.C (destroy) +test_object.C (destroy) ` const testTransformDestroyEdgeSelfRefStr = ` -test.A (destroy) +test_object.A (destroy) ` const testTransformDestroyEdgeModuleStr = ` -aws_instance.a (destroy) -module.child.aws_instance.b (destroy) - aws_instance.a (destroy) +module.child.test_object.b (destroy) + test_object.a (destroy) +test_object.a (destroy) `