github.com/arvindram03/terraform@v0.3.7-0.20150212015210-408f838db36d/terraform/graph_test.go (about) 1 package terraform 2 3 import ( 4 "reflect" 5 "sort" 6 "strings" 7 "testing" 8 ) 9 10 func TestGraph_basic(t *testing.T) { 11 m := testModule(t, "graph-basic") 12 13 g, err := Graph(&GraphOpts{Module: m}) 14 if err != nil { 15 t.Fatalf("err: %s", err) 16 } 17 18 actual := strings.TrimSpace(g.String()) 19 expected := strings.TrimSpace(testTerraformGraphStr) 20 if actual != expected { 21 t.Fatalf("bad:\n\n%s", actual) 22 } 23 } 24 25 func TestGraph_configRequired(t *testing.T) { 26 if _, err := Graph(new(GraphOpts)); err == nil { 27 t.Fatal("should error") 28 } 29 } 30 31 func TestGraph_count(t *testing.T) { 32 m := testModule(t, "graph-count") 33 34 g, err := Graph(&GraphOpts{Module: m}) 35 if err != nil { 36 t.Fatalf("err: %s", err) 37 } 38 39 actual := strings.TrimSpace(g.String()) 40 expected := strings.TrimSpace(testTerraformGraphCountStr) 41 if actual != expected { 42 t.Fatalf("bad:\n\n%s", actual) 43 } 44 } 45 46 func TestGraph_countTainted(t *testing.T) { 47 m := testModule(t, "graph-count") 48 state := &State{ 49 Modules: []*ModuleState{ 50 &ModuleState{ 51 Path: []string{"root"}, 52 Resources: map[string]*ResourceState{ 53 "aws_instance.web.0": &ResourceState{ 54 Type: "aws_instance", 55 Tainted: []*InstanceState{ 56 &InstanceState{ 57 ID: "foo", 58 }, 59 }, 60 }, 61 }, 62 }, 63 }, 64 } 65 66 g, err := Graph(&GraphOpts{Module: m, State: state}) 67 if err != nil { 68 t.Fatalf("err: %s", err) 69 } 70 71 actual := strings.TrimSpace(g.String()) 72 expected := strings.TrimSpace(testTerraformGraphCountTaintedStr) 73 if actual != expected { 74 t.Fatalf("bad:\n\n%s", actual) 75 } 76 } 77 78 func TestGraph_varResource(t *testing.T) { 79 m := testModule(t, "graph-count-var-resource") 80 81 g, err := Graph(&GraphOpts{Module: m}) 82 if err != nil { 83 t.Fatalf("err: %s", err) 84 } 85 86 actual := strings.TrimSpace(g.String()) 87 expected := strings.TrimSpace(testTerraformGraphCountVarResourceStr) 88 if actual != expected { 89 t.Fatalf("bad:\n\n%s", actual) 90 } 91 } 92 93 func TestGraph_cycle(t *testing.T) { 94 m := testModule(t, "graph-cycle") 95 96 _, err := Graph(&GraphOpts{Module: m}) 97 if err == nil { 98 t.Fatal("should error") 99 } 100 } 101 102 func TestGraph_dependsOn(t *testing.T) { 103 m := testModule(t, "graph-depends-on") 104 105 g, err := Graph(&GraphOpts{Module: m}) 106 if err != nil { 107 t.Fatalf("err: %s", err) 108 } 109 110 actual := strings.TrimSpace(g.String()) 111 expected := strings.TrimSpace(testTerraformGraphDependsStr) 112 if actual != expected { 113 t.Fatalf("bad:\n\n%s", actual) 114 } 115 } 116 117 func TestGraph_dependsOnCount(t *testing.T) { 118 m := testModule(t, "graph-depends-on-count") 119 120 g, err := Graph(&GraphOpts{Module: m}) 121 if err != nil { 122 t.Fatalf("err: %s", err) 123 } 124 125 actual := strings.TrimSpace(g.String()) 126 expected := strings.TrimSpace(testTerraformGraphDependsCountStr) 127 if actual != expected { 128 t.Fatalf("bad:\n\n%s", actual) 129 } 130 } 131 132 func TestGraph_dependsOnWithOrphan(t *testing.T) { 133 m := testModule(t, "graph-depends-on") 134 135 state := &State{ 136 Modules: []*ModuleState{ 137 &ModuleState{ 138 Path: []string{"root"}, 139 Resources: map[string]*ResourceState{ 140 "aws_instance.old": &ResourceState{ 141 Type: "aws_instance", 142 Primary: &InstanceState{ 143 ID: "foo", 144 }, 145 }, 146 }, 147 }, 148 }, 149 } 150 151 g, err := Graph(&GraphOpts{Module: m, State: state}) 152 if err != nil { 153 t.Fatalf("err: %s", err) 154 } 155 156 actual := strings.TrimSpace(g.String()) 157 expected := strings.TrimSpace(testTerraformGraphDependsOrphanStr) 158 if actual != expected { 159 t.Fatalf("bad:\n\n%s", actual) 160 } 161 } 162 163 func TestGraph_modules(t *testing.T) { 164 m := testModule(t, "graph-modules") 165 166 g, err := Graph(&GraphOpts{Module: m}) 167 if err != nil { 168 t.Fatalf("err: %s", err) 169 } 170 171 actual := strings.TrimSpace(g.String()) 172 expected := strings.TrimSpace(testTerraformGraphModulesStr) 173 if actual != expected { 174 t.Fatalf("bad:\n\n%s", actual) 175 } 176 177 n := g.Noun("module.consul") 178 if n == nil { 179 t.Fatal("can't find noun") 180 } 181 mn := n.Meta.(*GraphNodeModule) 182 183 if !reflect.DeepEqual(mn.Path, []string{"root", "consul"}) { 184 t.Fatalf("bad: %#v", mn.Path) 185 } 186 187 actual = strings.TrimSpace(mn.Graph.String()) 188 expected = strings.TrimSpace(testTerraformGraphModulesConsulStr) 189 if actual != expected { 190 t.Fatalf("bad:\n\n%s", actual) 191 } 192 } 193 194 func TestGraph_moduleOrphan(t *testing.T) { 195 m := testModule(t, "graph-module-orphan") 196 state := &State{ 197 Modules: []*ModuleState{ 198 &ModuleState{ 199 Path: []string{"root", "consul"}, 200 201 Resources: map[string]*ResourceState{ 202 "aws_instance.old": &ResourceState{ 203 Type: "aws_instance", 204 Primary: &InstanceState{ 205 ID: "foo", 206 }, 207 }, 208 }, 209 }, 210 }, 211 } 212 213 g, err := Graph(&GraphOpts{Module: m, State: state}) 214 if err != nil { 215 t.Fatalf("err: %s", err) 216 } 217 218 actual := strings.TrimSpace(g.String()) 219 expected := strings.TrimSpace(testTerraformGraphModuleOrphanStr) 220 if actual != expected { 221 t.Fatalf("bad:\n\n%s", actual) 222 } 223 224 n := g.Noun("module.consul") 225 if n == nil { 226 t.Fatal("can't find noun") 227 } 228 mn := n.Meta.(*GraphNodeModule) 229 230 if !reflect.DeepEqual(mn.Path, []string{"root", "consul"}) { 231 t.Fatalf("bad: %#v", mn.Path) 232 } 233 234 actual = strings.TrimSpace(mn.Graph.String()) 235 expected = strings.TrimSpace(testTerraformGraphModuleOrphanConsulStr) 236 if actual != expected { 237 t.Fatalf("bad:\n\n%s", actual) 238 } 239 } 240 241 func TestGraph_providerPrune(t *testing.T) { 242 m := testModule(t, "graph-provider-prune") 243 244 g, err := Graph(&GraphOpts{Module: m}) 245 if err != nil { 246 t.Fatalf("err: %s", err) 247 } 248 249 actual := strings.TrimSpace(g.String()) 250 expected := strings.TrimSpace(testTerraformGraphProviderPruneStr) 251 if actual != expected { 252 t.Fatalf("bad:\n\n%s", actual) 253 } 254 } 255 256 func TestGraph_state(t *testing.T) { 257 m := testModule(t, "graph-basic") 258 state := &State{ 259 Modules: []*ModuleState{ 260 &ModuleState{ 261 Path: rootModulePath, 262 263 Resources: map[string]*ResourceState{ 264 "aws_instance.old": &ResourceState{ 265 Type: "aws_instance", 266 Primary: &InstanceState{ 267 ID: "foo", 268 }, 269 }, 270 }, 271 }, 272 }, 273 } 274 275 g, err := Graph(&GraphOpts{Module: m, State: state}) 276 if err != nil { 277 t.Fatalf("err: %s", err) 278 } 279 280 actual := strings.TrimSpace(g.String()) 281 expected := strings.TrimSpace(testTerraformGraphStateStr) 282 if actual != expected { 283 t.Fatalf("bad:\n\n%s", actual) 284 } 285 } 286 287 func TestGraph_tainted(t *testing.T) { 288 m := testModule(t, "graph-tainted") 289 state := &State{ 290 Modules: []*ModuleState{ 291 &ModuleState{ 292 Path: rootModulePath, 293 294 Resources: map[string]*ResourceState{ 295 "aws_instance.web": &ResourceState{ 296 Type: "aws_instance", 297 Primary: &InstanceState{ 298 ID: "foo", 299 }, 300 Tainted: []*InstanceState{ 301 &InstanceState{ 302 ID: "bar", 303 }, 304 }, 305 }, 306 }, 307 }, 308 }, 309 } 310 311 g, err := Graph(&GraphOpts{Module: m, State: state}) 312 if err != nil { 313 t.Fatalf("err: %s", err) 314 } 315 316 actual := strings.TrimSpace(g.String()) 317 expected := strings.TrimSpace(testTerraformGraphTaintedStr) 318 if actual != expected { 319 t.Fatalf("bad:\n\n%s", actual) 320 } 321 } 322 323 func TestGraph_taintedMulti(t *testing.T) { 324 m := testModule(t, "graph-tainted") 325 state := &State{ 326 Modules: []*ModuleState{ 327 &ModuleState{ 328 Path: rootModulePath, 329 330 Resources: map[string]*ResourceState{ 331 "aws_instance.web": &ResourceState{ 332 Type: "aws_instance", 333 Primary: &InstanceState{ 334 ID: "foo", 335 }, 336 Tainted: []*InstanceState{ 337 &InstanceState{ 338 ID: "bar", 339 }, 340 &InstanceState{ 341 ID: "baz", 342 }, 343 }, 344 }, 345 }, 346 }, 347 }, 348 } 349 350 g, err := Graph(&GraphOpts{Module: m, State: state}) 351 if err != nil { 352 t.Fatalf("err: %s", err) 353 } 354 355 actual := strings.TrimSpace(g.String()) 356 expected := strings.TrimSpace(testTerraformGraphTaintedMultiStr) 357 if actual != expected { 358 t.Fatalf("bad:\n\n%s", actual) 359 } 360 } 361 362 func TestGraphFull(t *testing.T) { 363 rpAws := new(MockResourceProvider) 364 rpOS := new(MockResourceProvider) 365 366 rpAws.ResourcesReturn = []ResourceType{ 367 ResourceType{Name: "aws_instance"}, 368 ResourceType{Name: "aws_load_balancer"}, 369 ResourceType{Name: "aws_security_group"}, 370 } 371 rpOS.ResourcesReturn = []ResourceType{ 372 ResourceType{Name: "openstack_floating_ip"}, 373 } 374 375 ps := map[string]ResourceProviderFactory{ 376 "aws": testProviderFuncFixed(rpAws), 377 "open": testProviderFuncFixed(rpOS), 378 } 379 380 m := testModule(t, "graph-basic") 381 g, err := Graph(&GraphOpts{Module: m, Providers: ps}) 382 if err != nil { 383 t.Fatalf("err: %s", err) 384 } 385 386 // A helper to help get us the provider for a resource. 387 graphProvider := func(n string) ResourceProvider { 388 return g.Noun(n).Meta.(*GraphNodeResource).Resource.Provider 389 } 390 391 // Test a couple 392 if graphProvider("aws_instance.web") != rpAws { 393 t.Fatalf("bad: %#v", graphProvider("aws_instance.web")) 394 } 395 if graphProvider("openstack_floating_ip.random") != rpOS { 396 t.Fatalf("bad: %#v", graphProvider("openstack_floating_ip.random")) 397 } 398 399 // Test that all providers have been set 400 for _, n := range g.Nouns { 401 switch m := n.Meta.(type) { 402 case *GraphNodeResource: 403 if m.Resource.Provider == nil { 404 t.Fatalf("bad: %#v", m) 405 } 406 case *GraphNodeResourceProvider: 407 if len(m.Provider.Providers) == 0 { 408 t.Fatalf("bad: %#v", m) 409 } 410 default: 411 continue 412 } 413 } 414 } 415 416 func TestGraphProvisioners(t *testing.T) { 417 rpAws := new(MockResourceProvider) 418 provShell := new(MockResourceProvisioner) 419 provWinRM := new(MockResourceProvisioner) 420 421 rpAws.ResourcesReturn = []ResourceType{ 422 ResourceType{Name: "aws_instance"}, 423 ResourceType{Name: "aws_load_balancer"}, 424 ResourceType{Name: "aws_security_group"}, 425 } 426 427 ps := map[string]ResourceProvisionerFactory{ 428 "shell": testProvisionerFuncFixed(provShell), 429 "winrm": testProvisionerFuncFixed(provWinRM), 430 } 431 432 pf := map[string]ResourceProviderFactory{ 433 "aws": testProviderFuncFixed(rpAws), 434 } 435 436 m := testModule(t, "graph-provisioners") 437 g, err := Graph(&GraphOpts{Module: m, Providers: pf, Provisioners: ps}) 438 if err != nil { 439 t.Fatalf("err: %s", err) 440 } 441 442 // A helper to help get us the provider for a resource. 443 graphProvisioner := func(n string, idx int) *ResourceProvisionerConfig { 444 return g.Noun(n).Meta.(*GraphNodeResource).Resource.Provisioners[idx] 445 } 446 447 // A helper to verify depedencies 448 depends := func(a, b string) bool { 449 aNoun := g.Noun(a) 450 bNoun := g.Noun(b) 451 for _, dep := range aNoun.Deps { 452 if dep.Source == aNoun && dep.Target == bNoun { 453 return true 454 } 455 } 456 return false 457 } 458 459 // Test a couple 460 prov := graphProvisioner("aws_instance.web", 0) 461 if prov.Provisioner != provWinRM { 462 t.Fatalf("bad: %#v", prov) 463 } 464 if prov.RawConfig.Config()["cmd"] != "echo foo" { 465 t.Fatalf("bad: %#v", prov) 466 } 467 468 prov = graphProvisioner("aws_instance.web", 1) 469 if prov.Provisioner != provWinRM { 470 t.Fatalf("bad: %#v", prov) 471 } 472 if prov.RawConfig.Config()["cmd"] != "echo bar" { 473 t.Fatalf("bad: %#v", prov) 474 } 475 476 prov = graphProvisioner("aws_load_balancer.weblb", 0) 477 if prov.Provisioner != provShell { 478 t.Fatalf("bad: %#v", prov) 479 } 480 if prov.RawConfig.Config()["cmd"] != "add ${aws_instance.web.id}" { 481 t.Fatalf("bad: %#v", prov) 482 } 483 if prov.ConnInfo == nil || len(prov.ConnInfo.Raw) != 2 { 484 t.Fatalf("bad: %#v", prov) 485 } 486 487 // Check that the variable dependency is handled 488 if !depends("aws_load_balancer.weblb", "aws_instance.web") { 489 t.Fatalf("missing dependency from provisioner variable") 490 } 491 492 // Check that the connection variable dependency is handled 493 if !depends("aws_load_balancer.weblb", "aws_security_group.firewall") { 494 t.Fatalf("missing dependency from provisioner connection") 495 } 496 } 497 498 func TestGraphAddDiff(t *testing.T) { 499 m := testModule(t, "graph-diff") 500 diff := &Diff{ 501 Modules: []*ModuleDiff{ 502 &ModuleDiff{ 503 Path: rootModulePath, 504 Resources: map[string]*InstanceDiff{ 505 "aws_instance.foo": &InstanceDiff{ 506 Attributes: map[string]*ResourceAttrDiff{ 507 "foo": &ResourceAttrDiff{ 508 New: "bar", 509 }, 510 }, 511 }, 512 }, 513 }, 514 }, 515 } 516 517 g, err := Graph(&GraphOpts{Module: m, Diff: diff}) 518 if err != nil { 519 t.Fatalf("err: %s", err) 520 } 521 522 actual := strings.TrimSpace(g.String()) 523 expected := strings.TrimSpace(testTerraformGraphDiffStr) 524 if actual != expected { 525 t.Fatalf("bad:\n\n%s", actual) 526 } 527 528 /* 529 TODO: test this somewhere 530 // Verify that the state has been added 531 n := g.Noun("aws_instance.foo") 532 rn := n.Meta.(*GraphNodeResource) 533 534 expected2 := diff.RootModule().Resources["aws_instance.foo"] 535 actual2 := rn.Resource.Diff 536 if !reflect.DeepEqual(actual2, expected2) { 537 t.Fatalf("bad: %#v", actual2) 538 } 539 */ 540 } 541 542 func TestGraphAddDiff_destroy(t *testing.T) { 543 m := testModule(t, "graph-diff-destroy") 544 diff := &Diff{ 545 Modules: []*ModuleDiff{ 546 &ModuleDiff{ 547 Path: rootModulePath, 548 Resources: map[string]*InstanceDiff{ 549 "aws_instance.foo": &InstanceDiff{ 550 Destroy: true, 551 }, 552 "aws_instance.bar": &InstanceDiff{ 553 Destroy: true, 554 }, 555 }, 556 }, 557 }, 558 } 559 state := &State{ 560 Modules: []*ModuleState{ 561 &ModuleState{ 562 Path: rootModulePath, 563 Resources: map[string]*ResourceState{ 564 "aws_instance.foo": &ResourceState{ 565 Type: "aws_instance", 566 Primary: &InstanceState{ 567 ID: "foo", 568 }, 569 }, 570 571 "aws_instance.bar": &ResourceState{ 572 Type: "aws_instance", 573 Dependencies: []string{"foo"}, 574 Primary: &InstanceState{ 575 ID: "bar", 576 }, 577 }, 578 }, 579 }, 580 }, 581 } 582 583 diffHash := checksumStruct(t, diff) 584 585 g, err := Graph(&GraphOpts{ 586 Module: m, 587 Diff: diff, 588 State: state, 589 }) 590 if err != nil { 591 t.Fatalf("err: %s", err) 592 } 593 594 actual := strings.TrimSpace(g.String()) 595 expected := strings.TrimSpace(testTerraformGraphDiffDestroyStr) 596 if actual != expected { 597 t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected) 598 } 599 600 // Verify that the state has been added 601 n := g.Noun("aws_instance.foo (destroy)") 602 rn := n.Meta.(*GraphNodeResource) 603 604 expected2 := &InstanceDiff{Destroy: true} 605 actual2 := rn.Resource.Diff 606 if !reflect.DeepEqual(actual2, expected2) { 607 t.Fatalf("bad: %#v", actual2) 608 } 609 610 // Verify that our original structure has not been modified 611 diffHash2 := checksumStruct(t, diff) 612 if diffHash != diffHash2 { 613 t.Fatal("diff has been modified") 614 } 615 } 616 617 func TestGraphAddDiff_destroy_counts(t *testing.T) { 618 m := testModule(t, "graph-count") 619 diff := &Diff{ 620 Modules: []*ModuleDiff{ 621 &ModuleDiff{ 622 Path: rootModulePath, 623 Resources: map[string]*InstanceDiff{ 624 "aws_instance.web.0": &InstanceDiff{ 625 Destroy: true, 626 }, 627 "aws_instance.web.1": &InstanceDiff{ 628 Destroy: true, 629 }, 630 "aws_instance.web.2": &InstanceDiff{ 631 Destroy: true, 632 }, 633 "aws_load_balancer.weblb": &InstanceDiff{ 634 Destroy: true, 635 }, 636 }, 637 }, 638 }, 639 } 640 state := &State{ 641 Modules: []*ModuleState{ 642 &ModuleState{ 643 Path: rootModulePath, 644 Resources: map[string]*ResourceState{ 645 "aws_instance.web.0": &ResourceState{ 646 Type: "aws_instance", 647 Primary: &InstanceState{ 648 ID: "foo", 649 }, 650 }, 651 "aws_instance.web.1": &ResourceState{ 652 Type: "aws_instance", 653 Primary: &InstanceState{ 654 ID: "foo", 655 }, 656 }, 657 "aws_instance.web.2": &ResourceState{ 658 Type: "aws_instance", 659 Primary: &InstanceState{ 660 ID: "foo", 661 }, 662 }, 663 "aws_load_balancer.weblb": &ResourceState{ 664 Type: "aws_load_balancer", 665 Dependencies: []string{"aws_instance.web.0", "aws_instance.web.1", "aws_instance.web.2"}, 666 Primary: &InstanceState{ 667 ID: "bar", 668 }, 669 }, 670 }, 671 }, 672 }, 673 } 674 675 diffHash := checksumStruct(t, diff) 676 677 g, err := Graph(&GraphOpts{ 678 Module: m, 679 Diff: diff, 680 State: state, 681 }) 682 if err != nil { 683 t.Fatalf("err: %s", err) 684 } 685 686 actual := strings.TrimSpace(g.String()) 687 expected := strings.TrimSpace(testTerraformGraphDiffDestroyCountsStr) 688 if actual != expected { 689 t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected) 690 } 691 692 // Verify that the state has been added 693 n := g.Noun("aws_instance.web (destroy)") 694 rn := n.Meta.(*GraphNodeResource) 695 696 if rn.ExpandMode != ResourceExpandDestroy { 697 t.Fatalf("bad: %#v", rn) 698 } 699 700 // Verify that our original structure has not been modified 701 diffHash2 := checksumStruct(t, diff) 702 if diffHash != diffHash2 { 703 t.Fatal("diff has been modified") 704 } 705 } 706 707 func TestGraphAddDiff_module(t *testing.T) { 708 m := testModule(t, "graph-diff-module") 709 diff := &Diff{ 710 Modules: []*ModuleDiff{ 711 &ModuleDiff{ 712 Path: rootModulePath, 713 Resources: map[string]*InstanceDiff{ 714 "aws_instance.foo": &InstanceDiff{ 715 Destroy: true, 716 }, 717 }, 718 }, 719 }, 720 } 721 722 g, err := Graph(&GraphOpts{Module: m, Diff: diff}) 723 if err != nil { 724 t.Fatalf("err: %s", err) 725 } 726 727 actual := strings.TrimSpace(g.String()) 728 expected := strings.TrimSpace(testTerraformGraphDiffModuleStr) 729 if actual != expected { 730 t.Fatalf("bad:\n\n%s", actual) 731 } 732 } 733 734 func TestGraphAddDiff_module_depends(t *testing.T) { 735 m := testModule(t, "graph-diff-module-dep") 736 diff := &Diff{ 737 Modules: []*ModuleDiff{ 738 &ModuleDiff{ 739 Path: rootModulePath, 740 Resources: map[string]*InstanceDiff{ 741 "aws_instance.foo": &InstanceDiff{ 742 Destroy: true, 743 }, 744 }, 745 }, 746 &ModuleDiff{ 747 Path: []string{"root", "child"}, 748 Destroy: true, 749 Resources: map[string]*InstanceDiff{ 750 "aws_instance.foo": &InstanceDiff{ 751 Destroy: true, 752 }, 753 }, 754 }, 755 }, 756 } 757 state := &State{ 758 Modules: []*ModuleState{ 759 &ModuleState{ 760 Path: []string{"root", "orphan"}, 761 Resources: map[string]*ResourceState{ 762 "aws_instance.dead": &ResourceState{ 763 Type: "aws_instance", 764 Primary: &InstanceState{ 765 ID: "dead", 766 }, 767 }, 768 }, 769 Dependencies: []string{ 770 "aws_instance.foo", 771 "module.child", 772 }, 773 }, 774 }, 775 } 776 777 g, err := Graph(&GraphOpts{Module: m, Diff: diff, State: state}) 778 if err != nil { 779 t.Fatalf("err: %s", err) 780 } 781 782 actual := strings.TrimSpace(g.String()) 783 expected := strings.TrimSpace(testTerraformGraphDiffModuleDependsStr) 784 if actual != expected { 785 t.Fatalf("bad:\n\n%s", actual) 786 } 787 } 788 789 func TestGraphAddDiff_moduleDependsModule(t *testing.T) { 790 m := testModule(t, "graph-diff-module-dep-module") 791 diff := &Diff{ 792 Modules: []*ModuleDiff{ 793 &ModuleDiff{ 794 Path: []string{"root"}, 795 Destroy: true, 796 }, 797 &ModuleDiff{ 798 Path: []string{"root", "foo"}, 799 Destroy: true, 800 Resources: map[string]*InstanceDiff{ 801 "aws_instance.foo": &InstanceDiff{ 802 Destroy: true, 803 }, 804 }, 805 }, 806 &ModuleDiff{ 807 Path: []string{"root", "bar"}, 808 Destroy: true, 809 Resources: map[string]*InstanceDiff{ 810 "aws_instance.foo": &InstanceDiff{ 811 Destroy: true, 812 }, 813 }, 814 }, 815 }, 816 } 817 state := &State{ 818 Modules: []*ModuleState{ 819 &ModuleState{ 820 Path: []string{"root", "foo"}, 821 Resources: map[string]*ResourceState{ 822 "aws_instance.foo": &ResourceState{ 823 Type: "aws_instance", 824 Primary: &InstanceState{ 825 ID: "foo", 826 }, 827 }, 828 }, 829 }, 830 831 &ModuleState{ 832 Path: []string{"root", "bar"}, 833 Resources: map[string]*ResourceState{ 834 "aws_instance.foo": &ResourceState{ 835 Type: "aws_instance", 836 Primary: &InstanceState{ 837 ID: "foo", 838 }, 839 }, 840 }, 841 Dependencies: []string{ 842 "module.foo", 843 }, 844 }, 845 }, 846 } 847 848 g, err := Graph(&GraphOpts{Module: m, Diff: diff, State: state}) 849 if err != nil { 850 t.Fatalf("err: %s", err) 851 } 852 853 actual := strings.TrimSpace(g.String()) 854 expected := strings.TrimSpace(testTerraformGraphDiffModuleDependsModuleStr) 855 if actual != expected { 856 t.Fatalf("bad:\n\n%s", actual) 857 } 858 } 859 860 func TestGraphAddDiff_createBeforeDestroy(t *testing.T) { 861 m := testModule(t, "graph-diff-create-before") 862 diff := &Diff{ 863 Modules: []*ModuleDiff{ 864 &ModuleDiff{ 865 Path: rootModulePath, 866 Resources: map[string]*InstanceDiff{ 867 "aws_instance.bar": &InstanceDiff{ 868 Destroy: true, 869 Attributes: map[string]*ResourceAttrDiff{ 870 "ami": &ResourceAttrDiff{ 871 Old: "abc", 872 New: "xyz", 873 RequiresNew: true, 874 }, 875 }, 876 }, 877 }, 878 }, 879 }, 880 } 881 state := &State{ 882 Modules: []*ModuleState{ 883 &ModuleState{ 884 Path: rootModulePath, 885 Resources: map[string]*ResourceState{ 886 "aws_instance.bar": &ResourceState{ 887 Type: "aws_instance", 888 Primary: &InstanceState{ 889 ID: "bar", 890 Attributes: map[string]string{ 891 "ami": "abc", 892 }, 893 }, 894 }, 895 }, 896 }, 897 }, 898 } 899 900 diffHash := checksumStruct(t, diff) 901 902 g, err := Graph(&GraphOpts{ 903 Module: m, 904 Diff: diff, 905 State: state, 906 }) 907 if err != nil { 908 t.Fatalf("err: %s", err) 909 } 910 911 actual := strings.TrimSpace(g.String()) 912 expected := strings.TrimSpace(testTerraformGraphDiffCreateBeforeDestroyStr) 913 if actual != expected { 914 t.Fatalf("bad:\n\n%s\n\nexpected:\n\n%s", actual, expected) 915 } 916 917 // Verify the flags are set 918 r := g.Noun("aws_instance.bar") 919 if r.Meta.(*GraphNodeResource).Resource.Flags&FlagReplacePrimary == 0 { 920 t.Fatalf("missing FlagReplacePrimary") 921 } 922 923 r = g.Noun("aws_instance.bar (destroy)") 924 if r.Meta.(*GraphNodeResource).Resource.Flags&FlagDeposed == 0 { 925 t.Fatalf("missing FlagDeposed") 926 } 927 928 // Verify that our original structure has not been modified 929 diffHash2 := checksumStruct(t, diff) 930 if diffHash != diffHash2 { 931 t.Fatal("diff has been modified") 932 } 933 } 934 935 func TestGraphAddDiff_moduleDestroy(t *testing.T) { 936 m := testModule(t, "graph-diff-module") 937 diff := &Diff{ 938 Modules: []*ModuleDiff{ 939 &ModuleDiff{ 940 Path: rootModulePath, 941 Resources: map[string]*InstanceDiff{ 942 "aws_instance.foo": &InstanceDiff{ 943 Destroy: true, 944 }, 945 }, 946 }, 947 &ModuleDiff{ 948 Path: []string{"root", "child"}, 949 Resources: map[string]*InstanceDiff{ 950 "aws_instance.foo": &InstanceDiff{ 951 Destroy: true, 952 }, 953 }, 954 }, 955 }, 956 } 957 958 g, err := Graph(&GraphOpts{Module: m, Diff: diff}) 959 if err != nil { 960 t.Fatalf("err: %s", err) 961 } 962 963 actual := strings.TrimSpace(g.String()) 964 expected := strings.TrimSpace(testTerraformGraphDiffModuleStr) 965 if actual != expected { 966 t.Fatalf("bad:\n\n%s", actual) 967 } 968 } 969 970 func TestGraphEncodeDependencies(t *testing.T) { 971 m := testModule(t, "graph-basic") 972 973 g, err := Graph(&GraphOpts{Module: m}) 974 if err != nil { 975 t.Fatalf("err: %s", err) 976 } 977 978 // This should encode the dependency information into the state 979 graphEncodeDependencies(g) 980 981 web := g.Noun("aws_instance.web").Meta.(*GraphNodeResource).Resource 982 if len(web.Dependencies) != 1 || web.Dependencies[0] != "aws_security_group.firewall" { 983 t.Fatalf("bad: %#v", web) 984 } 985 986 weblb := g.Noun("aws_load_balancer.weblb").Meta.(*GraphNodeResource).Resource 987 if len(weblb.Dependencies) != 1 || weblb.Dependencies[0] != "aws_instance.web" { 988 t.Fatalf("bad: %#v", weblb) 989 } 990 } 991 992 func TestGraphEncodeDependencies_count(t *testing.T) { 993 m := testModule(t, "graph-count") 994 state := &State{ 995 Modules: []*ModuleState{ 996 &ModuleState{ 997 Path: rootModulePath, 998 Resources: map[string]*ResourceState{ 999 "aws_instance.web.0": &ResourceState{ 1000 Type: "aws_instance", 1001 Primary: &InstanceState{ 1002 ID: "foo", 1003 }, 1004 }, 1005 "aws_load_balancer.weblb": &ResourceState{ 1006 Type: "aws_load_balancer", 1007 Primary: &InstanceState{ 1008 ID: "foo", 1009 }, 1010 }, 1011 }, 1012 }, 1013 }, 1014 } 1015 1016 g, err := Graph(&GraphOpts{Module: m, State: state}) 1017 if err != nil { 1018 t.Fatalf("err: %s", err) 1019 } 1020 1021 // This should encode the dependency information into the state 1022 graphEncodeDependencies(g) 1023 1024 web := g.Noun("aws_instance.web").Meta.(*GraphNodeResource).Resource 1025 if len(web.Dependencies) != 0 { 1026 t.Fatalf("bad: %#v", web) 1027 } 1028 1029 weblb := g.Noun("aws_load_balancer.weblb").Meta.(*GraphNodeResource).Resource 1030 if len(weblb.Dependencies) != 1 { 1031 t.Fatalf("bad: %#v", weblb) 1032 } 1033 } 1034 1035 func TestGraphEncodeDependencies_module(t *testing.T) { 1036 m := testModule(t, "graph-modules") 1037 1038 g, err := Graph(&GraphOpts{Module: m, State: &State{}}) 1039 if err != nil { 1040 t.Fatalf("err: %s", err) 1041 } 1042 1043 // This should encode the dependency information into the state 1044 graphEncodeDependencies(g) 1045 1046 web := g.Noun("aws_instance.web").Meta.(*GraphNodeResource).Resource 1047 sort.Strings(web.Dependencies) 1048 if len(web.Dependencies) != 2 { 1049 t.Fatalf("bad: %#v", web) 1050 } 1051 if web.Dependencies[0] != "aws_security_group.firewall" { 1052 t.Fatalf("bad: %#v", web) 1053 } 1054 if web.Dependencies[1] != "module.consul" { 1055 t.Fatalf("bad: %#v", web) 1056 } 1057 1058 mod := g.Noun("module.consul").Meta.(*GraphNodeModule) 1059 deps := mod.State.Dependencies 1060 if len(deps) != 1 { 1061 t.Fatalf("Bad: %#v", deps) 1062 } 1063 if deps[0] != "aws_security_group.firewall" { 1064 t.Fatalf("Bad: %#v", deps) 1065 } 1066 } 1067 1068 func TestGraph_orphan_dependencies(t *testing.T) { 1069 m := testModule(t, "graph-count") 1070 state := &State{ 1071 Modules: []*ModuleState{ 1072 &ModuleState{ 1073 Path: rootModulePath, 1074 1075 Resources: map[string]*ResourceState{ 1076 "aws_instance.web.0": &ResourceState{ 1077 Type: "aws_instance", 1078 Primary: &InstanceState{ 1079 ID: "foo", 1080 }, 1081 }, 1082 "aws_instance.web.1": &ResourceState{ 1083 Type: "aws_instance", 1084 Primary: &InstanceState{ 1085 ID: "foo", 1086 }, 1087 }, 1088 "aws_load_balancer.old": &ResourceState{ 1089 Type: "aws_load_balancer", 1090 Primary: &InstanceState{ 1091 ID: "foo", 1092 }, 1093 Dependencies: []string{ 1094 "aws_instance.web.0", 1095 "aws_instance.web.1", 1096 "aws_instance.web.2", 1097 }, 1098 }, 1099 }, 1100 }, 1101 }, 1102 } 1103 1104 g, err := Graph(&GraphOpts{Module: m, State: state}) 1105 if err != nil { 1106 t.Fatalf("err: %s", err) 1107 } 1108 1109 actual := strings.TrimSpace(g.String()) 1110 expected := strings.TrimSpace(testTerraformGraphCountOrphanStr) 1111 if actual != expected { 1112 t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected) 1113 } 1114 } 1115 1116 func TestGraph_orphanDependenciesModules(t *testing.T) { 1117 m := testModule(t, "graph-modules") 1118 state := &State{ 1119 Modules: []*ModuleState{ 1120 &ModuleState{ 1121 Path: rootModulePath, 1122 1123 Resources: map[string]*ResourceState{ 1124 "aws_instance.foo": &ResourceState{ 1125 Type: "aws_instance", 1126 Primary: &InstanceState{ 1127 ID: "foo", 1128 }, 1129 Dependencies: []string{ 1130 "module.consul", 1131 }, 1132 }, 1133 }, 1134 }, 1135 }, 1136 } 1137 1138 g, err := Graph(&GraphOpts{Module: m, State: state}) 1139 if err != nil { 1140 t.Fatalf("err: %s", err) 1141 } 1142 1143 actual := strings.TrimSpace(g.String()) 1144 expected := strings.TrimSpace(testTerraformGraphOrphanModuleDepsStr) 1145 if actual != expected { 1146 t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected) 1147 } 1148 } 1149 1150 func TestGraph_orphanModules_Dependencies(t *testing.T) { 1151 m := testModule(t, "graph-modules") 1152 state := &State{ 1153 Modules: []*ModuleState{ 1154 &ModuleState{ 1155 Path: rootModulePath, 1156 1157 Resources: map[string]*ResourceState{ 1158 "aws_instance.foo": &ResourceState{ 1159 Type: "aws_instance", 1160 Primary: &InstanceState{ 1161 ID: "foo", 1162 }, 1163 Dependencies: []string{ 1164 "module.consul", 1165 }, 1166 }, 1167 }, 1168 }, 1169 1170 // Add an orphan module 1171 &ModuleState{ 1172 Path: []string{"root", "orphan"}, 1173 Resources: map[string]*ResourceState{ 1174 "aws_instance.bar": &ResourceState{ 1175 Type: "aws_instance", 1176 Primary: &InstanceState{ 1177 ID: "bar", 1178 }, 1179 }, 1180 }, 1181 Dependencies: []string{ 1182 "aws_instance.foo", 1183 "aws_instance.web", 1184 }, 1185 }, 1186 }, 1187 } 1188 1189 g, err := Graph(&GraphOpts{Module: m, State: state}) 1190 if err != nil { 1191 t.Fatalf("err: %s", err) 1192 } 1193 1194 actual := strings.TrimSpace(g.String()) 1195 expected := strings.TrimSpace(testTerraformGraphOrphanedModuleDepsStr) 1196 if actual != expected { 1197 t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected) 1198 } 1199 } 1200 1201 func TestGraphNodeResourceExpand(t *testing.T) { 1202 m := testModule(t, "graph-resource-expand") 1203 1204 g, err := Graph(&GraphOpts{Module: m}) 1205 if err != nil { 1206 t.Fatalf("err: %s", err) 1207 } 1208 1209 // Get the resource we care about expanding 1210 n := g.Noun("aws_instance.web") 1211 if n == nil { 1212 t.Fatal("could not find") 1213 } 1214 rn := n.Meta.(*GraphNodeResource) 1215 1216 g, err = rn.Expand() 1217 if err != nil { 1218 t.Fatalf("err: %s", err) 1219 } 1220 1221 actual := strings.TrimSpace(g.String()) 1222 expected := strings.TrimSpace(testTerraformGraphResourceExpandStr) 1223 if actual != expected { 1224 t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected) 1225 } 1226 } 1227 1228 func TestGraphNodeResourceExpand_provDeps(t *testing.T) { 1229 m := testModule(t, "graph-resource-expand-prov-deps") 1230 provs := map[string]ResourceProvisionerFactory{ 1231 "remote-exec": func() (ResourceProvisioner, error) { 1232 return new(MockResourceProvisioner), nil 1233 }, 1234 } 1235 1236 g, err := Graph(&GraphOpts{Module: m, Provisioners: provs}) 1237 if err != nil { 1238 t.Fatalf("err: %s", err) 1239 } 1240 1241 // Get the resource we care about expanding 1242 n := g.Noun("aws_instance.web") 1243 if n == nil { 1244 t.Fatal("could not find") 1245 } 1246 rn := n.Meta.(*GraphNodeResource) 1247 1248 g, err = rn.Expand() 1249 if err != nil { 1250 t.Fatalf("err: %s", err) 1251 } 1252 1253 actual := strings.TrimSpace(g.String()) 1254 expected := strings.TrimSpace(testTerraformGraphResourceExpandProvDepsStr) 1255 if actual != expected { 1256 t.Fatalf("bad:\n\nactual:\n%s\n\nexpected:\n%s", actual, expected) 1257 } 1258 } 1259 1260 const testTerraformGraphStr = ` 1261 root: root 1262 aws_instance.web 1263 aws_instance.web -> aws_security_group.firewall 1264 aws_instance.web -> provider.aws 1265 aws_load_balancer.weblb 1266 aws_load_balancer.weblb -> aws_instance.web 1267 aws_load_balancer.weblb -> provider.aws 1268 aws_security_group.firewall 1269 aws_security_group.firewall -> provider.aws 1270 openstack_floating_ip.random 1271 provider.aws 1272 provider.aws -> openstack_floating_ip.random 1273 root 1274 root -> aws_instance.web 1275 root -> aws_load_balancer.weblb 1276 root -> aws_security_group.firewall 1277 root -> openstack_floating_ip.random 1278 ` 1279 1280 const testTerraformGraphCountStr = ` 1281 root: root 1282 aws_instance.web 1283 aws_load_balancer.weblb 1284 aws_load_balancer.weblb -> aws_instance.web 1285 root 1286 root -> aws_instance.web 1287 root -> aws_load_balancer.weblb 1288 ` 1289 1290 const testTerraformGraphCountTaintedStr = ` 1291 root: root 1292 aws_instance.web 1293 aws_instance.web -> aws_instance.web.0 (tainted #1) 1294 aws_instance.web.0 (tainted #1) 1295 aws_load_balancer.weblb 1296 aws_load_balancer.weblb -> aws_instance.web 1297 root 1298 root -> aws_instance.web 1299 root -> aws_instance.web.0 (tainted #1) 1300 root -> aws_load_balancer.weblb 1301 ` 1302 1303 const testTerraformGraphCountVarResourceStr = ` 1304 root: root 1305 aws_instance.foo 1306 aws_instance.web 1307 aws_instance.web -> aws_instance.foo 1308 aws_load_balancer.weblb 1309 aws_load_balancer.weblb -> aws_instance.web 1310 root 1311 root -> aws_instance.foo 1312 root -> aws_instance.web 1313 root -> aws_load_balancer.weblb 1314 ` 1315 1316 const testTerraformGraphDependsStr = ` 1317 root: root 1318 aws_instance.db 1319 aws_instance.db -> aws_instance.web 1320 aws_instance.web 1321 root 1322 root -> aws_instance.db 1323 root -> aws_instance.web 1324 ` 1325 1326 const testTerraformGraphDependsCountStr = ` 1327 root: root 1328 aws_instance.db 1329 aws_instance.db -> aws_instance.web 1330 aws_instance.web 1331 root 1332 root -> aws_instance.db 1333 root -> aws_instance.web 1334 ` 1335 1336 const testTerraformGraphDependsOrphanStr = ` 1337 root: root 1338 aws_instance.db 1339 aws_instance.db -> aws_instance.web 1340 aws_instance.old 1341 aws_instance.web 1342 root 1343 root -> aws_instance.db 1344 root -> aws_instance.old 1345 root -> aws_instance.web 1346 ` 1347 1348 const testTerraformGraphDiffStr = ` 1349 root: root 1350 aws_instance.foo 1351 root 1352 root -> aws_instance.foo 1353 ` 1354 1355 const testTerraformGraphDiffDestroyStr = ` 1356 root: root 1357 aws_instance.bar 1358 aws_instance.bar -> aws_instance.bar (destroy) 1359 aws_instance.bar -> aws_instance.foo 1360 aws_instance.bar -> provider.aws 1361 aws_instance.bar (destroy) 1362 aws_instance.bar (destroy) -> provider.aws 1363 aws_instance.foo 1364 aws_instance.foo -> aws_instance.foo (destroy) 1365 aws_instance.foo -> provider.aws 1366 aws_instance.foo (destroy) 1367 aws_instance.foo (destroy) -> aws_instance.bar (destroy) 1368 aws_instance.foo (destroy) -> provider.aws 1369 provider.aws 1370 root 1371 root -> aws_instance.bar 1372 root -> aws_instance.foo 1373 ` 1374 1375 const testTerraformGraphDiffDestroyCountsStr = ` 1376 root: root 1377 aws_instance.web 1378 aws_instance.web -> aws_instance.web (destroy) 1379 aws_instance.web (destroy) 1380 aws_instance.web (destroy) -> aws_load_balancer.weblb (destroy) 1381 aws_load_balancer.weblb 1382 aws_load_balancer.weblb -> aws_instance.web 1383 aws_load_balancer.weblb -> aws_load_balancer.weblb (destroy) 1384 aws_load_balancer.weblb (destroy) 1385 root 1386 root -> aws_instance.web 1387 root -> aws_load_balancer.weblb 1388 ` 1389 1390 const testTerraformGraphDiffModuleStr = ` 1391 root: root 1392 aws_instance.foo 1393 aws_instance.foo -> aws_instance.foo (destroy) 1394 aws_instance.foo -> module.child 1395 aws_instance.foo (destroy) 1396 module.child 1397 module.child -> aws_instance.foo (destroy) 1398 root 1399 root -> aws_instance.foo 1400 root -> module.child 1401 ` 1402 1403 const testTerraformGraphDiffModuleDependsStr = ` 1404 root: root 1405 aws_instance.foo 1406 aws_instance.foo -> aws_instance.foo (destroy) 1407 aws_instance.foo (destroy) 1408 aws_instance.foo (destroy) -> module.child 1409 aws_instance.foo (destroy) -> module.orphan 1410 module.child 1411 module.child -> module.orphan 1412 module.orphan 1413 root 1414 root -> aws_instance.foo 1415 root -> module.child 1416 root -> module.orphan 1417 ` 1418 1419 const testTerraformGraphDiffModuleDependsModuleStr = ` 1420 root: root 1421 module.bar 1422 module.foo 1423 module.foo -> module.bar 1424 root 1425 root -> module.bar 1426 root -> module.foo 1427 ` 1428 1429 const testTerraformGraphModulesStr = ` 1430 root: root 1431 aws_instance.web 1432 aws_instance.web -> aws_security_group.firewall 1433 aws_instance.web -> module.consul 1434 aws_instance.web -> provider.aws 1435 aws_security_group.firewall 1436 aws_security_group.firewall -> provider.aws 1437 module.consul 1438 module.consul -> aws_security_group.firewall 1439 module.consul -> provider.aws 1440 provider.aws 1441 root 1442 root -> aws_instance.web 1443 root -> aws_security_group.firewall 1444 root -> module.consul 1445 ` 1446 1447 const testTerraformGraphModulesConsulStr = ` 1448 root: root 1449 aws_instance.server 1450 aws_instance.server -> provider.aws 1451 provider.aws 1452 root 1453 root -> aws_instance.server 1454 ` 1455 1456 const testTerraformGraphModuleOrphanStr = ` 1457 root: root 1458 aws_instance.web 1459 aws_instance.web -> aws_security_group.firewall 1460 aws_instance.web -> provider.aws 1461 aws_security_group.firewall 1462 aws_security_group.firewall -> provider.aws 1463 module.consul 1464 module.consul -> provider.aws 1465 provider.aws 1466 root 1467 root -> aws_instance.web 1468 root -> aws_security_group.firewall 1469 root -> module.consul 1470 ` 1471 1472 const testTerraformGraphModuleOrphanConsulStr = ` 1473 root: root 1474 aws_instance.old 1475 aws_instance.old -> provider.aws 1476 provider.aws 1477 root 1478 root -> aws_instance.old 1479 ` 1480 1481 const testTerraformGraphProviderPruneStr = ` 1482 root: root 1483 aws_load_balancer.weblb 1484 aws_load_balancer.weblb -> provider.aws 1485 provider.aws 1486 root 1487 root -> aws_load_balancer.weblb` 1488 1489 const testTerraformGraphDiffCreateBeforeDestroyStr = ` 1490 root: root 1491 aws_instance.bar 1492 aws_instance.bar -> provider.aws 1493 aws_instance.bar (destroy) 1494 aws_instance.bar (destroy) -> aws_instance.bar 1495 aws_instance.bar (destroy) -> provider.aws 1496 provider.aws 1497 root 1498 root -> aws_instance.bar 1499 root -> aws_instance.bar (destroy)` 1500 1501 const testTerraformGraphStateStr = ` 1502 root: root 1503 aws_instance.old 1504 aws_instance.old -> provider.aws 1505 aws_instance.web 1506 aws_instance.web -> aws_security_group.firewall 1507 aws_instance.web -> provider.aws 1508 aws_load_balancer.weblb 1509 aws_load_balancer.weblb -> aws_instance.web 1510 aws_load_balancer.weblb -> provider.aws 1511 aws_security_group.firewall 1512 aws_security_group.firewall -> provider.aws 1513 openstack_floating_ip.random 1514 provider.aws 1515 provider.aws -> openstack_floating_ip.random 1516 root 1517 root -> aws_instance.old 1518 root -> aws_instance.web 1519 root -> aws_load_balancer.weblb 1520 root -> aws_security_group.firewall 1521 root -> openstack_floating_ip.random 1522 ` 1523 1524 const testTerraformGraphTaintedStr = ` 1525 root: root 1526 aws_instance.web 1527 aws_instance.web -> aws_instance.web (tainted #1) 1528 aws_instance.web -> aws_security_group.firewall 1529 aws_instance.web -> provider.aws 1530 aws_instance.web (tainted #1) 1531 aws_instance.web (tainted #1) -> provider.aws 1532 aws_security_group.firewall 1533 aws_security_group.firewall -> provider.aws 1534 provider.aws 1535 root 1536 root -> aws_instance.web 1537 root -> aws_instance.web (tainted #1) 1538 root -> aws_security_group.firewall 1539 ` 1540 1541 const testTerraformGraphTaintedMultiStr = ` 1542 root: root 1543 aws_instance.web 1544 aws_instance.web -> aws_instance.web (tainted #1) 1545 aws_instance.web -> aws_instance.web (tainted #2) 1546 aws_instance.web -> aws_security_group.firewall 1547 aws_instance.web -> provider.aws 1548 aws_instance.web (tainted #1) 1549 aws_instance.web (tainted #1) -> provider.aws 1550 aws_instance.web (tainted #2) 1551 aws_instance.web (tainted #2) -> provider.aws 1552 aws_security_group.firewall 1553 aws_security_group.firewall -> provider.aws 1554 provider.aws 1555 root 1556 root -> aws_instance.web 1557 root -> aws_instance.web (tainted #1) 1558 root -> aws_instance.web (tainted #2) 1559 root -> aws_security_group.firewall 1560 ` 1561 1562 const testTerraformGraphCountOrphanStr = ` 1563 root: root 1564 aws_instance.web 1565 aws_load_balancer.old 1566 aws_load_balancer.old -> aws_instance.web 1567 aws_load_balancer.weblb 1568 aws_load_balancer.weblb -> aws_instance.web 1569 root 1570 root -> aws_instance.web 1571 root -> aws_load_balancer.old 1572 root -> aws_load_balancer.weblb 1573 ` 1574 1575 const testTerraformGraphOrphanModuleDepsStr = ` 1576 root: root 1577 aws_instance.foo 1578 aws_instance.foo -> module.consul 1579 aws_instance.foo -> provider.aws 1580 aws_instance.web 1581 aws_instance.web -> aws_security_group.firewall 1582 aws_instance.web -> module.consul 1583 aws_instance.web -> provider.aws 1584 aws_security_group.firewall 1585 aws_security_group.firewall -> provider.aws 1586 module.consul 1587 module.consul -> aws_security_group.firewall 1588 module.consul -> provider.aws 1589 provider.aws 1590 root 1591 root -> aws_instance.foo 1592 root -> aws_instance.web 1593 root -> aws_security_group.firewall 1594 root -> module.consul 1595 ` 1596 1597 const testTerraformGraphOrphanedModuleDepsStr = ` 1598 root: root 1599 aws_instance.foo 1600 aws_instance.foo -> module.consul 1601 aws_instance.foo -> provider.aws 1602 aws_instance.web 1603 aws_instance.web -> aws_security_group.firewall 1604 aws_instance.web -> module.consul 1605 aws_instance.web -> provider.aws 1606 aws_security_group.firewall 1607 aws_security_group.firewall -> provider.aws 1608 module.consul 1609 module.consul -> aws_security_group.firewall 1610 module.consul -> provider.aws 1611 module.orphan 1612 module.orphan -> aws_instance.foo 1613 module.orphan -> aws_instance.web 1614 module.orphan -> provider.aws 1615 provider.aws 1616 root 1617 root -> aws_instance.foo 1618 root -> aws_instance.web 1619 root -> aws_security_group.firewall 1620 root -> module.consul 1621 root -> module.orphan 1622 ` 1623 1624 const testTerraformGraphResourceExpandStr = ` 1625 root: root 1626 aws_instance.web.0 1627 aws_instance.web.1 1628 aws_instance.web.2 1629 root 1630 root -> aws_instance.web.0 1631 root -> aws_instance.web.1 1632 root -> aws_instance.web.2 1633 ` 1634 1635 const testTerraformGraphResourceExpandProvDepsStr = ` 1636 root: root 1637 aws_instance.web.0 1638 aws_instance.web.1 1639 aws_instance.web.1 -> aws_instance.web.0 1640 aws_instance.web.2 1641 aws_instance.web.2 -> aws_instance.web.0 1642 root 1643 root -> aws_instance.web.0 1644 root -> aws_instance.web.1 1645 root -> aws_instance.web.2 1646 `