github.com/r3labs/terraform@v0.8.4/terraform/context_apply_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 "sort" 8 "strings" 9 "sync" 10 "sync/atomic" 11 "testing" 12 "time" 13 14 "github.com/hashicorp/terraform/config/module" 15 ) 16 17 func TestContext2Apply_basic(t *testing.T) { 18 m := testModule(t, "apply-good") 19 p := testProvider("aws") 20 p.ApplyFn = testApplyFn 21 p.DiffFn = testDiffFn 22 ctx := testContext2(t, &ContextOpts{ 23 Module: m, 24 Providers: map[string]ResourceProviderFactory{ 25 "aws": testProviderFuncFixed(p), 26 }, 27 }) 28 29 if _, err := ctx.Plan(); err != nil { 30 t.Fatalf("err: %s", err) 31 } 32 33 state, err := ctx.Apply() 34 if err != nil { 35 t.Fatalf("err: %s", err) 36 } 37 38 mod := state.RootModule() 39 if len(mod.Resources) < 2 { 40 t.Fatalf("bad: %#v", mod.Resources) 41 } 42 43 actual := strings.TrimSpace(state.String()) 44 expected := strings.TrimSpace(testTerraformApplyStr) 45 if actual != expected { 46 t.Fatalf("bad: \n%s", actual) 47 } 48 } 49 50 func TestContext2Apply_escape(t *testing.T) { 51 m := testModule(t, "apply-escape") 52 p := testProvider("aws") 53 p.ApplyFn = testApplyFn 54 p.DiffFn = testDiffFn 55 ctx := testContext2(t, &ContextOpts{ 56 Module: m, 57 Providers: map[string]ResourceProviderFactory{ 58 "aws": testProviderFuncFixed(p), 59 }, 60 }) 61 62 if _, err := ctx.Plan(); err != nil { 63 t.Fatalf("err: %s", err) 64 } 65 66 state, err := ctx.Apply() 67 if err != nil { 68 t.Fatalf("err: %s", err) 69 } 70 71 checkStateString(t, state, ` 72 aws_instance.bar: 73 ID = foo 74 foo = "bar" 75 type = aws_instance 76 `) 77 } 78 79 func TestContext2Apply_resourceCountOneList(t *testing.T) { 80 m := testModule(t, "apply-resource-count-one-list") 81 p := testProvider("null") 82 p.ApplyFn = testApplyFn 83 p.DiffFn = testDiffFn 84 ctx := testContext2(t, &ContextOpts{ 85 Module: m, 86 Providers: map[string]ResourceProviderFactory{ 87 "null": testProviderFuncFixed(p), 88 }, 89 }) 90 91 if _, err := ctx.Plan(); err != nil { 92 t.Fatalf("err: %s", err) 93 } 94 95 state, err := ctx.Apply() 96 if err != nil { 97 t.Fatalf("err: %s", err) 98 } 99 100 actual := strings.TrimSpace(state.String()) 101 expected := strings.TrimSpace(`null_resource.foo: 102 ID = foo 103 104 Outputs: 105 106 test = [foo]`) 107 if actual != expected { 108 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 109 } 110 } 111 func TestContext2Apply_resourceCountZeroList(t *testing.T) { 112 m := testModule(t, "apply-resource-count-zero-list") 113 p := testProvider("null") 114 p.ApplyFn = testApplyFn 115 p.DiffFn = testDiffFn 116 ctx := testContext2(t, &ContextOpts{ 117 Module: m, 118 Providers: map[string]ResourceProviderFactory{ 119 "null": testProviderFuncFixed(p), 120 }, 121 }) 122 123 if _, err := ctx.Plan(); err != nil { 124 t.Fatalf("err: %s", err) 125 } 126 127 state, err := ctx.Apply() 128 if err != nil { 129 t.Fatalf("err: %s", err) 130 } 131 132 actual := strings.TrimSpace(state.String()) 133 expected := strings.TrimSpace(`<no state> 134 Outputs: 135 136 test = []`) 137 if actual != expected { 138 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 139 } 140 } 141 142 func TestContext2Apply_resourceDependsOnModule(t *testing.T) { 143 m := testModule(t, "apply-resource-depends-on-module") 144 p := testProvider("aws") 145 p.DiffFn = testDiffFn 146 147 { 148 // Wait for the dependency, sleep, and verify the graph never 149 // called a child. 150 var called int32 151 var checked bool 152 p.ApplyFn = func( 153 info *InstanceInfo, 154 is *InstanceState, 155 id *InstanceDiff) (*InstanceState, error) { 156 if info.HumanId() == "module.child.aws_instance.child" { 157 checked = true 158 159 // Sleep to allow parallel execution 160 time.Sleep(50 * time.Millisecond) 161 162 // Verify that called is 0 (dep not called) 163 if atomic.LoadInt32(&called) != 0 { 164 return nil, fmt.Errorf("aws_instance.a should not be called") 165 } 166 } 167 168 atomic.AddInt32(&called, 1) 169 return testApplyFn(info, is, id) 170 } 171 172 ctx := testContext2(t, &ContextOpts{ 173 Module: m, 174 Providers: map[string]ResourceProviderFactory{ 175 "aws": testProviderFuncFixed(p), 176 }, 177 }) 178 179 if _, err := ctx.Plan(); err != nil { 180 t.Fatalf("err: %s", err) 181 } 182 183 state, err := ctx.Apply() 184 if err != nil { 185 t.Fatalf("err: %s", err) 186 } 187 188 if !checked { 189 t.Fatal("should check") 190 } 191 192 checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr) 193 } 194 } 195 196 // Test that without a config, the Dependencies in the state are enough 197 // to maintain proper ordering. 198 func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) { 199 m := testModule(t, "apply-resource-depends-on-module-empty") 200 p := testProvider("aws") 201 p.DiffFn = testDiffFn 202 203 state := &State{ 204 Modules: []*ModuleState{ 205 &ModuleState{ 206 Path: rootModulePath, 207 Resources: map[string]*ResourceState{ 208 "aws_instance.a": &ResourceState{ 209 Type: "aws_instance", 210 Primary: &InstanceState{ 211 ID: "bar", 212 }, 213 Dependencies: []string{"module.child"}, 214 }, 215 }, 216 }, 217 &ModuleState{ 218 Path: []string{"root", "child"}, 219 Resources: map[string]*ResourceState{ 220 "aws_instance.child": &ResourceState{ 221 Type: "aws_instance", 222 Primary: &InstanceState{ 223 ID: "bar", 224 }, 225 }, 226 }, 227 }, 228 }, 229 } 230 231 { 232 // Wait for the dependency, sleep, and verify the graph never 233 // called a child. 234 var called int32 235 var checked bool 236 p.ApplyFn = func( 237 info *InstanceInfo, 238 is *InstanceState, 239 id *InstanceDiff) (*InstanceState, error) { 240 if info.HumanId() == "aws_instance.a" { 241 checked = true 242 243 // Sleep to allow parallel execution 244 time.Sleep(50 * time.Millisecond) 245 246 // Verify that called is 0 (dep not called) 247 if atomic.LoadInt32(&called) != 0 { 248 return nil, fmt.Errorf("module child should not be called") 249 } 250 } 251 252 atomic.AddInt32(&called, 1) 253 return testApplyFn(info, is, id) 254 } 255 256 ctx := testContext2(t, &ContextOpts{ 257 Module: m, 258 Providers: map[string]ResourceProviderFactory{ 259 "aws": testProviderFuncFixed(p), 260 }, 261 State: state, 262 }) 263 264 if _, err := ctx.Plan(); err != nil { 265 t.Fatalf("err: %s", err) 266 } 267 268 state, err := ctx.Apply() 269 if err != nil { 270 t.Fatalf("err: %s", err) 271 } 272 273 if !checked { 274 t.Fatal("should check") 275 } 276 277 checkStateString(t, state, ` 278 <no state> 279 module.child: 280 <no state> 281 `) 282 } 283 } 284 285 func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) { 286 m := testModule(t, "apply-resource-depends-on-module") 287 p := testProvider("aws") 288 p.DiffFn = testDiffFn 289 290 var globalState *State 291 { 292 p.ApplyFn = testApplyFn 293 ctx := testContext2(t, &ContextOpts{ 294 Module: m, 295 Providers: map[string]ResourceProviderFactory{ 296 "aws": testProviderFuncFixed(p), 297 }, 298 }) 299 300 if _, err := ctx.Plan(); err != nil { 301 t.Fatalf("err: %s", err) 302 } 303 304 state, err := ctx.Apply() 305 if err != nil { 306 t.Fatalf("err: %s", err) 307 } 308 309 globalState = state 310 } 311 312 { 313 // Wait for the dependency, sleep, and verify the graph never 314 // called a child. 315 var called int32 316 var checked bool 317 p.ApplyFn = func( 318 info *InstanceInfo, 319 is *InstanceState, 320 id *InstanceDiff) (*InstanceState, error) { 321 if info.HumanId() == "aws_instance.a" { 322 checked = true 323 324 // Sleep to allow parallel execution 325 time.Sleep(50 * time.Millisecond) 326 327 // Verify that called is 0 (dep not called) 328 if atomic.LoadInt32(&called) != 0 { 329 return nil, fmt.Errorf("module child should not be called") 330 } 331 } 332 333 atomic.AddInt32(&called, 1) 334 return testApplyFn(info, is, id) 335 } 336 337 ctx := testContext2(t, &ContextOpts{ 338 Module: m, 339 Providers: map[string]ResourceProviderFactory{ 340 "aws": testProviderFuncFixed(p), 341 }, 342 State: globalState, 343 Destroy: true, 344 }) 345 346 if _, err := ctx.Plan(); err != nil { 347 t.Fatalf("err: %s", err) 348 } 349 350 state, err := ctx.Apply() 351 if err != nil { 352 t.Fatalf("err: %s", err) 353 } 354 355 if !checked { 356 t.Fatal("should check") 357 } 358 359 checkStateString(t, state, ` 360 <no state> 361 module.child: 362 <no state> 363 `) 364 } 365 } 366 367 func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) { 368 m := testModule(t, "apply-resource-depends-on-module-deep") 369 p := testProvider("aws") 370 p.DiffFn = testDiffFn 371 372 { 373 // Wait for the dependency, sleep, and verify the graph never 374 // called a child. 375 var called int32 376 var checked bool 377 p.ApplyFn = func( 378 info *InstanceInfo, 379 is *InstanceState, 380 id *InstanceDiff) (*InstanceState, error) { 381 if info.HumanId() == "module.child.grandchild.aws_instance.c" { 382 checked = true 383 384 // Sleep to allow parallel execution 385 time.Sleep(50 * time.Millisecond) 386 387 // Verify that called is 0 (dep not called) 388 if atomic.LoadInt32(&called) != 0 { 389 return nil, fmt.Errorf("aws_instance.a should not be called") 390 } 391 } 392 393 atomic.AddInt32(&called, 1) 394 return testApplyFn(info, is, id) 395 } 396 397 ctx := testContext2(t, &ContextOpts{ 398 Module: m, 399 Providers: map[string]ResourceProviderFactory{ 400 "aws": testProviderFuncFixed(p), 401 }, 402 }) 403 404 if _, err := ctx.Plan(); err != nil { 405 t.Fatalf("err: %s", err) 406 } 407 408 state, err := ctx.Apply() 409 if err != nil { 410 t.Fatalf("err: %s", err) 411 } 412 413 if !checked { 414 t.Fatal("should check") 415 } 416 417 checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr) 418 } 419 } 420 421 func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) { 422 m := testModule(t, "apply-resource-depends-on-module-in-module") 423 p := testProvider("aws") 424 p.DiffFn = testDiffFn 425 426 { 427 // Wait for the dependency, sleep, and verify the graph never 428 // called a child. 429 var called int32 430 var checked bool 431 p.ApplyFn = func( 432 info *InstanceInfo, 433 is *InstanceState, 434 id *InstanceDiff) (*InstanceState, error) { 435 if info.HumanId() == "module.child.grandchild.aws_instance.c" { 436 checked = true 437 438 // Sleep to allow parallel execution 439 time.Sleep(50 * time.Millisecond) 440 441 // Verify that called is 0 (dep not called) 442 if atomic.LoadInt32(&called) != 0 { 443 return nil, fmt.Errorf("nothing else should not be called") 444 } 445 } 446 447 atomic.AddInt32(&called, 1) 448 return testApplyFn(info, is, id) 449 } 450 451 ctx := testContext2(t, &ContextOpts{ 452 Module: m, 453 Providers: map[string]ResourceProviderFactory{ 454 "aws": testProviderFuncFixed(p), 455 }, 456 }) 457 458 if _, err := ctx.Plan(); err != nil { 459 t.Fatalf("err: %s", err) 460 } 461 462 state, err := ctx.Apply() 463 if err != nil { 464 t.Fatalf("err: %s", err) 465 } 466 467 if !checked { 468 t.Fatal("should check") 469 } 470 471 checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr) 472 } 473 } 474 475 func TestContext2Apply_mapVarBetweenModules(t *testing.T) { 476 m := testModule(t, "apply-map-var-through-module") 477 p := testProvider("null") 478 p.ApplyFn = testApplyFn 479 p.DiffFn = testDiffFn 480 ctx := testContext2(t, &ContextOpts{ 481 Module: m, 482 Providers: map[string]ResourceProviderFactory{ 483 "null": testProviderFuncFixed(p), 484 }, 485 }) 486 487 if _, err := ctx.Plan(); err != nil { 488 t.Fatalf("err: %s", err) 489 } 490 491 state, err := ctx.Apply() 492 if err != nil { 493 t.Fatalf("err: %s", err) 494 } 495 496 actual := strings.TrimSpace(state.String()) 497 expected := strings.TrimSpace(`<no state> 498 Outputs: 499 500 amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 } 501 502 module.test: 503 null_resource.noop: 504 ID = foo 505 506 Outputs: 507 508 amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`) 509 if actual != expected { 510 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 511 } 512 } 513 514 func TestContext2Apply_refCount(t *testing.T) { 515 m := testModule(t, "apply-ref-count") 516 p := testProvider("aws") 517 p.ApplyFn = testApplyFn 518 p.DiffFn = testDiffFn 519 ctx := testContext2(t, &ContextOpts{ 520 Module: m, 521 Providers: map[string]ResourceProviderFactory{ 522 "aws": testProviderFuncFixed(p), 523 }, 524 }) 525 526 if _, err := ctx.Plan(); err != nil { 527 t.Fatalf("err: %s", err) 528 } 529 530 state, err := ctx.Apply() 531 if err != nil { 532 t.Fatalf("err: %s", err) 533 } 534 535 mod := state.RootModule() 536 if len(mod.Resources) < 2 { 537 t.Fatalf("bad: %#v", mod.Resources) 538 } 539 540 actual := strings.TrimSpace(state.String()) 541 expected := strings.TrimSpace(testTerraformApplyRefCountStr) 542 if actual != expected { 543 t.Fatalf("bad: \n%s", actual) 544 } 545 } 546 547 func TestContext2Apply_providerAlias(t *testing.T) { 548 m := testModule(t, "apply-provider-alias") 549 p := testProvider("aws") 550 p.ApplyFn = testApplyFn 551 p.DiffFn = testDiffFn 552 ctx := testContext2(t, &ContextOpts{ 553 Module: m, 554 Providers: map[string]ResourceProviderFactory{ 555 "aws": testProviderFuncFixed(p), 556 }, 557 }) 558 559 if _, err := ctx.Plan(); err != nil { 560 t.Fatalf("err: %s", err) 561 } 562 563 state, err := ctx.Apply() 564 if err != nil { 565 t.Fatalf("err: %s", err) 566 } 567 568 mod := state.RootModule() 569 if len(mod.Resources) < 2 { 570 t.Fatalf("bad: %#v", mod.Resources) 571 } 572 573 actual := strings.TrimSpace(state.String()) 574 expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) 575 if actual != expected { 576 t.Fatalf("bad: \n%s", actual) 577 } 578 } 579 580 // Two providers that are configured should both be configured prior to apply 581 func TestContext2Apply_providerAliasConfigure(t *testing.T) { 582 m := testModule(t, "apply-provider-alias-configure") 583 584 p2 := testProvider("another") 585 p2.ApplyFn = testApplyFn 586 p2.DiffFn = testDiffFn 587 588 ctx := testContext2(t, &ContextOpts{ 589 Module: m, 590 Providers: map[string]ResourceProviderFactory{ 591 "another": testProviderFuncFixed(p2), 592 }, 593 }) 594 595 if p, err := ctx.Plan(); err != nil { 596 t.Fatalf("err: %s", err) 597 } else { 598 t.Logf(p.String()) 599 } 600 601 // Configure to record calls AFTER Plan above 602 var configCount int32 603 p2.ConfigureFn = func(c *ResourceConfig) error { 604 atomic.AddInt32(&configCount, 1) 605 606 foo, ok := c.Get("foo") 607 if !ok { 608 return fmt.Errorf("foo is not found") 609 } 610 611 if foo != "bar" { 612 return fmt.Errorf("foo: %#v", foo) 613 } 614 615 return nil 616 } 617 618 state, err := ctx.Apply() 619 if err != nil { 620 t.Fatalf("err: %s", err) 621 } 622 623 if configCount != 2 { 624 t.Fatalf("provider config expected 2 calls, got: %d", configCount) 625 } 626 627 actual := strings.TrimSpace(state.String()) 628 expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr) 629 if actual != expected { 630 t.Fatalf("bad: \n%s", actual) 631 } 632 } 633 634 // GH-2870 635 func TestContext2Apply_providerWarning(t *testing.T) { 636 m := testModule(t, "apply-provider-warning") 637 p := testProvider("aws") 638 p.ApplyFn = testApplyFn 639 p.DiffFn = testDiffFn 640 p.ValidateFn = func(c *ResourceConfig) (ws []string, es []error) { 641 ws = append(ws, "Just a warning") 642 return 643 } 644 ctx := testContext2(t, &ContextOpts{ 645 Module: m, 646 Providers: map[string]ResourceProviderFactory{ 647 "aws": testProviderFuncFixed(p), 648 }, 649 }) 650 651 if _, err := ctx.Plan(); err != nil { 652 t.Fatalf("err: %s", err) 653 } 654 655 state, err := ctx.Apply() 656 if err != nil { 657 t.Fatalf("err: %s", err) 658 } 659 660 actual := strings.TrimSpace(state.String()) 661 expected := strings.TrimSpace(` 662 aws_instance.foo: 663 ID = foo 664 `) 665 if actual != expected { 666 t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected) 667 } 668 669 if !p.ConfigureCalled { 670 t.Fatalf("provider Configure() was never called!") 671 } 672 } 673 674 // Higher level test at TestResource_dataSourceListApplyPanic 675 func TestContext2Apply_computedAttrRefTypeMismatch(t *testing.T) { 676 m := testModule(t, "apply-computed-attr-ref-type-mismatch") 677 p := testProvider("aws") 678 p.DiffFn = testDiffFn 679 p.ValidateResourceFn = func(t string, c *ResourceConfig) (ws []string, es []error) { 680 // Emulate the type checking behavior of helper/schema based validation 681 if t == "aws_instance" { 682 ami, _ := c.Get("ami") 683 switch a := ami.(type) { 684 case string: 685 // ok 686 default: 687 es = append(es, fmt.Errorf("Expected ami to be string, got %T", a)) 688 } 689 } 690 return 691 } 692 p.DiffFn = func( 693 info *InstanceInfo, 694 state *InstanceState, 695 c *ResourceConfig) (*InstanceDiff, error) { 696 switch info.Type { 697 case "aws_ami_list": 698 // Emulate a diff that says "we'll create this list and ids will be populated" 699 return &InstanceDiff{ 700 Attributes: map[string]*ResourceAttrDiff{ 701 "ids.#": &ResourceAttrDiff{NewComputed: true}, 702 }, 703 }, nil 704 case "aws_instance": 705 // If we get to the diff for instance, we should be able to assume types 706 ami, _ := c.Get("ami") 707 _ = ami.(string) 708 } 709 return nil, nil 710 } 711 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 712 if info.Type != "aws_ami_list" { 713 t.Fatalf("Reached apply for unexpected resource type! %s", info.Type) 714 } 715 // Pretend like we make a thing and the computed list "ids" is populated 716 return &InstanceState{ 717 ID: "someid", 718 Attributes: map[string]string{ 719 "ids.#": "2", 720 "ids.0": "ami-abc123", 721 "ids.1": "ami-bcd345", 722 }, 723 }, nil 724 } 725 ctx := testContext2(t, &ContextOpts{ 726 Module: m, 727 Providers: map[string]ResourceProviderFactory{ 728 "aws": testProviderFuncFixed(p), 729 }, 730 }) 731 732 if _, err := ctx.Plan(); err != nil { 733 t.Fatalf("err: %s", err) 734 } 735 736 _, err := ctx.Apply() 737 if err == nil { 738 t.Fatalf("Expected err, got none!") 739 } 740 741 expected := "Expected ami to be string" 742 if !strings.Contains(err.Error(), expected) { 743 t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", err, expected) 744 } 745 } 746 747 func TestContext2Apply_emptyModule(t *testing.T) { 748 m := testModule(t, "apply-empty-module") 749 p := testProvider("aws") 750 p.ApplyFn = testApplyFn 751 p.DiffFn = testDiffFn 752 ctx := testContext2(t, &ContextOpts{ 753 Module: m, 754 Providers: map[string]ResourceProviderFactory{ 755 "aws": testProviderFuncFixed(p), 756 }, 757 }) 758 759 if _, err := ctx.Plan(); err != nil { 760 t.Fatalf("err: %s", err) 761 } 762 763 state, err := ctx.Apply() 764 if err != nil { 765 t.Fatalf("err: %s", err) 766 } 767 768 actual := strings.TrimSpace(state.String()) 769 actual = strings.Replace(actual, " ", "", -1) 770 expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr) 771 if actual != expected { 772 t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected) 773 } 774 } 775 776 func TestContext2Apply_createBeforeDestroy(t *testing.T) { 777 m := testModule(t, "apply-good-create-before") 778 p := testProvider("aws") 779 p.ApplyFn = testApplyFn 780 p.DiffFn = testDiffFn 781 state := &State{ 782 Modules: []*ModuleState{ 783 &ModuleState{ 784 Path: rootModulePath, 785 Resources: map[string]*ResourceState{ 786 "aws_instance.bar": &ResourceState{ 787 Type: "aws_instance", 788 Primary: &InstanceState{ 789 ID: "bar", 790 Attributes: map[string]string{ 791 "require_new": "abc", 792 }, 793 }, 794 }, 795 }, 796 }, 797 }, 798 } 799 ctx := testContext2(t, &ContextOpts{ 800 Module: m, 801 Providers: map[string]ResourceProviderFactory{ 802 "aws": testProviderFuncFixed(p), 803 }, 804 State: state, 805 }) 806 807 if p, err := ctx.Plan(); err != nil { 808 t.Fatalf("err: %s", err) 809 } else { 810 t.Logf(p.String()) 811 } 812 813 state, err := ctx.Apply() 814 if err != nil { 815 t.Fatalf("err: %s", err) 816 } 817 818 mod := state.RootModule() 819 if len(mod.Resources) != 1 { 820 t.Fatalf("bad: %s", state) 821 } 822 823 actual := strings.TrimSpace(state.String()) 824 expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr) 825 if actual != expected { 826 t.Fatalf("bad: \n%s", actual) 827 } 828 } 829 830 func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { 831 m := testModule(t, "apply-good-create-before-update") 832 p := testProvider("aws") 833 p.ApplyFn = testApplyFn 834 p.DiffFn = testDiffFn 835 state := &State{ 836 Modules: []*ModuleState{ 837 &ModuleState{ 838 Path: rootModulePath, 839 Resources: map[string]*ResourceState{ 840 "aws_instance.bar": &ResourceState{ 841 Type: "aws_instance", 842 Primary: &InstanceState{ 843 ID: "bar", 844 Attributes: map[string]string{ 845 "foo": "bar", 846 }, 847 }, 848 }, 849 }, 850 }, 851 }, 852 } 853 ctx := testContext2(t, &ContextOpts{ 854 Module: m, 855 Providers: map[string]ResourceProviderFactory{ 856 "aws": testProviderFuncFixed(p), 857 }, 858 State: state, 859 }) 860 861 if p, err := ctx.Plan(); err != nil { 862 t.Fatalf("err: %s", err) 863 } else { 864 t.Logf(p.String()) 865 } 866 867 state, err := ctx.Apply() 868 if err != nil { 869 t.Fatalf("err: %s", err) 870 } 871 872 mod := state.RootModule() 873 if len(mod.Resources) != 1 { 874 t.Fatalf("bad: %s", state) 875 } 876 877 actual := strings.TrimSpace(state.String()) 878 expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr) 879 if actual != expected { 880 t.Fatalf("bad: \n%s", actual) 881 } 882 } 883 884 // This tests that when a CBD resource depends on a non-CBD resource, 885 // we can still properly apply changes that require new for both. 886 func TestContext2Apply_createBeforeDestroy_dependsNonCBD(t *testing.T) { 887 m := testModule(t, "apply-cbd-depends-non-cbd") 888 p := testProvider("aws") 889 p.ApplyFn = testApplyFn 890 p.DiffFn = testDiffFn 891 state := &State{ 892 Modules: []*ModuleState{ 893 &ModuleState{ 894 Path: rootModulePath, 895 Resources: map[string]*ResourceState{ 896 "aws_instance.bar": &ResourceState{ 897 Type: "aws_instance", 898 Primary: &InstanceState{ 899 ID: "bar", 900 Attributes: map[string]string{ 901 "require_new": "abc", 902 }, 903 }, 904 }, 905 906 "aws_instance.foo": &ResourceState{ 907 Type: "aws_instance", 908 Primary: &InstanceState{ 909 ID: "foo", 910 Attributes: map[string]string{ 911 "require_new": "abc", 912 }, 913 }, 914 }, 915 }, 916 }, 917 }, 918 } 919 ctx := testContext2(t, &ContextOpts{ 920 Module: m, 921 Providers: map[string]ResourceProviderFactory{ 922 "aws": testProviderFuncFixed(p), 923 }, 924 State: state, 925 }) 926 927 if p, err := ctx.Plan(); err != nil { 928 t.Fatalf("err: %s", err) 929 } else { 930 t.Logf(p.String()) 931 } 932 933 state, err := ctx.Apply() 934 if err != nil { 935 t.Fatalf("err: %s", err) 936 } 937 938 checkStateString(t, state, ` 939 aws_instance.bar: 940 ID = foo 941 require_new = yes 942 type = aws_instance 943 value = foo 944 aws_instance.foo: 945 ID = foo 946 require_new = yes 947 type = aws_instance 948 `) 949 } 950 951 func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) { 952 h := new(MockHook) 953 m := testModule(t, "apply-good-create-before") 954 p := testProvider("aws") 955 p.ApplyFn = testApplyFn 956 p.DiffFn = testDiffFn 957 state := &State{ 958 Modules: []*ModuleState{ 959 &ModuleState{ 960 Path: rootModulePath, 961 Resources: map[string]*ResourceState{ 962 "aws_instance.bar": &ResourceState{ 963 Type: "aws_instance", 964 Primary: &InstanceState{ 965 ID: "bar", 966 Attributes: map[string]string{ 967 "require_new": "abc", 968 }, 969 }, 970 }, 971 }, 972 }, 973 }, 974 } 975 976 var actual []string 977 var actualLock sync.Mutex 978 h.PostApplyFn = func(n *InstanceInfo, s *InstanceState, e error) (HookAction, error) { 979 actualLock.Lock() 980 defer actualLock.Unlock() 981 actual = append(actual, n.Id) 982 return HookActionContinue, nil 983 } 984 985 ctx := testContext2(t, &ContextOpts{ 986 Module: m, 987 Hooks: []Hook{h}, 988 Providers: map[string]ResourceProviderFactory{ 989 "aws": testProviderFuncFixed(p), 990 }, 991 State: state, 992 }) 993 994 if p, err := ctx.Plan(); err != nil { 995 t.Fatalf("err: %s", err) 996 } else { 997 t.Logf(p.String()) 998 } 999 1000 if _, err := ctx.Apply(); err != nil { 1001 t.Fatalf("err: %s", err) 1002 } 1003 1004 expected := []string{"aws_instance.bar", "aws_instance.bar (deposed #0)"} 1005 if !reflect.DeepEqual(actual, expected) { 1006 t.Fatalf("bad: %#v", actual) 1007 } 1008 } 1009 1010 // Test that we can perform an apply with CBD in a count with deposed instances. 1011 func TestContext2Apply_createBeforeDestroy_deposedCount(t *testing.T) { 1012 m := testModule(t, "apply-cbd-count") 1013 p := testProvider("aws") 1014 p.ApplyFn = testApplyFn 1015 p.DiffFn = testDiffFn 1016 1017 state := &State{ 1018 Modules: []*ModuleState{ 1019 &ModuleState{ 1020 Path: rootModulePath, 1021 Resources: map[string]*ResourceState{ 1022 "aws_instance.bar.0": &ResourceState{ 1023 Type: "aws_instance", 1024 Primary: &InstanceState{ 1025 ID: "bar", 1026 Tainted: true, 1027 }, 1028 1029 Deposed: []*InstanceState{ 1030 &InstanceState{ 1031 ID: "foo", 1032 }, 1033 }, 1034 }, 1035 "aws_instance.bar.1": &ResourceState{ 1036 Type: "aws_instance", 1037 Primary: &InstanceState{ 1038 ID: "bar", 1039 Tainted: true, 1040 }, 1041 1042 Deposed: []*InstanceState{ 1043 &InstanceState{ 1044 ID: "bar", 1045 }, 1046 }, 1047 }, 1048 }, 1049 }, 1050 }, 1051 } 1052 1053 ctx := testContext2(t, &ContextOpts{ 1054 Module: m, 1055 Providers: map[string]ResourceProviderFactory{ 1056 "aws": testProviderFuncFixed(p), 1057 }, 1058 State: state, 1059 }) 1060 1061 if p, err := ctx.Plan(); err != nil { 1062 t.Fatalf("err: %s", err) 1063 } else { 1064 t.Logf(p.String()) 1065 } 1066 1067 state, err := ctx.Apply() 1068 if err != nil { 1069 t.Fatalf("err: %s", err) 1070 } 1071 1072 checkStateString(t, state, ` 1073 aws_instance.bar.0: 1074 ID = foo 1075 foo = bar 1076 type = aws_instance 1077 aws_instance.bar.1: 1078 ID = foo 1079 foo = bar 1080 type = aws_instance 1081 `) 1082 } 1083 1084 // Test that when we have a deposed instance but a good primary, we still 1085 // destroy the deposed instance. 1086 func TestContext2Apply_createBeforeDestroy_deposedOnly(t *testing.T) { 1087 m := testModule(t, "apply-cbd-deposed-only") 1088 p := testProvider("aws") 1089 p.ApplyFn = testApplyFn 1090 p.DiffFn = testDiffFn 1091 1092 state := &State{ 1093 Modules: []*ModuleState{ 1094 &ModuleState{ 1095 Path: rootModulePath, 1096 Resources: map[string]*ResourceState{ 1097 "aws_instance.bar": &ResourceState{ 1098 Type: "aws_instance", 1099 Primary: &InstanceState{ 1100 ID: "bar", 1101 }, 1102 1103 Deposed: []*InstanceState{ 1104 &InstanceState{ 1105 ID: "foo", 1106 }, 1107 }, 1108 }, 1109 }, 1110 }, 1111 }, 1112 } 1113 1114 ctx := testContext2(t, &ContextOpts{ 1115 Module: m, 1116 Providers: map[string]ResourceProviderFactory{ 1117 "aws": testProviderFuncFixed(p), 1118 }, 1119 State: state, 1120 }) 1121 1122 if p, err := ctx.Plan(); err != nil { 1123 t.Fatalf("err: %s", err) 1124 } else { 1125 t.Logf(p.String()) 1126 } 1127 1128 state, err := ctx.Apply() 1129 if err != nil { 1130 t.Fatalf("err: %s", err) 1131 } 1132 1133 checkStateString(t, state, ` 1134 aws_instance.bar: 1135 ID = bar 1136 `) 1137 } 1138 1139 func TestContext2Apply_destroyComputed(t *testing.T) { 1140 m := testModule(t, "apply-destroy-computed") 1141 p := testProvider("aws") 1142 p.ApplyFn = testApplyFn 1143 p.DiffFn = testDiffFn 1144 state := &State{ 1145 Modules: []*ModuleState{ 1146 &ModuleState{ 1147 Path: rootModulePath, 1148 Resources: map[string]*ResourceState{ 1149 "aws_instance.foo": &ResourceState{ 1150 Type: "aws_instance", 1151 Primary: &InstanceState{ 1152 ID: "foo", 1153 Attributes: map[string]string{ 1154 "output": "value", 1155 }, 1156 }, 1157 }, 1158 }, 1159 }, 1160 }, 1161 } 1162 ctx := testContext2(t, &ContextOpts{ 1163 Module: m, 1164 Providers: map[string]ResourceProviderFactory{ 1165 "aws": testProviderFuncFixed(p), 1166 }, 1167 State: state, 1168 Destroy: true, 1169 }) 1170 1171 if p, err := ctx.Plan(); err != nil { 1172 t.Fatalf("err: %s", err) 1173 } else { 1174 t.Logf(p.String()) 1175 } 1176 1177 if _, err := ctx.Apply(); err != nil { 1178 t.Fatalf("err: %s", err) 1179 } 1180 } 1181 1182 // Test that the destroy operation uses depends_on as a source of ordering. 1183 func TestContext2Apply_destroyDependsOn(t *testing.T) { 1184 // It is possible for this to be racy, so we loop a number of times 1185 // just to check. 1186 for i := 0; i < 10; i++ { 1187 testContext2Apply_destroyDependsOn(t) 1188 } 1189 } 1190 1191 func testContext2Apply_destroyDependsOn(t *testing.T) { 1192 m := testModule(t, "apply-destroy-depends-on") 1193 p := testProvider("aws") 1194 p.ApplyFn = testApplyFn 1195 p.DiffFn = testDiffFn 1196 state := &State{ 1197 Modules: []*ModuleState{ 1198 &ModuleState{ 1199 Path: rootModulePath, 1200 Resources: map[string]*ResourceState{ 1201 "aws_instance.foo": &ResourceState{ 1202 Type: "aws_instance", 1203 Primary: &InstanceState{ 1204 ID: "foo", 1205 Attributes: map[string]string{}, 1206 }, 1207 }, 1208 1209 "aws_instance.bar": &ResourceState{ 1210 Type: "aws_instance", 1211 Primary: &InstanceState{ 1212 ID: "bar", 1213 Attributes: map[string]string{}, 1214 }, 1215 }, 1216 }, 1217 }, 1218 }, 1219 } 1220 1221 // Record the order we see Apply 1222 var actual []string 1223 var actualLock sync.Mutex 1224 p.ApplyFn = func( 1225 info *InstanceInfo, _ *InstanceState, _ *InstanceDiff) (*InstanceState, error) { 1226 actualLock.Lock() 1227 defer actualLock.Unlock() 1228 actual = append(actual, info.Id) 1229 return nil, nil 1230 } 1231 1232 ctx := testContext2(t, &ContextOpts{ 1233 Module: m, 1234 Providers: map[string]ResourceProviderFactory{ 1235 "aws": testProviderFuncFixed(p), 1236 }, 1237 State: state, 1238 Destroy: true, 1239 Parallelism: 1, // To check ordering 1240 }) 1241 1242 if _, err := ctx.Plan(); err != nil { 1243 t.Fatalf("err: %s", err) 1244 } 1245 1246 if _, err := ctx.Apply(); err != nil { 1247 t.Fatalf("err: %s", err) 1248 } 1249 1250 expected := []string{"aws_instance.foo", "aws_instance.bar"} 1251 if !reflect.DeepEqual(actual, expected) { 1252 t.Fatalf("bad: %#v", actual) 1253 } 1254 } 1255 1256 // Test that destroy ordering is correct with dependencies only 1257 // in the state. 1258 func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) { 1259 // It is possible for this to be racy, so we loop a number of times 1260 // just to check. 1261 for i := 0; i < 10; i++ { 1262 testContext2Apply_destroyDependsOnStateOnly(t) 1263 } 1264 } 1265 1266 func testContext2Apply_destroyDependsOnStateOnly(t *testing.T) { 1267 m := testModule(t, "empty") 1268 p := testProvider("aws") 1269 p.ApplyFn = testApplyFn 1270 p.DiffFn = testDiffFn 1271 state := &State{ 1272 Modules: []*ModuleState{ 1273 &ModuleState{ 1274 Path: rootModulePath, 1275 Resources: map[string]*ResourceState{ 1276 "aws_instance.foo": &ResourceState{ 1277 Type: "aws_instance", 1278 Primary: &InstanceState{ 1279 ID: "foo", 1280 Attributes: map[string]string{}, 1281 }, 1282 }, 1283 1284 "aws_instance.bar": &ResourceState{ 1285 Type: "aws_instance", 1286 Primary: &InstanceState{ 1287 ID: "bar", 1288 Attributes: map[string]string{}, 1289 }, 1290 Dependencies: []string{"aws_instance.foo"}, 1291 }, 1292 }, 1293 }, 1294 }, 1295 } 1296 1297 // Record the order we see Apply 1298 var actual []string 1299 var actualLock sync.Mutex 1300 p.ApplyFn = func( 1301 info *InstanceInfo, _ *InstanceState, _ *InstanceDiff) (*InstanceState, error) { 1302 actualLock.Lock() 1303 defer actualLock.Unlock() 1304 actual = append(actual, info.Id) 1305 return nil, nil 1306 } 1307 1308 ctx := testContext2(t, &ContextOpts{ 1309 Module: m, 1310 Providers: map[string]ResourceProviderFactory{ 1311 "aws": testProviderFuncFixed(p), 1312 }, 1313 State: state, 1314 Destroy: true, 1315 Parallelism: 1, // To check ordering 1316 }) 1317 1318 if _, err := ctx.Plan(); err != nil { 1319 t.Fatalf("err: %s", err) 1320 } 1321 1322 if _, err := ctx.Apply(); err != nil { 1323 t.Fatalf("err: %s", err) 1324 } 1325 1326 expected := []string{"aws_instance.bar", "aws_instance.foo"} 1327 if !reflect.DeepEqual(actual, expected) { 1328 t.Fatalf("bad: %#v", actual) 1329 } 1330 } 1331 1332 func TestContext2Apply_dataBasic(t *testing.T) { 1333 m := testModule(t, "apply-data-basic") 1334 p := testProvider("null") 1335 p.ApplyFn = testApplyFn 1336 p.DiffFn = testDiffFn 1337 p.ReadDataApplyReturn = &InstanceState{ID: "yo"} 1338 1339 ctx := testContext2(t, &ContextOpts{ 1340 Module: m, 1341 Providers: map[string]ResourceProviderFactory{ 1342 "null": testProviderFuncFixed(p), 1343 }, 1344 }) 1345 1346 if p, err := ctx.Plan(); err != nil { 1347 t.Fatalf("err: %s", err) 1348 } else { 1349 t.Logf(p.String()) 1350 } 1351 1352 state, err := ctx.Apply() 1353 if err != nil { 1354 t.Fatalf("err: %s", err) 1355 } 1356 1357 actual := strings.TrimSpace(state.String()) 1358 expected := strings.TrimSpace(testTerraformApplyDataBasicStr) 1359 if actual != expected { 1360 t.Fatalf("bad: \n%s", actual) 1361 } 1362 } 1363 1364 func TestContext2Apply_destroyData(t *testing.T) { 1365 m := testModule(t, "apply-destroy-data-resource") 1366 p := testProvider("null") 1367 p.ApplyFn = testApplyFn 1368 p.DiffFn = testDiffFn 1369 state := &State{ 1370 Modules: []*ModuleState{ 1371 &ModuleState{ 1372 Path: rootModulePath, 1373 Resources: map[string]*ResourceState{ 1374 "data.null_data_source.testing": &ResourceState{ 1375 Type: "aws_instance", 1376 Primary: &InstanceState{ 1377 ID: "-", 1378 Attributes: map[string]string{ 1379 "inputs.#": "1", 1380 "inputs.test": "yes", 1381 }, 1382 }, 1383 }, 1384 }, 1385 }, 1386 }, 1387 } 1388 ctx := testContext2(t, &ContextOpts{ 1389 Module: m, 1390 Providers: map[string]ResourceProviderFactory{ 1391 "null": testProviderFuncFixed(p), 1392 }, 1393 State: state, 1394 Destroy: true, 1395 }) 1396 1397 if p, err := ctx.Plan(); err != nil { 1398 t.Fatalf("err: %s", err) 1399 } else { 1400 t.Logf(p.String()) 1401 } 1402 1403 newState, err := ctx.Apply() 1404 if err != nil { 1405 t.Fatalf("err: %s", err) 1406 } 1407 1408 if got := len(newState.Modules); got != 1 { 1409 t.Fatalf("state has %d modules after destroy; want 1", got) 1410 } 1411 1412 if got := len(newState.Modules[0].Resources); got != 0 { 1413 t.Fatalf("state has %d resources after destroy; want 0", got) 1414 } 1415 } 1416 1417 // https://github.com/hashicorp/terraform/pull/5096 1418 func TestContext2Apply_destroySkipsCBD(t *testing.T) { 1419 // Config contains CBD resource depending on non-CBD resource, which triggers 1420 // a cycle if they are both replaced, but should _not_ trigger a cycle when 1421 // just doing a `terraform destroy`. 1422 m := testModule(t, "apply-destroy-cbd") 1423 p := testProvider("aws") 1424 p.ApplyFn = testApplyFn 1425 p.DiffFn = testDiffFn 1426 state := &State{ 1427 Modules: []*ModuleState{ 1428 &ModuleState{ 1429 Path: rootModulePath, 1430 Resources: map[string]*ResourceState{ 1431 "aws_instance.foo": &ResourceState{ 1432 Type: "aws_instance", 1433 Primary: &InstanceState{ 1434 ID: "foo", 1435 }, 1436 }, 1437 "aws_instance.bar": &ResourceState{ 1438 Type: "aws_instance", 1439 Primary: &InstanceState{ 1440 ID: "foo", 1441 }, 1442 }, 1443 }, 1444 }, 1445 }, 1446 } 1447 ctx := testContext2(t, &ContextOpts{ 1448 Module: m, 1449 Providers: map[string]ResourceProviderFactory{ 1450 "aws": testProviderFuncFixed(p), 1451 }, 1452 State: state, 1453 Destroy: true, 1454 }) 1455 1456 if p, err := ctx.Plan(); err != nil { 1457 t.Fatalf("err: %s", err) 1458 } else { 1459 t.Logf(p.String()) 1460 } 1461 1462 if _, err := ctx.Apply(); err != nil { 1463 t.Fatalf("err: %s", err) 1464 } 1465 } 1466 1467 func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) { 1468 m := testModule(t, "apply-destroy-mod-var-provider-config") 1469 p := testProvider("aws") 1470 p.ApplyFn = testApplyFn 1471 p.DiffFn = testDiffFn 1472 state := &State{ 1473 Modules: []*ModuleState{ 1474 &ModuleState{ 1475 Path: []string{"root", "child"}, 1476 Resources: map[string]*ResourceState{ 1477 "aws_instance.foo": &ResourceState{ 1478 Type: "aws_instance", 1479 Primary: &InstanceState{ 1480 ID: "foo", 1481 }, 1482 }, 1483 }, 1484 }, 1485 }, 1486 } 1487 ctx := testContext2(t, &ContextOpts{ 1488 Module: m, 1489 Providers: map[string]ResourceProviderFactory{ 1490 "aws": testProviderFuncFixed(p), 1491 }, 1492 State: state, 1493 Destroy: true, 1494 }) 1495 1496 if _, err := ctx.Plan(); err != nil { 1497 t.Fatalf("err: %s", err) 1498 } 1499 1500 _, err := ctx.Apply() 1501 if err != nil { 1502 t.Fatalf("err: %s", err) 1503 } 1504 } 1505 1506 // https://github.com/hashicorp/terraform/issues/2892 1507 func TestContext2Apply_destroyCrossProviders(t *testing.T) { 1508 m := testModule(t, "apply-destroy-cross-providers") 1509 1510 p_aws := testProvider("aws") 1511 p_aws.ApplyFn = testApplyFn 1512 p_aws.DiffFn = testDiffFn 1513 1514 p_tf := testProvider("terraform") 1515 p_tf.ApplyFn = testApplyFn 1516 p_tf.DiffFn = testDiffFn 1517 1518 providers := map[string]ResourceProviderFactory{ 1519 "aws": testProviderFuncFixed(p_aws), 1520 "terraform": testProviderFuncFixed(p_tf), 1521 } 1522 1523 // Bug only appears from time to time, 1524 // so we run this test multiple times 1525 // to check for the race-condition 1526 for i := 0; i <= 10; i++ { 1527 ctx := getContextForApply_destroyCrossProviders( 1528 t, m, providers) 1529 1530 if p, err := ctx.Plan(); err != nil { 1531 t.Fatalf("err: %s", err) 1532 } else { 1533 t.Logf(p.String()) 1534 } 1535 1536 if _, err := ctx.Apply(); err != nil { 1537 t.Fatalf("err: %s", err) 1538 } 1539 } 1540 } 1541 1542 func getContextForApply_destroyCrossProviders( 1543 t *testing.T, 1544 m *module.Tree, 1545 providers map[string]ResourceProviderFactory) *Context { 1546 state := &State{ 1547 Modules: []*ModuleState{ 1548 &ModuleState{ 1549 Path: rootModulePath, 1550 Resources: map[string]*ResourceState{ 1551 "terraform_remote_state.shared": &ResourceState{ 1552 Type: "terraform_remote_state", 1553 Primary: &InstanceState{ 1554 ID: "remote-2652591293", 1555 Attributes: map[string]string{ 1556 "output.env_name": "test", 1557 }, 1558 }, 1559 }, 1560 }, 1561 }, 1562 &ModuleState{ 1563 Path: []string{"root", "child"}, 1564 Resources: map[string]*ResourceState{ 1565 "aws_vpc.bar": &ResourceState{ 1566 Type: "aws_vpc", 1567 Primary: &InstanceState{ 1568 ID: "vpc-aaabbb12", 1569 Attributes: map[string]string{ 1570 "value": "test", 1571 }, 1572 }, 1573 }, 1574 }, 1575 }, 1576 }, 1577 } 1578 ctx := testContext2(t, &ContextOpts{ 1579 Module: m, 1580 Providers: providers, 1581 State: state, 1582 Destroy: true, 1583 }) 1584 1585 return ctx 1586 } 1587 1588 func TestContext2Apply_minimal(t *testing.T) { 1589 m := testModule(t, "apply-minimal") 1590 p := testProvider("aws") 1591 p.ApplyFn = testApplyFn 1592 p.DiffFn = testDiffFn 1593 ctx := testContext2(t, &ContextOpts{ 1594 Module: m, 1595 Providers: map[string]ResourceProviderFactory{ 1596 "aws": testProviderFuncFixed(p), 1597 }, 1598 }) 1599 1600 if _, err := ctx.Plan(); err != nil { 1601 t.Fatalf("err: %s", err) 1602 } 1603 1604 state, err := ctx.Apply() 1605 if err != nil { 1606 t.Fatalf("err: %s", err) 1607 } 1608 1609 actual := strings.TrimSpace(state.String()) 1610 expected := strings.TrimSpace(testTerraformApplyMinimalStr) 1611 if actual != expected { 1612 t.Fatalf("bad: \n%s", actual) 1613 } 1614 } 1615 1616 func TestContext2Apply_badDiff(t *testing.T) { 1617 m := testModule(t, "apply-good") 1618 p := testProvider("aws") 1619 p.ApplyFn = testApplyFn 1620 p.DiffFn = testDiffFn 1621 ctx := testContext2(t, &ContextOpts{ 1622 Module: m, 1623 Providers: map[string]ResourceProviderFactory{ 1624 "aws": testProviderFuncFixed(p), 1625 }, 1626 }) 1627 1628 if _, err := ctx.Plan(); err != nil { 1629 t.Fatalf("err: %s", err) 1630 } 1631 1632 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1633 return &InstanceDiff{ 1634 Attributes: map[string]*ResourceAttrDiff{ 1635 "newp": nil, 1636 }, 1637 }, nil 1638 } 1639 1640 if _, err := ctx.Apply(); err == nil { 1641 t.Fatal("should error") 1642 } 1643 } 1644 1645 func TestContext2Apply_cancel(t *testing.T) { 1646 stopped := false 1647 1648 m := testModule(t, "apply-cancel") 1649 p := testProvider("aws") 1650 ctx := testContext2(t, &ContextOpts{ 1651 Module: m, 1652 Providers: map[string]ResourceProviderFactory{ 1653 "aws": testProviderFuncFixed(p), 1654 }, 1655 }) 1656 1657 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 1658 if !stopped { 1659 stopped = true 1660 go ctx.Stop() 1661 1662 for { 1663 if ctx.sh.Stopped() { 1664 break 1665 } 1666 } 1667 } 1668 1669 return &InstanceState{ 1670 ID: "foo", 1671 Attributes: map[string]string{ 1672 "num": "2", 1673 }, 1674 }, nil 1675 } 1676 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1677 return &InstanceDiff{ 1678 Attributes: map[string]*ResourceAttrDiff{ 1679 "num": &ResourceAttrDiff{ 1680 New: "bar", 1681 }, 1682 }, 1683 }, nil 1684 } 1685 1686 if _, err := ctx.Plan(); err != nil { 1687 t.Fatalf("err: %s", err) 1688 } 1689 1690 // Start the Apply in a goroutine 1691 var applyErr error 1692 stateCh := make(chan *State) 1693 go func() { 1694 state, err := ctx.Apply() 1695 if err != nil { 1696 applyErr = err 1697 } 1698 1699 stateCh <- state 1700 }() 1701 1702 state := <-stateCh 1703 if applyErr != nil { 1704 t.Fatalf("err: %s", applyErr) 1705 } 1706 1707 mod := state.RootModule() 1708 if len(mod.Resources) != 1 { 1709 t.Fatalf("bad: %s", state.String()) 1710 } 1711 1712 actual := strings.TrimSpace(state.String()) 1713 expected := strings.TrimSpace(testTerraformApplyCancelStr) 1714 if actual != expected { 1715 t.Fatalf("bad: \n%s", actual) 1716 } 1717 1718 if !p.StopCalled { 1719 t.Fatal("stop should be called") 1720 } 1721 } 1722 1723 func TestContext2Apply_compute(t *testing.T) { 1724 m := testModule(t, "apply-compute") 1725 p := testProvider("aws") 1726 p.ApplyFn = testApplyFn 1727 p.DiffFn = testDiffFn 1728 ctx := testContext2(t, &ContextOpts{ 1729 Module: m, 1730 Providers: map[string]ResourceProviderFactory{ 1731 "aws": testProviderFuncFixed(p), 1732 }, 1733 }) 1734 1735 if _, err := ctx.Plan(); err != nil { 1736 t.Fatalf("err: %s", err) 1737 } 1738 1739 ctx.variables = map[string]interface{}{"value": "1"} 1740 1741 state, err := ctx.Apply() 1742 if err != nil { 1743 t.Fatalf("err: %s", err) 1744 } 1745 1746 actual := strings.TrimSpace(state.String()) 1747 expected := strings.TrimSpace(testTerraformApplyComputeStr) 1748 if actual != expected { 1749 t.Fatalf("bad: \n%s", actual) 1750 } 1751 } 1752 1753 func TestContext2Apply_countDecrease(t *testing.T) { 1754 m := testModule(t, "apply-count-dec") 1755 p := testProvider("aws") 1756 p.DiffFn = testDiffFn 1757 s := &State{ 1758 Modules: []*ModuleState{ 1759 &ModuleState{ 1760 Path: rootModulePath, 1761 Resources: map[string]*ResourceState{ 1762 "aws_instance.foo.0": &ResourceState{ 1763 Type: "aws_instance", 1764 Primary: &InstanceState{ 1765 ID: "bar", 1766 Attributes: map[string]string{ 1767 "foo": "foo", 1768 "type": "aws_instance", 1769 }, 1770 }, 1771 }, 1772 "aws_instance.foo.1": &ResourceState{ 1773 Type: "aws_instance", 1774 Primary: &InstanceState{ 1775 ID: "bar", 1776 Attributes: map[string]string{ 1777 "foo": "foo", 1778 "type": "aws_instance", 1779 }, 1780 }, 1781 }, 1782 "aws_instance.foo.2": &ResourceState{ 1783 Type: "aws_instance", 1784 Primary: &InstanceState{ 1785 ID: "bar", 1786 Attributes: map[string]string{ 1787 "foo": "foo", 1788 "type": "aws_instance", 1789 }, 1790 }, 1791 }, 1792 }, 1793 }, 1794 }, 1795 } 1796 ctx := testContext2(t, &ContextOpts{ 1797 Module: m, 1798 Providers: map[string]ResourceProviderFactory{ 1799 "aws": testProviderFuncFixed(p), 1800 }, 1801 State: s, 1802 }) 1803 1804 if _, err := ctx.Plan(); err != nil { 1805 t.Fatalf("err: %s", err) 1806 } 1807 1808 state, err := ctx.Apply() 1809 if err != nil { 1810 t.Fatalf("err: %s", err) 1811 } 1812 1813 actual := strings.TrimSpace(state.String()) 1814 expected := strings.TrimSpace(testTerraformApplyCountDecStr) 1815 if actual != expected { 1816 t.Fatalf("bad: \n%s", actual) 1817 } 1818 } 1819 1820 func TestContext2Apply_countDecreaseToOneX(t *testing.T) { 1821 m := testModule(t, "apply-count-dec-one") 1822 p := testProvider("aws") 1823 p.ApplyFn = testApplyFn 1824 p.DiffFn = testDiffFn 1825 s := &State{ 1826 Modules: []*ModuleState{ 1827 &ModuleState{ 1828 Path: rootModulePath, 1829 Resources: map[string]*ResourceState{ 1830 "aws_instance.foo.0": &ResourceState{ 1831 Type: "aws_instance", 1832 Primary: &InstanceState{ 1833 ID: "bar", 1834 Attributes: map[string]string{ 1835 "foo": "foo", 1836 "type": "aws_instance", 1837 }, 1838 }, 1839 }, 1840 "aws_instance.foo.1": &ResourceState{ 1841 Type: "aws_instance", 1842 Primary: &InstanceState{ 1843 ID: "bar", 1844 }, 1845 }, 1846 "aws_instance.foo.2": &ResourceState{ 1847 Type: "aws_instance", 1848 Primary: &InstanceState{ 1849 ID: "bar", 1850 }, 1851 }, 1852 }, 1853 }, 1854 }, 1855 } 1856 ctx := testContext2(t, &ContextOpts{ 1857 Module: m, 1858 Providers: map[string]ResourceProviderFactory{ 1859 "aws": testProviderFuncFixed(p), 1860 }, 1861 State: s, 1862 }) 1863 1864 if _, err := ctx.Plan(); err != nil { 1865 t.Fatalf("err: %s", err) 1866 } 1867 1868 state, err := ctx.Apply() 1869 if err != nil { 1870 t.Fatalf("err: %s", err) 1871 } 1872 1873 actual := strings.TrimSpace(state.String()) 1874 expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) 1875 if actual != expected { 1876 t.Fatalf("bad: \n%s", actual) 1877 } 1878 } 1879 1880 // https://github.com/PeoplePerHour/terraform/pull/11 1881 // 1882 // This tests a case where both a "resource" and "resource.0" are in 1883 // the state file, which apparently is a reasonable backwards compatibility 1884 // concern found in the above 3rd party repo. 1885 func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { 1886 m := testModule(t, "apply-count-dec-one") 1887 p := testProvider("aws") 1888 p.ApplyFn = testApplyFn 1889 p.DiffFn = testDiffFn 1890 s := &State{ 1891 Modules: []*ModuleState{ 1892 &ModuleState{ 1893 Path: rootModulePath, 1894 Resources: map[string]*ResourceState{ 1895 "aws_instance.foo": &ResourceState{ 1896 Type: "aws_instance", 1897 Primary: &InstanceState{ 1898 ID: "bar", 1899 Attributes: map[string]string{ 1900 "foo": "foo", 1901 "type": "aws_instance", 1902 }, 1903 }, 1904 }, 1905 "aws_instance.foo.0": &ResourceState{ 1906 Type: "aws_instance", 1907 Primary: &InstanceState{ 1908 ID: "baz", 1909 Attributes: map[string]string{ 1910 "type": "aws_instance", 1911 }, 1912 }, 1913 }, 1914 }, 1915 }, 1916 }, 1917 } 1918 ctx := testContext2(t, &ContextOpts{ 1919 Module: m, 1920 Providers: map[string]ResourceProviderFactory{ 1921 "aws": testProviderFuncFixed(p), 1922 }, 1923 State: s, 1924 }) 1925 1926 if p, err := ctx.Plan(); err != nil { 1927 t.Fatalf("err: %s", err) 1928 } else { 1929 testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr) 1930 } 1931 1932 state, err := ctx.Apply() 1933 if err != nil { 1934 t.Fatalf("err: %s", err) 1935 } 1936 1937 actual := strings.TrimSpace(state.String()) 1938 expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) 1939 if actual != expected { 1940 t.Fatalf("bad: \n%s", actual) 1941 } 1942 } 1943 1944 func TestContext2Apply_countTainted(t *testing.T) { 1945 m := testModule(t, "apply-count-tainted") 1946 p := testProvider("aws") 1947 p.DiffFn = testDiffFn 1948 s := &State{ 1949 Modules: []*ModuleState{ 1950 &ModuleState{ 1951 Path: rootModulePath, 1952 Resources: map[string]*ResourceState{ 1953 "aws_instance.foo.0": &ResourceState{ 1954 Type: "aws_instance", 1955 Primary: &InstanceState{ 1956 ID: "bar", 1957 Attributes: map[string]string{ 1958 "foo": "foo", 1959 "type": "aws_instance", 1960 }, 1961 Tainted: true, 1962 }, 1963 }, 1964 }, 1965 }, 1966 }, 1967 } 1968 ctx := testContext2(t, &ContextOpts{ 1969 Module: m, 1970 Providers: map[string]ResourceProviderFactory{ 1971 "aws": testProviderFuncFixed(p), 1972 }, 1973 State: s, 1974 }) 1975 1976 if _, err := ctx.Plan(); err != nil { 1977 t.Fatalf("err: %s", err) 1978 } 1979 1980 state, err := ctx.Apply() 1981 if err != nil { 1982 t.Fatalf("err: %s", err) 1983 } 1984 1985 actual := strings.TrimSpace(state.String()) 1986 expected := strings.TrimSpace(testTerraformApplyCountTaintedStr) 1987 if actual != expected { 1988 t.Fatalf("bad: \n%s", actual) 1989 } 1990 } 1991 1992 func TestContext2Apply_countVariable(t *testing.T) { 1993 m := testModule(t, "apply-count-variable") 1994 p := testProvider("aws") 1995 p.ApplyFn = testApplyFn 1996 p.DiffFn = testDiffFn 1997 ctx := testContext2(t, &ContextOpts{ 1998 Module: m, 1999 Providers: map[string]ResourceProviderFactory{ 2000 "aws": testProviderFuncFixed(p), 2001 }, 2002 }) 2003 2004 if _, err := ctx.Plan(); err != nil { 2005 t.Fatalf("err: %s", err) 2006 } 2007 2008 state, err := ctx.Apply() 2009 if err != nil { 2010 t.Fatalf("err: %s", err) 2011 } 2012 2013 actual := strings.TrimSpace(state.String()) 2014 expected := strings.TrimSpace(testTerraformApplyCountVariableStr) 2015 if actual != expected { 2016 t.Fatalf("bad: \n%s", actual) 2017 } 2018 } 2019 2020 func TestContext2Apply_countVariableRef(t *testing.T) { 2021 m := testModule(t, "apply-count-variable-ref") 2022 p := testProvider("aws") 2023 p.ApplyFn = testApplyFn 2024 p.DiffFn = testDiffFn 2025 ctx := testContext2(t, &ContextOpts{ 2026 Module: m, 2027 Providers: map[string]ResourceProviderFactory{ 2028 "aws": testProviderFuncFixed(p), 2029 }, 2030 }) 2031 2032 if _, err := ctx.Plan(); err != nil { 2033 t.Fatalf("err: %s", err) 2034 } 2035 2036 state, err := ctx.Apply() 2037 if err != nil { 2038 t.Fatalf("err: %s", err) 2039 } 2040 2041 actual := strings.TrimSpace(state.String()) 2042 expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr) 2043 if actual != expected { 2044 t.Fatalf("bad: \n%s", actual) 2045 } 2046 } 2047 2048 func TestContext2Apply_mapVariableOverride(t *testing.T) { 2049 m := testModule(t, "apply-map-var-override") 2050 p := testProvider("aws") 2051 p.ApplyFn = testApplyFn 2052 p.DiffFn = testDiffFn 2053 ctx := testContext2(t, &ContextOpts{ 2054 Module: m, 2055 Providers: map[string]ResourceProviderFactory{ 2056 "aws": testProviderFuncFixed(p), 2057 }, 2058 Variables: map[string]interface{}{ 2059 "images": []map[string]interface{}{ 2060 map[string]interface{}{ 2061 "us-west-2": "overridden", 2062 }, 2063 }, 2064 }, 2065 }) 2066 2067 if _, err := ctx.Plan(); err != nil { 2068 t.Fatalf("err: %s", err) 2069 } 2070 2071 state, err := ctx.Apply() 2072 if err != nil { 2073 t.Fatalf("err: %s", err) 2074 } 2075 2076 actual := strings.TrimSpace(state.String()) 2077 expected := strings.TrimSpace(` 2078 aws_instance.bar: 2079 ID = foo 2080 ami = overridden 2081 type = aws_instance 2082 aws_instance.foo: 2083 ID = foo 2084 ami = image-1234 2085 type = aws_instance 2086 `) 2087 if actual != expected { 2088 t.Fatalf("got: \n%s\nexpected: \n%s", actual, expected) 2089 } 2090 } 2091 2092 func TestContext2Apply_moduleBasic(t *testing.T) { 2093 m := testModule(t, "apply-module") 2094 p := testProvider("aws") 2095 p.ApplyFn = testApplyFn 2096 p.DiffFn = testDiffFn 2097 ctx := testContext2(t, &ContextOpts{ 2098 Module: m, 2099 Providers: map[string]ResourceProviderFactory{ 2100 "aws": testProviderFuncFixed(p), 2101 }, 2102 }) 2103 2104 if _, err := ctx.Plan(); err != nil { 2105 t.Fatalf("err: %s", err) 2106 } 2107 2108 state, err := ctx.Apply() 2109 if err != nil { 2110 t.Fatalf("err: %s", err) 2111 } 2112 2113 actual := strings.TrimSpace(state.String()) 2114 expected := strings.TrimSpace(testTerraformApplyModuleStr) 2115 if actual != expected { 2116 t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual) 2117 } 2118 } 2119 2120 func TestContext2Apply_moduleDestroyOrder(t *testing.T) { 2121 m := testModule(t, "apply-module-destroy-order") 2122 p := testProvider("aws") 2123 p.DiffFn = testDiffFn 2124 2125 // Create a custom apply function to track the order they were destroyed 2126 var order []string 2127 var orderLock sync.Mutex 2128 p.ApplyFn = func( 2129 info *InstanceInfo, 2130 is *InstanceState, 2131 id *InstanceDiff) (*InstanceState, error) { 2132 orderLock.Lock() 2133 defer orderLock.Unlock() 2134 2135 order = append(order, is.ID) 2136 return nil, nil 2137 } 2138 2139 state := &State{ 2140 Modules: []*ModuleState{ 2141 &ModuleState{ 2142 Path: rootModulePath, 2143 Resources: map[string]*ResourceState{ 2144 "aws_instance.b": &ResourceState{ 2145 Type: "aws_instance", 2146 Primary: &InstanceState{ 2147 ID: "b", 2148 }, 2149 }, 2150 }, 2151 }, 2152 2153 &ModuleState{ 2154 Path: []string{"root", "child"}, 2155 Resources: map[string]*ResourceState{ 2156 "aws_instance.a": &ResourceState{ 2157 Type: "aws_instance", 2158 Primary: &InstanceState{ 2159 ID: "a", 2160 }, 2161 }, 2162 }, 2163 Outputs: map[string]*OutputState{ 2164 "a_output": &OutputState{ 2165 Type: "string", 2166 Sensitive: false, 2167 Value: "a", 2168 }, 2169 }, 2170 }, 2171 }, 2172 } 2173 2174 ctx := testContext2(t, &ContextOpts{ 2175 Module: m, 2176 Providers: map[string]ResourceProviderFactory{ 2177 "aws": testProviderFuncFixed(p), 2178 }, 2179 State: state, 2180 Destroy: true, 2181 }) 2182 2183 if _, err := ctx.Plan(); err != nil { 2184 t.Fatalf("err: %s", err) 2185 } 2186 2187 state, err := ctx.Apply() 2188 if err != nil { 2189 t.Fatalf("err: %s", err) 2190 } 2191 2192 expected := []string{"b", "a"} 2193 if !reflect.DeepEqual(order, expected) { 2194 t.Fatalf("bad: %#v", order) 2195 } 2196 2197 { 2198 actual := strings.TrimSpace(state.String()) 2199 expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr) 2200 if actual != expected { 2201 t.Fatalf("bad: \n%s", actual) 2202 } 2203 } 2204 } 2205 2206 func TestContext2Apply_moduleInheritAlias(t *testing.T) { 2207 m := testModule(t, "apply-module-provider-inherit-alias") 2208 p := testProvider("aws") 2209 p.ApplyFn = testApplyFn 2210 p.DiffFn = testDiffFn 2211 2212 p.ConfigureFn = func(c *ResourceConfig) error { 2213 if _, ok := c.Get("child"); !ok { 2214 return nil 2215 } 2216 2217 if _, ok := c.Get("root"); ok { 2218 return fmt.Errorf("child should not get root") 2219 } 2220 2221 return nil 2222 } 2223 2224 ctx := testContext2(t, &ContextOpts{ 2225 Module: m, 2226 Providers: map[string]ResourceProviderFactory{ 2227 "aws": testProviderFuncFixed(p), 2228 }, 2229 }) 2230 2231 if _, err := ctx.Plan(); err != nil { 2232 t.Fatalf("err: %s", err) 2233 } 2234 2235 state, err := ctx.Apply() 2236 if err != nil { 2237 t.Fatalf("err: %s", err) 2238 } 2239 2240 checkStateString(t, state, ` 2241 <no state> 2242 module.child: 2243 aws_instance.foo: 2244 ID = foo 2245 provider = aws.eu 2246 `) 2247 } 2248 2249 func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) { 2250 m := testModule(t, "apply-module-provider-inherit-alias-orphan") 2251 p := testProvider("aws") 2252 p.ApplyFn = testApplyFn 2253 p.DiffFn = testDiffFn 2254 2255 called := false 2256 p.ConfigureFn = func(c *ResourceConfig) error { 2257 called = true 2258 2259 if _, ok := c.Get("child"); !ok { 2260 return nil 2261 } 2262 2263 if _, ok := c.Get("root"); ok { 2264 return fmt.Errorf("child should not get root") 2265 } 2266 2267 return nil 2268 } 2269 2270 // Create a state with an orphan module 2271 state := &State{ 2272 Modules: []*ModuleState{ 2273 &ModuleState{ 2274 Path: []string{"root", "child"}, 2275 Resources: map[string]*ResourceState{ 2276 "aws_instance.bar": &ResourceState{ 2277 Type: "aws_instance", 2278 Primary: &InstanceState{ 2279 ID: "bar", 2280 }, 2281 Provider: "aws.eu", 2282 }, 2283 }, 2284 }, 2285 }, 2286 } 2287 2288 ctx := testContext2(t, &ContextOpts{ 2289 Module: m, 2290 State: state, 2291 Providers: map[string]ResourceProviderFactory{ 2292 "aws": testProviderFuncFixed(p), 2293 }, 2294 }) 2295 2296 if _, err := ctx.Plan(); err != nil { 2297 t.Fatalf("err: %s", err) 2298 } 2299 2300 state, err := ctx.Apply() 2301 if err != nil { 2302 t.Fatalf("err: %s", err) 2303 } 2304 2305 if !called { 2306 t.Fatal("must call configure") 2307 } 2308 2309 checkStateString(t, state, ` 2310 module.child: 2311 <no state> 2312 `) 2313 } 2314 2315 func TestContext2Apply_moduleOrphanProvider(t *testing.T) { 2316 m := testModule(t, "apply-module-orphan-provider-inherit") 2317 p := testProvider("aws") 2318 p.ApplyFn = testApplyFn 2319 p.DiffFn = testDiffFn 2320 2321 p.ConfigureFn = func(c *ResourceConfig) error { 2322 if _, ok := c.Get("value"); !ok { 2323 return fmt.Errorf("value is not found") 2324 } 2325 2326 return nil 2327 } 2328 2329 // Create a state with an orphan module 2330 state := &State{ 2331 Modules: []*ModuleState{ 2332 &ModuleState{ 2333 Path: []string{"root", "child"}, 2334 Resources: map[string]*ResourceState{ 2335 "aws_instance.bar": &ResourceState{ 2336 Type: "aws_instance", 2337 Primary: &InstanceState{ 2338 ID: "bar", 2339 }, 2340 }, 2341 }, 2342 }, 2343 }, 2344 } 2345 2346 ctx := testContext2(t, &ContextOpts{ 2347 Module: m, 2348 State: state, 2349 Providers: map[string]ResourceProviderFactory{ 2350 "aws": testProviderFuncFixed(p), 2351 }, 2352 }) 2353 2354 if _, err := ctx.Plan(); err != nil { 2355 t.Fatalf("err: %s", err) 2356 } 2357 2358 if _, err := ctx.Apply(); err != nil { 2359 t.Fatalf("err: %s", err) 2360 } 2361 } 2362 2363 func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) { 2364 m := testModule(t, "apply-module-orphan-provider-inherit") 2365 p := testProvider("aws") 2366 p.ApplyFn = testApplyFn 2367 p.DiffFn = testDiffFn 2368 2369 p.ConfigureFn = func(c *ResourceConfig) error { 2370 if _, ok := c.Get("value"); !ok { 2371 return fmt.Errorf("value is not found") 2372 } 2373 2374 return nil 2375 } 2376 2377 // Create a state with an orphan module that is nested (grandchild) 2378 state := &State{ 2379 Modules: []*ModuleState{ 2380 &ModuleState{ 2381 Path: []string{"root", "parent", "child"}, 2382 Resources: map[string]*ResourceState{ 2383 "aws_instance.bar": &ResourceState{ 2384 Type: "aws_instance", 2385 Primary: &InstanceState{ 2386 ID: "bar", 2387 }, 2388 }, 2389 }, 2390 }, 2391 }, 2392 } 2393 2394 ctx := testContext2(t, &ContextOpts{ 2395 Module: m, 2396 State: state, 2397 Providers: map[string]ResourceProviderFactory{ 2398 "aws": testProviderFuncFixed(p), 2399 }, 2400 }) 2401 2402 if _, err := ctx.Plan(); err != nil { 2403 t.Fatalf("err: %s", err) 2404 } 2405 2406 if _, err := ctx.Apply(); err != nil { 2407 t.Fatalf("err: %s", err) 2408 } 2409 } 2410 2411 func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { 2412 m := testModule(t, "apply-module-grandchild-provider-inherit") 2413 p := testProvider("aws") 2414 p.ApplyFn = testApplyFn 2415 p.DiffFn = testDiffFn 2416 2417 var callLock sync.Mutex 2418 called := false 2419 p.ConfigureFn = func(c *ResourceConfig) error { 2420 if _, ok := c.Get("value"); !ok { 2421 return fmt.Errorf("value is not found") 2422 } 2423 callLock.Lock() 2424 called = true 2425 callLock.Unlock() 2426 2427 return nil 2428 } 2429 2430 ctx := testContext2(t, &ContextOpts{ 2431 Module: m, 2432 Providers: map[string]ResourceProviderFactory{ 2433 "aws": testProviderFuncFixed(p), 2434 }, 2435 }) 2436 2437 if _, err := ctx.Plan(); err != nil { 2438 t.Fatalf("err: %s", err) 2439 } 2440 2441 if _, err := ctx.Apply(); err != nil { 2442 t.Fatalf("err: %s", err) 2443 } 2444 2445 callLock.Lock() 2446 defer callLock.Unlock() 2447 if called != true { 2448 t.Fatalf("err: configure never called") 2449 } 2450 } 2451 2452 // This tests an issue where all the providers in a module but not 2453 // in the root weren't being added to the root properly. In this test 2454 // case: aws is explicitly added to root, but "test" should be added to. 2455 // With the bug, it wasn't. 2456 func TestContext2Apply_moduleOnlyProvider(t *testing.T) { 2457 m := testModule(t, "apply-module-only-provider") 2458 p := testProvider("aws") 2459 p.ApplyFn = testApplyFn 2460 p.DiffFn = testDiffFn 2461 pTest := testProvider("test") 2462 pTest.ApplyFn = testApplyFn 2463 pTest.DiffFn = testDiffFn 2464 2465 ctx := testContext2(t, &ContextOpts{ 2466 Module: m, 2467 Providers: map[string]ResourceProviderFactory{ 2468 "aws": testProviderFuncFixed(p), 2469 "test": testProviderFuncFixed(pTest), 2470 }, 2471 }) 2472 2473 if _, err := ctx.Plan(); err != nil { 2474 t.Fatalf("err: %s", err) 2475 } 2476 2477 state, err := ctx.Apply() 2478 if err != nil { 2479 t.Fatalf("err: %s", err) 2480 } 2481 2482 actual := strings.TrimSpace(state.String()) 2483 expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) 2484 if actual != expected { 2485 t.Fatalf("bad: \n%s", actual) 2486 } 2487 } 2488 2489 func TestContext2Apply_moduleProviderAlias(t *testing.T) { 2490 m := testModule(t, "apply-module-provider-alias") 2491 p := testProvider("aws") 2492 p.ApplyFn = testApplyFn 2493 p.DiffFn = testDiffFn 2494 ctx := testContext2(t, &ContextOpts{ 2495 Module: m, 2496 Providers: map[string]ResourceProviderFactory{ 2497 "aws": testProviderFuncFixed(p), 2498 }, 2499 }) 2500 2501 if _, err := ctx.Plan(); err != nil { 2502 t.Fatalf("err: %s", err) 2503 } 2504 2505 state, err := ctx.Apply() 2506 if err != nil { 2507 t.Fatalf("err: %s", err) 2508 } 2509 2510 actual := strings.TrimSpace(state.String()) 2511 expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) 2512 if actual != expected { 2513 t.Fatalf("bad: \n%s", actual) 2514 } 2515 } 2516 2517 func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { 2518 m := testModule(t, "apply-module-provider-alias") 2519 p := testProvider("aws") 2520 p.ApplyFn = testApplyFn 2521 p.DiffFn = testDiffFn 2522 ctx := testContext2(t, &ContextOpts{ 2523 Module: m, 2524 Providers: map[string]ResourceProviderFactory{ 2525 "aws": testProviderFuncFixed(p), 2526 }, 2527 Targets: []string{"no.thing"}, 2528 }) 2529 2530 if _, err := ctx.Plan(); err != nil { 2531 t.Fatalf("err: %s", err) 2532 } 2533 2534 state, err := ctx.Apply() 2535 if err != nil { 2536 t.Fatalf("err: %s", err) 2537 } 2538 2539 actual := strings.TrimSpace(state.String()) 2540 expected := strings.TrimSpace(` 2541 <no state> 2542 `) 2543 if actual != expected { 2544 t.Fatalf("bad: \n%s", actual) 2545 } 2546 } 2547 2548 func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { 2549 m := testModule(t, "apply-module-provider-close-nested") 2550 p := testProvider("aws") 2551 p.ApplyFn = testApplyFn 2552 p.DiffFn = testDiffFn 2553 ctx := testContext2(t, &ContextOpts{ 2554 Module: m, 2555 Providers: map[string]ResourceProviderFactory{ 2556 "aws": testProviderFuncFixed(p), 2557 }, 2558 State: &State{ 2559 Modules: []*ModuleState{ 2560 &ModuleState{ 2561 Path: []string{"root", "child", "subchild"}, 2562 Resources: map[string]*ResourceState{ 2563 "aws_instance.foo": &ResourceState{ 2564 Type: "aws_instance", 2565 Primary: &InstanceState{ 2566 ID: "bar", 2567 }, 2568 }, 2569 }, 2570 }, 2571 }, 2572 }, 2573 Destroy: true, 2574 }) 2575 2576 if _, err := ctx.Plan(); err != nil { 2577 t.Fatalf("err: %s", err) 2578 } 2579 2580 if _, err := ctx.Apply(); err != nil { 2581 t.Fatalf("err: %s", err) 2582 } 2583 } 2584 2585 // Tests that variables used as module vars that reference data that 2586 // already exists in the state and requires no diff works properly. This 2587 // fixes an issue faced where module variables were pruned because they were 2588 // accessing "non-existent" resources (they existed, just not in the graph 2589 // cause they weren't in the diff). 2590 func TestContext2Apply_moduleVarRefExisting(t *testing.T) { 2591 m := testModule(t, "apply-ref-existing") 2592 p := testProvider("aws") 2593 p.ApplyFn = testApplyFn 2594 p.DiffFn = testDiffFn 2595 2596 state := &State{ 2597 Modules: []*ModuleState{ 2598 &ModuleState{ 2599 Path: rootModulePath, 2600 Resources: map[string]*ResourceState{ 2601 "aws_instance.foo": &ResourceState{ 2602 Type: "aws_instance", 2603 Primary: &InstanceState{ 2604 ID: "foo", 2605 Attributes: map[string]string{ 2606 "foo": "bar", 2607 }, 2608 }, 2609 }, 2610 }, 2611 }, 2612 }, 2613 } 2614 2615 ctx := testContext2(t, &ContextOpts{ 2616 Module: m, 2617 Providers: map[string]ResourceProviderFactory{ 2618 "aws": testProviderFuncFixed(p), 2619 }, 2620 State: state, 2621 }) 2622 2623 if _, err := ctx.Plan(); err != nil { 2624 t.Fatalf("err: %s", err) 2625 } 2626 2627 state, err := ctx.Apply() 2628 if err != nil { 2629 t.Fatalf("err: %s", err) 2630 } 2631 2632 actual := strings.TrimSpace(state.String()) 2633 expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr) 2634 if actual != expected { 2635 t.Fatalf("bad: \n%s", actual) 2636 } 2637 } 2638 2639 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 2640 m := testModule(t, "apply-module-var-resource-count") 2641 p := testProvider("aws") 2642 p.ApplyFn = testApplyFn 2643 p.DiffFn = testDiffFn 2644 ctx := testContext2(t, &ContextOpts{ 2645 Module: m, 2646 Providers: map[string]ResourceProviderFactory{ 2647 "aws": testProviderFuncFixed(p), 2648 }, 2649 Variables: map[string]interface{}{ 2650 "count": "2", 2651 }, 2652 Destroy: true, 2653 }) 2654 2655 if _, err := ctx.Plan(); err != nil { 2656 t.Fatalf("err: %s", err) 2657 } 2658 2659 if _, err := ctx.Apply(); err != nil { 2660 t.Fatalf("err: %s", err) 2661 } 2662 2663 ctx = testContext2(t, &ContextOpts{ 2664 Module: m, 2665 Providers: map[string]ResourceProviderFactory{ 2666 "aws": testProviderFuncFixed(p), 2667 }, 2668 Variables: map[string]interface{}{ 2669 "count": "5", 2670 }, 2671 }) 2672 2673 if _, err := ctx.Plan(); err != nil { 2674 t.Fatalf("err: %s", err) 2675 } 2676 2677 if _, err := ctx.Apply(); err != nil { 2678 t.Fatalf("err: %s", err) 2679 } 2680 } 2681 2682 // GH-819 2683 func TestContext2Apply_moduleBool(t *testing.T) { 2684 m := testModule(t, "apply-module-bool") 2685 p := testProvider("aws") 2686 p.ApplyFn = testApplyFn 2687 p.DiffFn = testDiffFn 2688 ctx := testContext2(t, &ContextOpts{ 2689 Module: m, 2690 Providers: map[string]ResourceProviderFactory{ 2691 "aws": testProviderFuncFixed(p), 2692 }, 2693 }) 2694 2695 if _, err := ctx.Plan(); err != nil { 2696 t.Fatalf("err: %s", err) 2697 } 2698 2699 state, err := ctx.Apply() 2700 if err != nil { 2701 t.Fatalf("err: %s", err) 2702 } 2703 2704 actual := strings.TrimSpace(state.String()) 2705 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 2706 if actual != expected { 2707 t.Fatalf("bad: \n%s", actual) 2708 } 2709 } 2710 2711 // Tests that a module can be targeted and everything is properly created. 2712 // This adds to the plan test to also just verify that apply works. 2713 func TestContext2Apply_moduleTarget(t *testing.T) { 2714 m := testModule(t, "plan-targeted-cross-module") 2715 p := testProvider("aws") 2716 p.ApplyFn = testApplyFn 2717 p.DiffFn = testDiffFn 2718 ctx := testContext2(t, &ContextOpts{ 2719 Module: m, 2720 Providers: map[string]ResourceProviderFactory{ 2721 "aws": testProviderFuncFixed(p), 2722 }, 2723 Targets: []string{"module.B"}, 2724 }) 2725 2726 if _, err := ctx.Plan(); err != nil { 2727 t.Fatalf("err: %s", err) 2728 } 2729 2730 state, err := ctx.Apply() 2731 if err != nil { 2732 t.Fatalf("err: %s", err) 2733 } 2734 2735 checkStateString(t, state, ` 2736 <no state> 2737 module.A: 2738 aws_instance.foo: 2739 ID = foo 2740 foo = bar 2741 type = aws_instance 2742 2743 Outputs: 2744 2745 value = foo 2746 module.B: 2747 aws_instance.bar: 2748 ID = foo 2749 foo = foo 2750 type = aws_instance 2751 `) 2752 } 2753 2754 func TestContext2Apply_multiProvider(t *testing.T) { 2755 m := testModule(t, "apply-multi-provider") 2756 p := testProvider("aws") 2757 p.ApplyFn = testApplyFn 2758 p.DiffFn = testDiffFn 2759 2760 pDO := testProvider("do") 2761 pDO.ApplyFn = testApplyFn 2762 pDO.DiffFn = testDiffFn 2763 2764 ctx := testContext2(t, &ContextOpts{ 2765 Module: m, 2766 Providers: map[string]ResourceProviderFactory{ 2767 "aws": testProviderFuncFixed(p), 2768 "do": testProviderFuncFixed(pDO), 2769 }, 2770 }) 2771 2772 if _, err := ctx.Plan(); err != nil { 2773 t.Fatalf("err: %s", err) 2774 } 2775 2776 state, err := ctx.Apply() 2777 if err != nil { 2778 t.Fatalf("err: %s", err) 2779 } 2780 2781 mod := state.RootModule() 2782 if len(mod.Resources) < 2 { 2783 t.Fatalf("bad: %#v", mod.Resources) 2784 } 2785 2786 actual := strings.TrimSpace(state.String()) 2787 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 2788 if actual != expected { 2789 t.Fatalf("bad: \n%s", actual) 2790 } 2791 } 2792 2793 func TestContext2Apply_multiProviderDestroy(t *testing.T) { 2794 m := testModule(t, "apply-multi-provider-destroy") 2795 p := testProvider("aws") 2796 p.ApplyFn = testApplyFn 2797 p.DiffFn = testDiffFn 2798 2799 p2 := testProvider("do") 2800 p2.ApplyFn = testApplyFn 2801 p2.DiffFn = testDiffFn 2802 2803 var state *State 2804 2805 // First, create the instances 2806 { 2807 ctx := testContext2(t, &ContextOpts{ 2808 Module: m, 2809 Providers: map[string]ResourceProviderFactory{ 2810 "aws": testProviderFuncFixed(p), 2811 "vault": testProviderFuncFixed(p2), 2812 }, 2813 }) 2814 2815 if _, err := ctx.Plan(); err != nil { 2816 t.Fatalf("err: %s", err) 2817 } 2818 2819 s, err := ctx.Apply() 2820 if err != nil { 2821 t.Fatalf("err: %s", err) 2822 } 2823 2824 state = s 2825 } 2826 2827 // Destroy them 2828 { 2829 // Verify that aws_instance.bar is destroyed first 2830 var checked bool 2831 var called int32 2832 var lock sync.Mutex 2833 applyFn := func( 2834 info *InstanceInfo, 2835 is *InstanceState, 2836 id *InstanceDiff) (*InstanceState, error) { 2837 lock.Lock() 2838 defer lock.Unlock() 2839 2840 if info.HumanId() == "aws_instance.bar" { 2841 checked = true 2842 2843 // Sleep to allow parallel execution 2844 time.Sleep(50 * time.Millisecond) 2845 2846 // Verify that called is 0 (dep not called) 2847 if atomic.LoadInt32(&called) != 0 { 2848 return nil, fmt.Errorf("nothing else should be called") 2849 } 2850 } 2851 2852 atomic.AddInt32(&called, 1) 2853 return testApplyFn(info, is, id) 2854 } 2855 2856 // Set the apply functions 2857 p.ApplyFn = applyFn 2858 p2.ApplyFn = applyFn 2859 2860 ctx := testContext2(t, &ContextOpts{ 2861 Destroy: true, 2862 State: state, 2863 Module: m, 2864 Providers: map[string]ResourceProviderFactory{ 2865 "aws": testProviderFuncFixed(p), 2866 "vault": testProviderFuncFixed(p2), 2867 }, 2868 }) 2869 2870 if _, err := ctx.Plan(); err != nil { 2871 t.Fatalf("err: %s", err) 2872 } 2873 2874 s, err := ctx.Apply() 2875 if err != nil { 2876 t.Fatalf("err: %s", err) 2877 } 2878 2879 if !checked { 2880 t.Fatal("should be checked") 2881 } 2882 2883 state = s 2884 } 2885 2886 checkStateString(t, state, `<no state>`) 2887 } 2888 2889 // This is like the multiProviderDestroy test except it tests that 2890 // dependent resources within a child module that inherit provider 2891 // configuration are still destroyed first. 2892 func TestContext2Apply_multiProviderDestroyChild(t *testing.T) { 2893 m := testModule(t, "apply-multi-provider-destroy-child") 2894 p := testProvider("aws") 2895 p.ApplyFn = testApplyFn 2896 p.DiffFn = testDiffFn 2897 2898 p2 := testProvider("do") 2899 p2.ApplyFn = testApplyFn 2900 p2.DiffFn = testDiffFn 2901 2902 var state *State 2903 2904 // First, create the instances 2905 { 2906 ctx := testContext2(t, &ContextOpts{ 2907 Module: m, 2908 Providers: map[string]ResourceProviderFactory{ 2909 "aws": testProviderFuncFixed(p), 2910 "vault": testProviderFuncFixed(p2), 2911 }, 2912 }) 2913 2914 if _, err := ctx.Plan(); err != nil { 2915 t.Fatalf("err: %s", err) 2916 } 2917 2918 s, err := ctx.Apply() 2919 if err != nil { 2920 t.Fatalf("err: %s", err) 2921 } 2922 2923 state = s 2924 } 2925 2926 // Destroy them 2927 { 2928 // Verify that aws_instance.bar is destroyed first 2929 var checked bool 2930 var called int32 2931 var lock sync.Mutex 2932 applyFn := func( 2933 info *InstanceInfo, 2934 is *InstanceState, 2935 id *InstanceDiff) (*InstanceState, error) { 2936 lock.Lock() 2937 defer lock.Unlock() 2938 2939 if info.HumanId() == "module.child.aws_instance.bar" { 2940 checked = true 2941 2942 // Sleep to allow parallel execution 2943 time.Sleep(50 * time.Millisecond) 2944 2945 // Verify that called is 0 (dep not called) 2946 if atomic.LoadInt32(&called) != 0 { 2947 return nil, fmt.Errorf("nothing else should be called") 2948 } 2949 } 2950 2951 atomic.AddInt32(&called, 1) 2952 return testApplyFn(info, is, id) 2953 } 2954 2955 // Set the apply functions 2956 p.ApplyFn = applyFn 2957 p2.ApplyFn = applyFn 2958 2959 ctx := testContext2(t, &ContextOpts{ 2960 Destroy: true, 2961 State: state, 2962 Module: m, 2963 Providers: map[string]ResourceProviderFactory{ 2964 "aws": testProviderFuncFixed(p), 2965 "vault": testProviderFuncFixed(p2), 2966 }, 2967 }) 2968 2969 if _, err := ctx.Plan(); err != nil { 2970 t.Fatalf("err: %s", err) 2971 } 2972 2973 s, err := ctx.Apply() 2974 if err != nil { 2975 t.Fatalf("err: %s", err) 2976 } 2977 2978 if !checked { 2979 t.Fatal("should be checked") 2980 } 2981 2982 state = s 2983 } 2984 2985 checkStateString(t, state, ` 2986 <no state> 2987 module.child: 2988 <no state> 2989 `) 2990 } 2991 2992 func TestContext2Apply_multiVar(t *testing.T) { 2993 m := testModule(t, "apply-multi-var") 2994 p := testProvider("aws") 2995 p.ApplyFn = testApplyFn 2996 p.DiffFn = testDiffFn 2997 2998 // First, apply with a count of 3 2999 ctx := testContext2(t, &ContextOpts{ 3000 Module: m, 3001 Providers: map[string]ResourceProviderFactory{ 3002 "aws": testProviderFuncFixed(p), 3003 }, 3004 Variables: map[string]interface{}{ 3005 "count": "3", 3006 }, 3007 }) 3008 3009 if _, err := ctx.Plan(); err != nil { 3010 t.Fatalf("err: %s", err) 3011 } 3012 3013 state, err := ctx.Apply() 3014 if err != nil { 3015 t.Fatalf("err: %s", err) 3016 } 3017 3018 actual := state.RootModule().Outputs["output"] 3019 expected := "bar0,bar1,bar2" 3020 if actual == nil || actual.Value != expected { 3021 t.Fatalf("bad: \n%s", actual) 3022 } 3023 3024 t.Logf("Initial state: %s", state.String()) 3025 3026 // Apply again, reduce the count to 1 3027 { 3028 ctx := testContext2(t, &ContextOpts{ 3029 Module: m, 3030 State: state, 3031 Providers: map[string]ResourceProviderFactory{ 3032 "aws": testProviderFuncFixed(p), 3033 }, 3034 Variables: map[string]interface{}{ 3035 "count": "1", 3036 }, 3037 }) 3038 3039 if _, err := ctx.Plan(); err != nil { 3040 t.Fatalf("err: %s", err) 3041 } 3042 3043 state, err := ctx.Apply() 3044 if err != nil { 3045 t.Fatalf("err: %s", err) 3046 } 3047 3048 t.Logf("End state: %s", state.String()) 3049 3050 actual := state.RootModule().Outputs["output"] 3051 if actual == nil { 3052 t.Fatal("missing output") 3053 } 3054 3055 expected := "bar0" 3056 if actual.Value != expected { 3057 t.Fatalf("bad: \n%s", actual) 3058 } 3059 } 3060 } 3061 3062 // Test that multi-var (splat) access is ordered by count, not by 3063 // value. 3064 func TestContext2Apply_multiVarOrder(t *testing.T) { 3065 m := testModule(t, "apply-multi-var-order") 3066 p := testProvider("aws") 3067 p.ApplyFn = testApplyFn 3068 p.DiffFn = testDiffFn 3069 3070 // First, apply with a count of 3 3071 ctx := testContext2(t, &ContextOpts{ 3072 Module: m, 3073 Providers: map[string]ResourceProviderFactory{ 3074 "aws": testProviderFuncFixed(p), 3075 }, 3076 }) 3077 3078 if _, err := ctx.Plan(); err != nil { 3079 t.Fatalf("err: %s", err) 3080 } 3081 3082 state, err := ctx.Apply() 3083 if err != nil { 3084 t.Fatalf("err: %s", err) 3085 } 3086 3087 t.Logf("State: %s", state.String()) 3088 3089 actual := state.RootModule().Outputs["should-be-11"] 3090 expected := "index-11" 3091 if actual == nil || actual.Value != expected { 3092 t.Fatalf("bad: \n%s", actual) 3093 } 3094 } 3095 3096 // Test that multi-var (splat) access is ordered by count, not by 3097 // value, through interpolations. 3098 func TestContext2Apply_multiVarOrderInterp(t *testing.T) { 3099 m := testModule(t, "apply-multi-var-order-interp") 3100 p := testProvider("aws") 3101 p.ApplyFn = testApplyFn 3102 p.DiffFn = testDiffFn 3103 3104 // First, apply with a count of 3 3105 ctx := testContext2(t, &ContextOpts{ 3106 Module: m, 3107 Providers: map[string]ResourceProviderFactory{ 3108 "aws": testProviderFuncFixed(p), 3109 }, 3110 }) 3111 3112 if _, err := ctx.Plan(); err != nil { 3113 t.Fatalf("err: %s", err) 3114 } 3115 3116 state, err := ctx.Apply() 3117 if err != nil { 3118 t.Fatalf("err: %s", err) 3119 } 3120 3121 t.Logf("State: %s", state.String()) 3122 3123 actual := state.RootModule().Outputs["should-be-11"] 3124 expected := "baz-index-11" 3125 if actual == nil || actual.Value != expected { 3126 t.Fatalf("bad: \n%s", actual) 3127 } 3128 } 3129 3130 // Based on GH-10440 where a graph edge wasn't properly being created 3131 // between a modified resource and a count instance being destroyed. 3132 func TestContext2Apply_multiVarCountDec(t *testing.T) { 3133 var s *State 3134 3135 // First create resources. Nothing sneaky here. 3136 { 3137 m := testModule(t, "apply-multi-var-count-dec") 3138 p := testProvider("aws") 3139 p.ApplyFn = testApplyFn 3140 p.DiffFn = testDiffFn 3141 ctx := testContext2(t, &ContextOpts{ 3142 Module: m, 3143 Providers: map[string]ResourceProviderFactory{ 3144 "aws": testProviderFuncFixed(p), 3145 }, 3146 Variables: map[string]interface{}{ 3147 "count": "2", 3148 }, 3149 }) 3150 3151 if _, err := ctx.Plan(); err != nil { 3152 t.Fatalf("err: %s", err) 3153 } 3154 3155 state, err := ctx.Apply() 3156 if err != nil { 3157 t.Fatalf("err: %s", err) 3158 } 3159 3160 t.Logf("Step 1 state: %s", state) 3161 3162 s = state 3163 } 3164 3165 // Decrease the count by 1 and verify that everything happens in the 3166 // right order. 3167 { 3168 m := testModule(t, "apply-multi-var-count-dec") 3169 p := testProvider("aws") 3170 p.ApplyFn = testApplyFn 3171 p.DiffFn = testDiffFn 3172 3173 // Verify that aws_instance.bar is modified first and nothing 3174 // else happens at the same time. 3175 var checked bool 3176 var called int32 3177 var lock sync.Mutex 3178 p.ApplyFn = func( 3179 info *InstanceInfo, 3180 is *InstanceState, 3181 id *InstanceDiff) (*InstanceState, error) { 3182 lock.Lock() 3183 defer lock.Unlock() 3184 3185 if info.HumanId() == "aws_instance.bar" { 3186 checked = true 3187 3188 // Sleep to allow parallel execution 3189 time.Sleep(50 * time.Millisecond) 3190 3191 // Verify that called is 0 (dep not called) 3192 if atomic.LoadInt32(&called) != 1 { 3193 return nil, fmt.Errorf("nothing else should be called") 3194 } 3195 } 3196 3197 atomic.AddInt32(&called, 1) 3198 return testApplyFn(info, is, id) 3199 } 3200 3201 ctx := testContext2(t, &ContextOpts{ 3202 State: s, 3203 Module: m, 3204 Providers: map[string]ResourceProviderFactory{ 3205 "aws": testProviderFuncFixed(p), 3206 }, 3207 Variables: map[string]interface{}{ 3208 "count": "1", 3209 }, 3210 }) 3211 3212 if _, err := ctx.Plan(); err != nil { 3213 t.Fatalf("err: %s", err) 3214 } 3215 3216 state, err := ctx.Apply() 3217 if err != nil { 3218 t.Fatalf("err: %s", err) 3219 } 3220 3221 if !checked { 3222 t.Fatal("apply never called") 3223 } 3224 3225 t.Logf("Step 2 state: %s", state) 3226 3227 s = state 3228 } 3229 } 3230 3231 func TestContext2Apply_nilDiff(t *testing.T) { 3232 m := testModule(t, "apply-good") 3233 p := testProvider("aws") 3234 p.ApplyFn = testApplyFn 3235 p.DiffFn = testDiffFn 3236 ctx := testContext2(t, &ContextOpts{ 3237 Module: m, 3238 Providers: map[string]ResourceProviderFactory{ 3239 "aws": testProviderFuncFixed(p), 3240 }, 3241 }) 3242 3243 if _, err := ctx.Plan(); err != nil { 3244 t.Fatalf("err: %s", err) 3245 } 3246 3247 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3248 return nil, nil 3249 } 3250 3251 if _, err := ctx.Apply(); err == nil { 3252 t.Fatal("should error") 3253 } 3254 } 3255 3256 func TestContext2Apply_outputDependsOn(t *testing.T) { 3257 m := testModule(t, "apply-output-depends-on") 3258 p := testProvider("aws") 3259 p.DiffFn = testDiffFn 3260 3261 { 3262 // Create a custom apply function that sleeps a bit (to allow parallel 3263 // graph execution) and then returns an error to force a partial state 3264 // return. We then verify the output is NOT there. 3265 p.ApplyFn = func( 3266 info *InstanceInfo, 3267 is *InstanceState, 3268 id *InstanceDiff) (*InstanceState, error) { 3269 3270 // Sleep to allow parallel execution 3271 time.Sleep(50 * time.Millisecond) 3272 3273 // Return error to force partial state 3274 return nil, fmt.Errorf("abcd") 3275 } 3276 3277 ctx := testContext2(t, &ContextOpts{ 3278 Module: m, 3279 Providers: map[string]ResourceProviderFactory{ 3280 "aws": testProviderFuncFixed(p), 3281 }, 3282 }) 3283 3284 if _, err := ctx.Plan(); err != nil { 3285 t.Fatalf("err: %s", err) 3286 } 3287 3288 state, err := ctx.Apply() 3289 if err == nil || !strings.Contains(err.Error(), "abcd") { 3290 t.Fatalf("err: %s", err) 3291 } 3292 3293 checkStateString(t, state, `<no state>`) 3294 } 3295 3296 { 3297 // Create the standard apply function and verify we get the output 3298 p.ApplyFn = testApplyFn 3299 3300 ctx := testContext2(t, &ContextOpts{ 3301 Module: m, 3302 Providers: map[string]ResourceProviderFactory{ 3303 "aws": testProviderFuncFixed(p), 3304 }, 3305 }) 3306 3307 if _, err := ctx.Plan(); err != nil { 3308 t.Fatalf("err: %s", err) 3309 } 3310 3311 state, err := ctx.Apply() 3312 if err != nil { 3313 t.Fatalf("err: %s", err) 3314 } 3315 3316 checkStateString(t, state, ` 3317 aws_instance.foo: 3318 ID = foo 3319 3320 Outputs: 3321 3322 value = result 3323 `) 3324 } 3325 } 3326 3327 func TestContext2Apply_outputOrphan(t *testing.T) { 3328 m := testModule(t, "apply-output-orphan") 3329 p := testProvider("aws") 3330 p.ApplyFn = testApplyFn 3331 p.DiffFn = testDiffFn 3332 3333 state := &State{ 3334 Modules: []*ModuleState{ 3335 &ModuleState{ 3336 Path: rootModulePath, 3337 Outputs: map[string]*OutputState{ 3338 "foo": &OutputState{ 3339 Type: "string", 3340 Sensitive: false, 3341 Value: "bar", 3342 }, 3343 "bar": &OutputState{ 3344 Type: "string", 3345 Sensitive: false, 3346 Value: "baz", 3347 }, 3348 }, 3349 }, 3350 }, 3351 } 3352 3353 ctx := testContext2(t, &ContextOpts{ 3354 Module: m, 3355 Providers: map[string]ResourceProviderFactory{ 3356 "aws": testProviderFuncFixed(p), 3357 }, 3358 State: state, 3359 }) 3360 3361 if _, err := ctx.Plan(); err != nil { 3362 t.Fatalf("err: %s", err) 3363 } 3364 3365 state, err := ctx.Apply() 3366 if err != nil { 3367 t.Fatalf("err: %s", err) 3368 } 3369 3370 actual := strings.TrimSpace(state.String()) 3371 expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) 3372 if actual != expected { 3373 t.Fatalf("bad: \n%s", actual) 3374 } 3375 } 3376 3377 func TestContext2Apply_outputOrphanModule(t *testing.T) { 3378 m := testModule(t, "apply-output-orphan-module") 3379 p := testProvider("aws") 3380 p.ApplyFn = testApplyFn 3381 p.DiffFn = testDiffFn 3382 3383 state := &State{ 3384 Modules: []*ModuleState{ 3385 &ModuleState{ 3386 Path: []string{"root", "child"}, 3387 Outputs: map[string]*OutputState{ 3388 "foo": &OutputState{ 3389 Type: "string", 3390 Value: "bar", 3391 }, 3392 "bar": &OutputState{ 3393 Type: "string", 3394 Value: "baz", 3395 }, 3396 }, 3397 }, 3398 }, 3399 } 3400 3401 ctx := testContext2(t, &ContextOpts{ 3402 Module: m, 3403 Providers: map[string]ResourceProviderFactory{ 3404 "aws": testProviderFuncFixed(p), 3405 }, 3406 State: state, 3407 }) 3408 3409 if _, err := ctx.Plan(); err != nil { 3410 t.Fatalf("err: %s", err) 3411 } 3412 3413 state, err := ctx.Apply() 3414 if err != nil { 3415 t.Fatalf("err: %s", err) 3416 } 3417 3418 actual := strings.TrimSpace(state.String()) 3419 expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr) 3420 if actual != expected { 3421 t.Fatalf("bad: \n%s", actual) 3422 } 3423 } 3424 3425 func TestContext2Apply_providerComputedVar(t *testing.T) { 3426 m := testModule(t, "apply-provider-computed") 3427 p := testProvider("aws") 3428 p.ApplyFn = testApplyFn 3429 p.DiffFn = testDiffFn 3430 3431 pTest := testProvider("test") 3432 pTest.ApplyFn = testApplyFn 3433 pTest.DiffFn = testDiffFn 3434 3435 ctx := testContext2(t, &ContextOpts{ 3436 Module: m, 3437 Providers: map[string]ResourceProviderFactory{ 3438 "aws": testProviderFuncFixed(p), 3439 "test": testProviderFuncFixed(pTest), 3440 }, 3441 }) 3442 3443 p.ConfigureFn = func(c *ResourceConfig) error { 3444 if c.IsComputed("value") { 3445 return fmt.Errorf("value is computed") 3446 } 3447 3448 v, ok := c.Get("value") 3449 if !ok { 3450 return fmt.Errorf("value is not found") 3451 } 3452 if v != "yes" { 3453 return fmt.Errorf("value is not 'yes': %v", v) 3454 } 3455 3456 return nil 3457 } 3458 3459 if _, err := ctx.Plan(); err != nil { 3460 t.Fatalf("err: %s", err) 3461 } 3462 3463 if _, err := ctx.Apply(); err != nil { 3464 t.Fatalf("err: %s", err) 3465 } 3466 } 3467 3468 func TestContext2Apply_providerConfigureDisabled(t *testing.T) { 3469 m := testModule(t, "apply-provider-configure-disabled") 3470 p := testProvider("aws") 3471 p.ApplyFn = testApplyFn 3472 p.DiffFn = testDiffFn 3473 3474 called := false 3475 p.ConfigureFn = func(c *ResourceConfig) error { 3476 called = true 3477 3478 if _, ok := c.Get("value"); !ok { 3479 return fmt.Errorf("value is not found") 3480 } 3481 3482 return nil 3483 } 3484 3485 ctx := testContext2(t, &ContextOpts{ 3486 Module: m, 3487 Providers: map[string]ResourceProviderFactory{ 3488 "aws": testProviderFuncFixed(p), 3489 }, 3490 }) 3491 3492 if _, err := ctx.Plan(); err != nil { 3493 t.Fatalf("err: %s", err) 3494 } 3495 3496 if _, err := ctx.Apply(); err != nil { 3497 t.Fatalf("err: %s", err) 3498 } 3499 3500 if !called { 3501 t.Fatal("configure never called") 3502 } 3503 } 3504 3505 func TestContext2Apply_provisionerModule(t *testing.T) { 3506 m := testModule(t, "apply-provisioner-module") 3507 p := testProvider("aws") 3508 pr := testProvisioner() 3509 p.ApplyFn = testApplyFn 3510 p.DiffFn = testDiffFn 3511 ctx := testContext2(t, &ContextOpts{ 3512 Module: m, 3513 Providers: map[string]ResourceProviderFactory{ 3514 "aws": testProviderFuncFixed(p), 3515 }, 3516 Provisioners: map[string]ResourceProvisionerFactory{ 3517 "shell": testProvisionerFuncFixed(pr), 3518 }, 3519 }) 3520 3521 if _, err := ctx.Plan(); err != nil { 3522 t.Fatalf("err: %s", err) 3523 } 3524 3525 state, err := ctx.Apply() 3526 if err != nil { 3527 t.Fatalf("err: %s", err) 3528 } 3529 3530 actual := strings.TrimSpace(state.String()) 3531 expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr) 3532 if actual != expected { 3533 t.Fatalf("bad: \n%s", actual) 3534 } 3535 3536 // Verify apply was invoked 3537 if !pr.ApplyCalled { 3538 t.Fatalf("provisioner not invoked") 3539 } 3540 } 3541 3542 func TestContext2Apply_Provisioner_compute(t *testing.T) { 3543 m := testModule(t, "apply-provisioner-compute") 3544 p := testProvider("aws") 3545 pr := testProvisioner() 3546 p.ApplyFn = testApplyFn 3547 p.DiffFn = testDiffFn 3548 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3549 val, ok := c.Config["foo"] 3550 if !ok || val != "computed_dynamical" { 3551 t.Fatalf("bad value for foo: %v %#v", val, c) 3552 } 3553 3554 return nil 3555 } 3556 ctx := testContext2(t, &ContextOpts{ 3557 Module: m, 3558 Providers: map[string]ResourceProviderFactory{ 3559 "aws": testProviderFuncFixed(p), 3560 }, 3561 Provisioners: map[string]ResourceProvisionerFactory{ 3562 "shell": testProvisionerFuncFixed(pr), 3563 }, 3564 Variables: map[string]interface{}{ 3565 "value": "1", 3566 }, 3567 }) 3568 3569 if _, err := ctx.Plan(); err != nil { 3570 t.Fatalf("err: %s", err) 3571 } 3572 3573 state, err := ctx.Apply() 3574 if err != nil { 3575 t.Fatalf("err: %s", err) 3576 } 3577 3578 actual := strings.TrimSpace(state.String()) 3579 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 3580 if actual != expected { 3581 t.Fatalf("bad: \n%s", actual) 3582 } 3583 3584 // Verify apply was invoked 3585 if !pr.ApplyCalled { 3586 t.Fatalf("provisioner not invoked") 3587 } 3588 } 3589 3590 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 3591 m := testModule(t, "apply-provisioner-fail-create") 3592 p := testProvider("aws") 3593 pr := testProvisioner() 3594 p.DiffFn = testDiffFn 3595 3596 p.ApplyFn = func( 3597 info *InstanceInfo, 3598 is *InstanceState, 3599 id *InstanceDiff) (*InstanceState, error) { 3600 is.ID = "foo" 3601 return is, fmt.Errorf("error") 3602 } 3603 3604 ctx := testContext2(t, &ContextOpts{ 3605 Module: m, 3606 Providers: map[string]ResourceProviderFactory{ 3607 "aws": testProviderFuncFixed(p), 3608 }, 3609 Provisioners: map[string]ResourceProvisionerFactory{ 3610 "shell": testProvisionerFuncFixed(pr), 3611 }, 3612 }) 3613 3614 if _, err := ctx.Plan(); err != nil { 3615 t.Fatalf("err: %s", err) 3616 } 3617 3618 state, err := ctx.Apply() 3619 if err == nil { 3620 t.Fatal("should error") 3621 } 3622 3623 actual := strings.TrimSpace(state.String()) 3624 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 3625 if actual != expected { 3626 t.Fatalf("bad: \n%s", actual) 3627 } 3628 } 3629 3630 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 3631 m := testModule(t, "apply-provisioner-fail-create") 3632 p := testProvider("aws") 3633 pr := testProvisioner() 3634 p.DiffFn = testDiffFn 3635 3636 p.ApplyFn = func( 3637 info *InstanceInfo, 3638 is *InstanceState, 3639 id *InstanceDiff) (*InstanceState, error) { 3640 return nil, fmt.Errorf("error") 3641 } 3642 3643 ctx := testContext2(t, &ContextOpts{ 3644 Module: m, 3645 Providers: map[string]ResourceProviderFactory{ 3646 "aws": testProviderFuncFixed(p), 3647 }, 3648 Provisioners: map[string]ResourceProvisionerFactory{ 3649 "shell": testProvisionerFuncFixed(pr), 3650 }, 3651 }) 3652 3653 if _, err := ctx.Plan(); err != nil { 3654 t.Fatalf("err: %s", err) 3655 } 3656 3657 state, err := ctx.Apply() 3658 if err == nil { 3659 t.Fatal("should error") 3660 } 3661 3662 actual := strings.TrimSpace(state.String()) 3663 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 3664 if actual != expected { 3665 t.Fatalf("bad: \n%s", actual) 3666 } 3667 } 3668 3669 func TestContext2Apply_provisionerFail(t *testing.T) { 3670 m := testModule(t, "apply-provisioner-fail") 3671 p := testProvider("aws") 3672 pr := testProvisioner() 3673 p.ApplyFn = testApplyFn 3674 p.DiffFn = testDiffFn 3675 3676 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 3677 return fmt.Errorf("EXPLOSION") 3678 } 3679 3680 ctx := testContext2(t, &ContextOpts{ 3681 Module: m, 3682 Providers: map[string]ResourceProviderFactory{ 3683 "aws": testProviderFuncFixed(p), 3684 }, 3685 Provisioners: map[string]ResourceProvisionerFactory{ 3686 "shell": testProvisionerFuncFixed(pr), 3687 }, 3688 Variables: map[string]interface{}{ 3689 "value": "1", 3690 }, 3691 }) 3692 3693 if _, err := ctx.Plan(); err != nil { 3694 t.Fatalf("err: %s", err) 3695 } 3696 3697 state, err := ctx.Apply() 3698 if err == nil { 3699 t.Fatal("should error") 3700 } 3701 3702 actual := strings.TrimSpace(state.String()) 3703 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 3704 if actual != expected { 3705 t.Fatalf("bad: \n%s", actual) 3706 } 3707 } 3708 3709 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 3710 m := testModule(t, "apply-provisioner-fail-create-before") 3711 p := testProvider("aws") 3712 pr := testProvisioner() 3713 p.ApplyFn = testApplyFn 3714 p.DiffFn = testDiffFn 3715 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 3716 return fmt.Errorf("EXPLOSION") 3717 } 3718 3719 state := &State{ 3720 Modules: []*ModuleState{ 3721 &ModuleState{ 3722 Path: rootModulePath, 3723 Resources: map[string]*ResourceState{ 3724 "aws_instance.bar": &ResourceState{ 3725 Type: "aws_instance", 3726 Primary: &InstanceState{ 3727 ID: "bar", 3728 Attributes: map[string]string{ 3729 "require_new": "abc", 3730 }, 3731 }, 3732 }, 3733 }, 3734 }, 3735 }, 3736 } 3737 ctx := testContext2(t, &ContextOpts{ 3738 Module: m, 3739 Providers: map[string]ResourceProviderFactory{ 3740 "aws": testProviderFuncFixed(p), 3741 }, 3742 Provisioners: map[string]ResourceProvisionerFactory{ 3743 "shell": testProvisionerFuncFixed(pr), 3744 }, 3745 State: state, 3746 }) 3747 3748 if _, err := ctx.Plan(); err != nil { 3749 t.Fatalf("err: %s", err) 3750 } 3751 3752 state, err := ctx.Apply() 3753 if err == nil { 3754 t.Fatal("should error") 3755 } 3756 3757 actual := strings.TrimSpace(state.String()) 3758 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 3759 if actual != expected { 3760 t.Fatalf("bad: \n%s", actual) 3761 } 3762 } 3763 3764 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 3765 m := testModule(t, "apply-error-create-before") 3766 p := testProvider("aws") 3767 state := &State{ 3768 Modules: []*ModuleState{ 3769 &ModuleState{ 3770 Path: rootModulePath, 3771 Resources: map[string]*ResourceState{ 3772 "aws_instance.bar": &ResourceState{ 3773 Type: "aws_instance", 3774 Primary: &InstanceState{ 3775 ID: "bar", 3776 Attributes: map[string]string{ 3777 "require_new": "abc", 3778 }, 3779 }, 3780 }, 3781 }, 3782 }, 3783 }, 3784 } 3785 ctx := testContext2(t, &ContextOpts{ 3786 Module: m, 3787 Providers: map[string]ResourceProviderFactory{ 3788 "aws": testProviderFuncFixed(p), 3789 }, 3790 State: state, 3791 }) 3792 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 3793 return nil, fmt.Errorf("error") 3794 } 3795 p.DiffFn = testDiffFn 3796 3797 if _, err := ctx.Plan(); err != nil { 3798 t.Fatalf("err: %s", err) 3799 } 3800 3801 state, err := ctx.Apply() 3802 if err == nil { 3803 t.Fatal("should have error") 3804 } 3805 3806 actual := strings.TrimSpace(state.String()) 3807 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 3808 if actual != expected { 3809 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 3810 } 3811 } 3812 3813 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 3814 m := testModule(t, "apply-error-create-before") 3815 p := testProvider("aws") 3816 state := &State{ 3817 Modules: []*ModuleState{ 3818 &ModuleState{ 3819 Path: rootModulePath, 3820 Resources: map[string]*ResourceState{ 3821 "aws_instance.bar": &ResourceState{ 3822 Type: "aws_instance", 3823 Primary: &InstanceState{ 3824 ID: "bar", 3825 Attributes: map[string]string{ 3826 "require_new": "abc", 3827 }, 3828 }, 3829 }, 3830 }, 3831 }, 3832 }, 3833 } 3834 ctx := testContext2(t, &ContextOpts{ 3835 Module: m, 3836 Providers: map[string]ResourceProviderFactory{ 3837 "aws": testProviderFuncFixed(p), 3838 }, 3839 State: state, 3840 }) 3841 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 3842 // Fail the destroy! 3843 if id.Destroy { 3844 return is, fmt.Errorf("error") 3845 } 3846 3847 // Create should work 3848 is = &InstanceState{ 3849 ID: "foo", 3850 } 3851 return is, nil 3852 } 3853 p.DiffFn = testDiffFn 3854 3855 if _, err := ctx.Plan(); err != nil { 3856 t.Fatalf("err: %s", err) 3857 } 3858 3859 state, err := ctx.Apply() 3860 if err == nil { 3861 t.Fatal("should have error") 3862 } 3863 3864 actual := strings.TrimSpace(state.String()) 3865 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 3866 if actual != expected { 3867 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 3868 } 3869 } 3870 3871 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 3872 m := testModule(t, "apply-multi-depose-create-before-destroy") 3873 p := testProvider("aws") 3874 p.DiffFn = testDiffFn 3875 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 3876 state := &State{ 3877 Modules: []*ModuleState{ 3878 &ModuleState{ 3879 Path: rootModulePath, 3880 Resources: map[string]*ResourceState{ 3881 "aws_instance.web": &ResourceState{ 3882 Type: "aws_instance", 3883 Primary: &InstanceState{ID: "foo"}, 3884 }, 3885 }, 3886 }, 3887 }, 3888 } 3889 3890 ctx := testContext2(t, &ContextOpts{ 3891 Module: m, 3892 Providers: ps, 3893 State: state, 3894 }) 3895 createdInstanceId := "bar" 3896 // Create works 3897 createFunc := func(is *InstanceState) (*InstanceState, error) { 3898 return &InstanceState{ID: createdInstanceId}, nil 3899 } 3900 // Destroy starts broken 3901 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 3902 return is, fmt.Errorf("destroy failed") 3903 } 3904 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 3905 if id.Destroy { 3906 return destroyFunc(is) 3907 } else { 3908 return createFunc(is) 3909 } 3910 } 3911 3912 if _, err := ctx.Plan(); err != nil { 3913 t.Fatalf("err: %s", err) 3914 } 3915 3916 // Destroy is broken, so even though CBD successfully replaces the instance, 3917 // we'll have to save the Deposed instance to destroy later 3918 state, err := ctx.Apply() 3919 if err == nil { 3920 t.Fatal("should have error") 3921 } 3922 3923 checkStateString(t, state, ` 3924 aws_instance.web: (1 deposed) 3925 ID = bar 3926 Deposed ID 1 = foo 3927 `) 3928 3929 createdInstanceId = "baz" 3930 ctx = testContext2(t, &ContextOpts{ 3931 Module: m, 3932 Providers: ps, 3933 State: state, 3934 }) 3935 3936 if _, err := ctx.Plan(); err != nil { 3937 t.Fatalf("err: %s", err) 3938 } 3939 3940 // We're replacing the primary instance once again. Destroy is _still_ 3941 // broken, so the Deposed list gets longer 3942 state, err = ctx.Apply() 3943 if err == nil { 3944 t.Fatal("should have error") 3945 } 3946 3947 checkStateString(t, state, ` 3948 aws_instance.web: (2 deposed) 3949 ID = baz 3950 Deposed ID 1 = foo 3951 Deposed ID 2 = bar 3952 `) 3953 3954 // Destroy partially fixed! 3955 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 3956 if is.ID == "foo" || is.ID == "baz" { 3957 return nil, nil 3958 } else { 3959 return is, fmt.Errorf("destroy partially failed") 3960 } 3961 } 3962 3963 createdInstanceId = "qux" 3964 if _, err := ctx.Plan(); err != nil { 3965 t.Fatalf("err: %s", err) 3966 } 3967 state, err = ctx.Apply() 3968 // Expect error because 1/2 of Deposed destroys failed 3969 if err == nil { 3970 t.Fatal("should have error") 3971 } 3972 3973 // foo and baz are now gone, bar sticks around 3974 checkStateString(t, state, ` 3975 aws_instance.web: (1 deposed) 3976 ID = qux 3977 Deposed ID 1 = bar 3978 `) 3979 3980 // Destroy working fully! 3981 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 3982 return nil, nil 3983 } 3984 3985 createdInstanceId = "quux" 3986 if _, err := ctx.Plan(); err != nil { 3987 t.Fatalf("err: %s", err) 3988 } 3989 state, err = ctx.Apply() 3990 if err != nil { 3991 t.Fatal("should not have error:", err) 3992 } 3993 3994 // And finally the state is clean 3995 checkStateString(t, state, ` 3996 aws_instance.web: 3997 ID = quux 3998 `) 3999 } 4000 4001 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 4002 m := testModule(t, "apply-provisioner-resource-ref") 4003 p := testProvider("aws") 4004 pr := testProvisioner() 4005 p.ApplyFn = testApplyFn 4006 p.DiffFn = testDiffFn 4007 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4008 val, ok := c.Config["foo"] 4009 if !ok || val != "2" { 4010 t.Fatalf("bad value for foo: %v %#v", val, c) 4011 } 4012 4013 return nil 4014 } 4015 4016 ctx := testContext2(t, &ContextOpts{ 4017 Module: m, 4018 Providers: map[string]ResourceProviderFactory{ 4019 "aws": testProviderFuncFixed(p), 4020 }, 4021 Provisioners: map[string]ResourceProvisionerFactory{ 4022 "shell": testProvisionerFuncFixed(pr), 4023 }, 4024 }) 4025 4026 if _, err := ctx.Plan(); err != nil { 4027 t.Fatalf("err: %s", err) 4028 } 4029 4030 state, err := ctx.Apply() 4031 if err != nil { 4032 t.Fatalf("err: %s", err) 4033 } 4034 4035 actual := strings.TrimSpace(state.String()) 4036 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 4037 if actual != expected { 4038 t.Fatalf("bad: \n%s", actual) 4039 } 4040 4041 // Verify apply was invoked 4042 if !pr.ApplyCalled { 4043 t.Fatalf("provisioner not invoked") 4044 } 4045 } 4046 4047 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 4048 m := testModule(t, "apply-provisioner-self-ref") 4049 p := testProvider("aws") 4050 pr := testProvisioner() 4051 p.ApplyFn = testApplyFn 4052 p.DiffFn = testDiffFn 4053 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4054 val, ok := c.Config["command"] 4055 if !ok || val != "bar" { 4056 t.Fatalf("bad value for command: %v %#v", val, c) 4057 } 4058 4059 return nil 4060 } 4061 4062 ctx := testContext2(t, &ContextOpts{ 4063 Module: m, 4064 Providers: map[string]ResourceProviderFactory{ 4065 "aws": testProviderFuncFixed(p), 4066 }, 4067 Provisioners: map[string]ResourceProvisionerFactory{ 4068 "shell": testProvisionerFuncFixed(pr), 4069 }, 4070 }) 4071 4072 if _, err := ctx.Plan(); err != nil { 4073 t.Fatalf("err: %s", err) 4074 } 4075 4076 state, err := ctx.Apply() 4077 if err != nil { 4078 t.Fatalf("err: %s", err) 4079 } 4080 4081 actual := strings.TrimSpace(state.String()) 4082 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 4083 if actual != expected { 4084 t.Fatalf("bad: \n%s", actual) 4085 } 4086 4087 // Verify apply was invoked 4088 if !pr.ApplyCalled { 4089 t.Fatalf("provisioner not invoked") 4090 } 4091 } 4092 4093 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 4094 var lock sync.Mutex 4095 commands := make([]string, 0, 5) 4096 4097 m := testModule(t, "apply-provisioner-multi-self-ref") 4098 p := testProvider("aws") 4099 pr := testProvisioner() 4100 p.ApplyFn = testApplyFn 4101 p.DiffFn = testDiffFn 4102 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4103 lock.Lock() 4104 defer lock.Unlock() 4105 4106 val, ok := c.Config["command"] 4107 if !ok { 4108 t.Fatalf("bad value for command: %v %#v", val, c) 4109 } 4110 4111 commands = append(commands, val.(string)) 4112 return nil 4113 } 4114 4115 ctx := testContext2(t, &ContextOpts{ 4116 Module: m, 4117 Providers: map[string]ResourceProviderFactory{ 4118 "aws": testProviderFuncFixed(p), 4119 }, 4120 Provisioners: map[string]ResourceProvisionerFactory{ 4121 "shell": testProvisionerFuncFixed(pr), 4122 }, 4123 }) 4124 4125 if _, err := ctx.Plan(); err != nil { 4126 t.Fatalf("err: %s", err) 4127 } 4128 4129 state, err := ctx.Apply() 4130 if err != nil { 4131 t.Fatalf("err: %s", err) 4132 } 4133 4134 actual := strings.TrimSpace(state.String()) 4135 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 4136 if actual != expected { 4137 t.Fatalf("bad: \n%s", actual) 4138 } 4139 4140 // Verify apply was invoked 4141 if !pr.ApplyCalled { 4142 t.Fatalf("provisioner not invoked") 4143 } 4144 4145 // Verify our result 4146 sort.Strings(commands) 4147 expectedCommands := []string{"number 0", "number 1", "number 2"} 4148 if !reflect.DeepEqual(commands, expectedCommands) { 4149 t.Fatalf("bad: %#v", commands) 4150 } 4151 } 4152 4153 func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) { 4154 var lock sync.Mutex 4155 order := make([]string, 0, 5) 4156 4157 m := testModule(t, "apply-provisioner-multi-self-ref-single") 4158 p := testProvider("aws") 4159 pr := testProvisioner() 4160 p.ApplyFn = testApplyFn 4161 p.DiffFn = testDiffFn 4162 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4163 lock.Lock() 4164 defer lock.Unlock() 4165 4166 val, ok := c.Config["order"] 4167 if !ok { 4168 t.Fatalf("bad value for order: %v %#v", val, c) 4169 } 4170 4171 order = append(order, val.(string)) 4172 return nil 4173 } 4174 4175 ctx := testContext2(t, &ContextOpts{ 4176 Module: m, 4177 Providers: map[string]ResourceProviderFactory{ 4178 "aws": testProviderFuncFixed(p), 4179 }, 4180 Provisioners: map[string]ResourceProvisionerFactory{ 4181 "shell": testProvisionerFuncFixed(pr), 4182 }, 4183 }) 4184 4185 if _, err := ctx.Plan(); err != nil { 4186 t.Fatalf("err: %s", err) 4187 } 4188 4189 state, err := ctx.Apply() 4190 if err != nil { 4191 t.Fatalf("err: %s", err) 4192 } 4193 4194 actual := strings.TrimSpace(state.String()) 4195 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr) 4196 if actual != expected { 4197 t.Fatalf("bad: \n%s", actual) 4198 } 4199 4200 // Verify apply was invoked 4201 if !pr.ApplyCalled { 4202 t.Fatalf("provisioner not invoked") 4203 } 4204 4205 // Verify our result 4206 sort.Strings(order) 4207 expectedOrder := []string{"0", "1", "2"} 4208 if !reflect.DeepEqual(order, expectedOrder) { 4209 t.Fatalf("bad: %#v", order) 4210 } 4211 } 4212 4213 func TestContext2Apply_provisionerMultiSelfRefCount(t *testing.T) { 4214 var lock sync.Mutex 4215 commands := make([]string, 0, 5) 4216 4217 m := testModule(t, "apply-provisioner-multi-self-ref-count") 4218 p := testProvider("aws") 4219 pr := testProvisioner() 4220 p.ApplyFn = testApplyFn 4221 p.DiffFn = testDiffFn 4222 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4223 lock.Lock() 4224 defer lock.Unlock() 4225 4226 val, ok := c.Config["command"] 4227 if !ok { 4228 t.Fatalf("bad value for command: %v %#v", val, c) 4229 } 4230 4231 commands = append(commands, val.(string)) 4232 return nil 4233 } 4234 4235 ctx := testContext2(t, &ContextOpts{ 4236 Module: m, 4237 Providers: map[string]ResourceProviderFactory{ 4238 "aws": testProviderFuncFixed(p), 4239 }, 4240 Provisioners: map[string]ResourceProvisionerFactory{ 4241 "shell": testProvisionerFuncFixed(pr), 4242 }, 4243 }) 4244 4245 if _, err := ctx.Plan(); err != nil { 4246 t.Fatalf("err: %s", err) 4247 } 4248 4249 if _, err := ctx.Apply(); err != nil { 4250 t.Fatalf("err: %s", err) 4251 } 4252 4253 // Verify apply was invoked 4254 if !pr.ApplyCalled { 4255 t.Fatalf("provisioner not invoked") 4256 } 4257 4258 // Verify our result 4259 sort.Strings(commands) 4260 expectedCommands := []string{"3", "3", "3"} 4261 if !reflect.DeepEqual(commands, expectedCommands) { 4262 t.Fatalf("bad: %#v", commands) 4263 } 4264 } 4265 4266 func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) { 4267 m := testModule(t, "apply-provisioner-explicit-self-ref") 4268 p := testProvider("aws") 4269 pr := testProvisioner() 4270 p.ApplyFn = testApplyFn 4271 p.DiffFn = testDiffFn 4272 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4273 val, ok := c.Config["command"] 4274 if !ok || val != "bar" { 4275 t.Fatalf("bad value for command: %v %#v", val, c) 4276 } 4277 4278 return nil 4279 } 4280 4281 var state *State 4282 { 4283 ctx := testContext2(t, &ContextOpts{ 4284 Module: m, 4285 Providers: map[string]ResourceProviderFactory{ 4286 "aws": testProviderFuncFixed(p), 4287 }, 4288 Provisioners: map[string]ResourceProvisionerFactory{ 4289 "shell": testProvisionerFuncFixed(pr), 4290 }, 4291 }) 4292 4293 _, err := ctx.Plan() 4294 if err != nil { 4295 t.Fatalf("err: %s", err) 4296 } 4297 4298 state, err = ctx.Apply() 4299 if err != nil { 4300 t.Fatalf("err: %s", err) 4301 } 4302 4303 // Verify apply was invoked 4304 if !pr.ApplyCalled { 4305 t.Fatalf("provisioner not invoked") 4306 } 4307 } 4308 4309 { 4310 ctx := testContext2(t, &ContextOpts{ 4311 Module: m, 4312 Destroy: true, 4313 State: state, 4314 Providers: map[string]ResourceProviderFactory{ 4315 "aws": testProviderFuncFixed(p), 4316 }, 4317 Provisioners: map[string]ResourceProvisionerFactory{ 4318 "shell": testProvisionerFuncFixed(pr), 4319 }, 4320 }) 4321 4322 _, err := ctx.Plan() 4323 if err != nil { 4324 t.Fatalf("err: %s", err) 4325 } 4326 4327 state, err = ctx.Apply() 4328 if err != nil { 4329 t.Fatalf("err: %s", err) 4330 } 4331 4332 checkStateString(t, state, `<no state>`) 4333 } 4334 } 4335 4336 // Provisioner should NOT run on a diff, only create 4337 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 4338 m := testModule(t, "apply-provisioner-diff") 4339 p := testProvider("aws") 4340 pr := testProvisioner() 4341 p.ApplyFn = testApplyFn 4342 p.DiffFn = testDiffFn 4343 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4344 return nil 4345 } 4346 ctx := testContext2(t, &ContextOpts{ 4347 Module: m, 4348 Providers: map[string]ResourceProviderFactory{ 4349 "aws": testProviderFuncFixed(p), 4350 }, 4351 Provisioners: map[string]ResourceProvisionerFactory{ 4352 "shell": testProvisionerFuncFixed(pr), 4353 }, 4354 }) 4355 4356 if _, err := ctx.Plan(); err != nil { 4357 t.Fatalf("err: %s", err) 4358 } 4359 4360 state, err := ctx.Apply() 4361 if err != nil { 4362 t.Fatalf("err: %s", err) 4363 } 4364 4365 actual := strings.TrimSpace(state.String()) 4366 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 4367 if actual != expected { 4368 t.Fatalf("bad: \n%s", actual) 4369 } 4370 4371 // Verify apply was invoked 4372 if !pr.ApplyCalled { 4373 t.Fatalf("provisioner not invoked") 4374 } 4375 pr.ApplyCalled = false 4376 4377 // Change the state to force a diff 4378 mod := state.RootModule() 4379 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 4380 4381 // Re-create context with state 4382 ctx = testContext2(t, &ContextOpts{ 4383 Module: m, 4384 Providers: map[string]ResourceProviderFactory{ 4385 "aws": testProviderFuncFixed(p), 4386 }, 4387 Provisioners: map[string]ResourceProvisionerFactory{ 4388 "shell": testProvisionerFuncFixed(pr), 4389 }, 4390 State: state, 4391 }) 4392 4393 if _, err := ctx.Plan(); err != nil { 4394 t.Fatalf("err: %s", err) 4395 } 4396 4397 state2, err := ctx.Apply() 4398 if err != nil { 4399 t.Fatalf("err: %s", err) 4400 } 4401 4402 actual = strings.TrimSpace(state2.String()) 4403 if actual != expected { 4404 t.Fatalf("bad: \n%s", actual) 4405 } 4406 4407 // Verify apply was NOT invoked 4408 if pr.ApplyCalled { 4409 t.Fatalf("provisioner invoked") 4410 } 4411 } 4412 4413 func TestContext2Apply_outputDiffVars(t *testing.T) { 4414 m := testModule(t, "apply-good") 4415 p := testProvider("aws") 4416 s := &State{ 4417 Modules: []*ModuleState{ 4418 &ModuleState{ 4419 Path: rootModulePath, 4420 Resources: map[string]*ResourceState{ 4421 "aws_instance.baz": &ResourceState{ 4422 Type: "aws_instance", 4423 Primary: &InstanceState{ 4424 ID: "bar", 4425 }, 4426 }, 4427 }, 4428 }, 4429 }, 4430 } 4431 ctx := testContext2(t, &ContextOpts{ 4432 Module: m, 4433 Providers: map[string]ResourceProviderFactory{ 4434 "aws": testProviderFuncFixed(p), 4435 }, 4436 State: s, 4437 }) 4438 4439 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4440 for k, ad := range d.Attributes { 4441 if ad.NewComputed { 4442 return nil, fmt.Errorf("%s: computed", k) 4443 } 4444 } 4445 4446 result := s.MergeDiff(d) 4447 result.ID = "foo" 4448 return result, nil 4449 } 4450 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4451 return &InstanceDiff{ 4452 Attributes: map[string]*ResourceAttrDiff{ 4453 "foo": &ResourceAttrDiff{ 4454 NewComputed: true, 4455 Type: DiffAttrOutput, 4456 }, 4457 "bar": &ResourceAttrDiff{ 4458 New: "baz", 4459 }, 4460 }, 4461 }, nil 4462 } 4463 4464 if _, err := ctx.Plan(); err != nil { 4465 t.Fatalf("err: %s", err) 4466 } 4467 if _, err := ctx.Apply(); err != nil { 4468 t.Fatalf("err: %s", err) 4469 } 4470 } 4471 4472 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 4473 m := testModule(t, "apply-provisioner-conninfo") 4474 p := testProvider("aws") 4475 pr := testProvisioner() 4476 4477 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4478 if s.Ephemeral.ConnInfo == nil { 4479 t.Fatalf("ConnInfo not initialized") 4480 } 4481 4482 result, _ := testApplyFn(info, s, d) 4483 result.Ephemeral.ConnInfo = map[string]string{ 4484 "type": "ssh", 4485 "host": "127.0.0.1", 4486 "port": "22", 4487 } 4488 return result, nil 4489 } 4490 p.DiffFn = testDiffFn 4491 4492 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4493 conn := rs.Ephemeral.ConnInfo 4494 if conn["type"] != "telnet" { 4495 t.Fatalf("Bad: %#v", conn) 4496 } 4497 if conn["host"] != "127.0.0.1" { 4498 t.Fatalf("Bad: %#v", conn) 4499 } 4500 if conn["port"] != "2222" { 4501 t.Fatalf("Bad: %#v", conn) 4502 } 4503 if conn["user"] != "superuser" { 4504 t.Fatalf("Bad: %#v", conn) 4505 } 4506 if conn["pass"] != "test" { 4507 t.Fatalf("Bad: %#v", conn) 4508 } 4509 4510 return nil 4511 } 4512 4513 ctx := testContext2(t, &ContextOpts{ 4514 Module: m, 4515 Providers: map[string]ResourceProviderFactory{ 4516 "aws": testProviderFuncFixed(p), 4517 }, 4518 Provisioners: map[string]ResourceProvisionerFactory{ 4519 "shell": testProvisionerFuncFixed(pr), 4520 }, 4521 Variables: map[string]interface{}{ 4522 "value": "1", 4523 "pass": "test", 4524 }, 4525 }) 4526 4527 if _, err := ctx.Plan(); err != nil { 4528 t.Fatalf("err: %s", err) 4529 } 4530 4531 state, err := ctx.Apply() 4532 if err != nil { 4533 t.Fatalf("err: %s", err) 4534 } 4535 4536 actual := strings.TrimSpace(state.String()) 4537 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 4538 if actual != expected { 4539 t.Fatalf("bad: \n%s", actual) 4540 } 4541 4542 // Verify apply was invoked 4543 if !pr.ApplyCalled { 4544 t.Fatalf("provisioner not invoked") 4545 } 4546 } 4547 4548 func TestContext2Apply_destroyX(t *testing.T) { 4549 m := testModule(t, "apply-destroy") 4550 h := new(HookRecordApplyOrder) 4551 p := testProvider("aws") 4552 p.ApplyFn = testApplyFn 4553 p.DiffFn = testDiffFn 4554 ctx := testContext2(t, &ContextOpts{ 4555 Module: m, 4556 Hooks: []Hook{h}, 4557 Providers: map[string]ResourceProviderFactory{ 4558 "aws": testProviderFuncFixed(p), 4559 }, 4560 }) 4561 4562 // First plan and apply a create operation 4563 if _, err := ctx.Plan(); err != nil { 4564 t.Fatalf("err: %s", err) 4565 } 4566 4567 state, err := ctx.Apply() 4568 if err != nil { 4569 t.Fatalf("err: %s", err) 4570 } 4571 4572 // Next, plan and apply a destroy operation 4573 h.Active = true 4574 ctx = testContext2(t, &ContextOpts{ 4575 Destroy: true, 4576 State: state, 4577 Module: m, 4578 Hooks: []Hook{h}, 4579 Providers: map[string]ResourceProviderFactory{ 4580 "aws": testProviderFuncFixed(p), 4581 }, 4582 }) 4583 4584 if _, err := ctx.Plan(); err != nil { 4585 t.Fatalf("err: %s", err) 4586 } 4587 4588 state, err = ctx.Apply() 4589 if err != nil { 4590 t.Fatalf("err: %s", err) 4591 } 4592 4593 // Test that things were destroyed 4594 actual := strings.TrimSpace(state.String()) 4595 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 4596 if actual != expected { 4597 t.Fatalf("bad: \n%s", actual) 4598 } 4599 4600 // Test that things were destroyed _in the right order_ 4601 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 4602 actual2 := h.IDs 4603 if !reflect.DeepEqual(actual2, expected2) { 4604 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 4605 } 4606 } 4607 4608 func TestContext2Apply_destroyOrder(t *testing.T) { 4609 m := testModule(t, "apply-destroy") 4610 h := new(HookRecordApplyOrder) 4611 p := testProvider("aws") 4612 p.ApplyFn = testApplyFn 4613 p.DiffFn = testDiffFn 4614 ctx := testContext2(t, &ContextOpts{ 4615 Module: m, 4616 Hooks: []Hook{h}, 4617 Providers: map[string]ResourceProviderFactory{ 4618 "aws": testProviderFuncFixed(p), 4619 }, 4620 }) 4621 4622 // First plan and apply a create operation 4623 if _, err := ctx.Plan(); err != nil { 4624 t.Fatalf("err: %s", err) 4625 } 4626 4627 state, err := ctx.Apply() 4628 if err != nil { 4629 t.Fatalf("err: %s", err) 4630 } 4631 4632 t.Logf("State 1: %s", state) 4633 4634 // Next, plan and apply config-less to force a destroy with "apply" 4635 h.Active = true 4636 ctx = testContext2(t, &ContextOpts{ 4637 State: state, 4638 Module: module.NewEmptyTree(), 4639 Hooks: []Hook{h}, 4640 Providers: map[string]ResourceProviderFactory{ 4641 "aws": testProviderFuncFixed(p), 4642 }, 4643 }) 4644 4645 if _, err := ctx.Plan(); err != nil { 4646 t.Fatalf("err: %s", err) 4647 } 4648 4649 state, err = ctx.Apply() 4650 if err != nil { 4651 t.Fatalf("err: %s", err) 4652 } 4653 4654 // Test that things were destroyed 4655 actual := strings.TrimSpace(state.String()) 4656 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 4657 if actual != expected { 4658 t.Fatalf("bad: \n%s", actual) 4659 } 4660 4661 // Test that things were destroyed _in the right order_ 4662 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 4663 actual2 := h.IDs 4664 if !reflect.DeepEqual(actual2, expected2) { 4665 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 4666 } 4667 } 4668 4669 // https://github.com/hashicorp/terraform/issues/2767 4670 func TestContext2Apply_destroyModulePrefix(t *testing.T) { 4671 m := testModule(t, "apply-destroy-module-resource-prefix") 4672 h := new(MockHook) 4673 p := testProvider("aws") 4674 p.ApplyFn = testApplyFn 4675 p.DiffFn = testDiffFn 4676 ctx := testContext2(t, &ContextOpts{ 4677 Module: m, 4678 Hooks: []Hook{h}, 4679 Providers: map[string]ResourceProviderFactory{ 4680 "aws": testProviderFuncFixed(p), 4681 }, 4682 }) 4683 4684 // First plan and apply a create operation 4685 if _, err := ctx.Plan(); err != nil { 4686 t.Fatalf("err: %s", err) 4687 } 4688 4689 state, err := ctx.Apply() 4690 if err != nil { 4691 t.Fatalf("err: %s", err) 4692 } 4693 4694 // Verify that we got the apply info correct 4695 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 4696 t.Fatalf("bad: %s", v) 4697 } 4698 4699 // Next, plan and apply a destroy operation and reset the hook 4700 h = new(MockHook) 4701 ctx = testContext2(t, &ContextOpts{ 4702 Destroy: true, 4703 State: state, 4704 Module: m, 4705 Hooks: []Hook{h}, 4706 Providers: map[string]ResourceProviderFactory{ 4707 "aws": testProviderFuncFixed(p), 4708 }, 4709 }) 4710 4711 if _, err := ctx.Plan(); err != nil { 4712 t.Fatalf("err: %s", err) 4713 } 4714 4715 state, err = ctx.Apply() 4716 if err != nil { 4717 t.Fatalf("err: %s", err) 4718 } 4719 4720 // Test that things were destroyed 4721 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 4722 t.Fatalf("bad: %s", v) 4723 } 4724 } 4725 4726 func TestContext2Apply_destroyNestedModule(t *testing.T) { 4727 m := testModule(t, "apply-destroy-nested-module") 4728 p := testProvider("aws") 4729 p.ApplyFn = testApplyFn 4730 p.DiffFn = testDiffFn 4731 4732 s := &State{ 4733 Modules: []*ModuleState{ 4734 &ModuleState{ 4735 Path: []string{"root", "child", "subchild"}, 4736 Resources: map[string]*ResourceState{ 4737 "aws_instance.bar": &ResourceState{ 4738 Type: "aws_instance", 4739 Primary: &InstanceState{ 4740 ID: "bar", 4741 }, 4742 }, 4743 }, 4744 }, 4745 }, 4746 } 4747 4748 ctx := testContext2(t, &ContextOpts{ 4749 Module: m, 4750 Providers: map[string]ResourceProviderFactory{ 4751 "aws": testProviderFuncFixed(p), 4752 }, 4753 State: s, 4754 }) 4755 4756 // First plan and apply a create operation 4757 if _, err := ctx.Plan(); err != nil { 4758 t.Fatalf("err: %s", err) 4759 } 4760 4761 state, err := ctx.Apply() 4762 if err != nil { 4763 t.Fatalf("err: %s", err) 4764 } 4765 4766 // Test that things were destroyed 4767 actual := strings.TrimSpace(state.String()) 4768 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 4769 if actual != expected { 4770 t.Fatalf("bad: \n%s", actual) 4771 } 4772 } 4773 4774 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 4775 m := testModule(t, "apply-destroy-deeply-nested-module") 4776 p := testProvider("aws") 4777 p.ApplyFn = testApplyFn 4778 p.DiffFn = testDiffFn 4779 4780 s := &State{ 4781 Modules: []*ModuleState{ 4782 &ModuleState{ 4783 Path: []string{"root", "child", "subchild", "subsubchild"}, 4784 Resources: map[string]*ResourceState{ 4785 "aws_instance.bar": &ResourceState{ 4786 Type: "aws_instance", 4787 Primary: &InstanceState{ 4788 ID: "bar", 4789 }, 4790 }, 4791 }, 4792 }, 4793 }, 4794 } 4795 4796 ctx := testContext2(t, &ContextOpts{ 4797 Module: m, 4798 Providers: map[string]ResourceProviderFactory{ 4799 "aws": testProviderFuncFixed(p), 4800 }, 4801 State: s, 4802 }) 4803 4804 // First plan and apply a create operation 4805 if _, err := ctx.Plan(); err != nil { 4806 t.Fatalf("err: %s", err) 4807 } 4808 4809 state, err := ctx.Apply() 4810 if err != nil { 4811 t.Fatalf("err: %s", err) 4812 } 4813 4814 // Test that things were destroyed 4815 actual := strings.TrimSpace(state.String()) 4816 expected := strings.TrimSpace(` 4817 module.child.subchild.subsubchild: 4818 <no state> 4819 `) 4820 if actual != expected { 4821 t.Fatalf("bad: \n%s", actual) 4822 } 4823 } 4824 4825 // https://github.com/hashicorp/terraform/issues/5440 4826 func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { 4827 m := testModule(t, "apply-destroy-module-with-attrs") 4828 p := testProvider("aws") 4829 p.ApplyFn = testApplyFn 4830 p.DiffFn = testDiffFn 4831 4832 var state *State 4833 var err error 4834 { 4835 ctx := testContext2(t, &ContextOpts{ 4836 Module: m, 4837 Providers: map[string]ResourceProviderFactory{ 4838 "aws": testProviderFuncFixed(p), 4839 }, 4840 }) 4841 4842 // First plan and apply a create operation 4843 if p, err := ctx.Plan(); err != nil { 4844 t.Fatalf("plan err: %s", err) 4845 } else { 4846 t.Logf("Step 1 plan: %s", p) 4847 } 4848 4849 state, err = ctx.Apply() 4850 if err != nil { 4851 t.Fatalf("apply err: %s", err) 4852 } 4853 4854 t.Logf("Step 1 state: %s", state) 4855 } 4856 4857 h := new(HookRecordApplyOrder) 4858 h.Active = true 4859 4860 { 4861 ctx := testContext2(t, &ContextOpts{ 4862 Destroy: true, 4863 Module: m, 4864 State: state, 4865 Hooks: []Hook{h}, 4866 Providers: map[string]ResourceProviderFactory{ 4867 "aws": testProviderFuncFixed(p), 4868 }, 4869 Variables: map[string]interface{}{ 4870 "key_name": "foobarkey", 4871 }, 4872 }) 4873 4874 // First plan and apply a create operation 4875 plan, err := ctx.Plan() 4876 if err != nil { 4877 t.Fatalf("destroy plan err: %s", err) 4878 } 4879 4880 t.Logf("Step 2 plan: %s", plan) 4881 4882 var buf bytes.Buffer 4883 if err := WritePlan(plan, &buf); err != nil { 4884 t.Fatalf("plan write err: %s", err) 4885 } 4886 4887 planFromFile, err := ReadPlan(&buf) 4888 if err != nil { 4889 t.Fatalf("plan read err: %s", err) 4890 } 4891 4892 ctx, err = planFromFile.Context(&ContextOpts{ 4893 Providers: map[string]ResourceProviderFactory{ 4894 "aws": testProviderFuncFixed(p), 4895 }, 4896 }) 4897 if err != nil { 4898 t.Fatalf("err: %s", err) 4899 } 4900 4901 state, err = ctx.Apply() 4902 if err != nil { 4903 t.Fatalf("destroy apply err: %s", err) 4904 } 4905 4906 t.Logf("Step 2 state: %s", state) 4907 } 4908 4909 //Test that things were destroyed 4910 actual := strings.TrimSpace(state.String()) 4911 expected := strings.TrimSpace(` 4912 <no state> 4913 module.child: 4914 <no state> 4915 `) 4916 if actual != expected { 4917 t.Fatalf("expected:\n\n%s\n\nactual:\n\n%s", expected, actual) 4918 } 4919 } 4920 4921 func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { 4922 m := testModule(t, "apply-destroy-mod-var-and-count") 4923 p := testProvider("aws") 4924 p.ApplyFn = testApplyFn 4925 p.DiffFn = testDiffFn 4926 4927 var state *State 4928 var err error 4929 { 4930 ctx := testContext2(t, &ContextOpts{ 4931 Module: m, 4932 Providers: map[string]ResourceProviderFactory{ 4933 "aws": testProviderFuncFixed(p), 4934 }, 4935 }) 4936 4937 // First plan and apply a create operation 4938 if _, err := ctx.Plan(); err != nil { 4939 t.Fatalf("plan err: %s", err) 4940 } 4941 4942 state, err = ctx.Apply() 4943 if err != nil { 4944 t.Fatalf("apply err: %s", err) 4945 } 4946 } 4947 4948 h := new(HookRecordApplyOrder) 4949 h.Active = true 4950 4951 { 4952 ctx := testContext2(t, &ContextOpts{ 4953 Destroy: true, 4954 Module: m, 4955 State: state, 4956 Hooks: []Hook{h}, 4957 Providers: map[string]ResourceProviderFactory{ 4958 "aws": testProviderFuncFixed(p), 4959 }, 4960 }) 4961 4962 // First plan and apply a create operation 4963 plan, err := ctx.Plan() 4964 if err != nil { 4965 t.Fatalf("destroy plan err: %s", err) 4966 } 4967 4968 var buf bytes.Buffer 4969 if err := WritePlan(plan, &buf); err != nil { 4970 t.Fatalf("plan write err: %s", err) 4971 } 4972 4973 planFromFile, err := ReadPlan(&buf) 4974 if err != nil { 4975 t.Fatalf("plan read err: %s", err) 4976 } 4977 4978 ctx, err = planFromFile.Context(&ContextOpts{ 4979 Providers: map[string]ResourceProviderFactory{ 4980 "aws": testProviderFuncFixed(p), 4981 }, 4982 }) 4983 if err != nil { 4984 t.Fatalf("err: %s", err) 4985 } 4986 4987 state, err = ctx.Apply() 4988 if err != nil { 4989 t.Fatalf("destroy apply err: %s", err) 4990 } 4991 } 4992 4993 //Test that things were destroyed 4994 actual := strings.TrimSpace(state.String()) 4995 expected := strings.TrimSpace(` 4996 <no state> 4997 module.child: 4998 <no state> 4999 `) 5000 if actual != expected { 5001 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5002 } 5003 } 5004 5005 func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) { 5006 m := testModule(t, "apply-destroy-mod-var-and-count") 5007 p := testProvider("aws") 5008 p.ApplyFn = testApplyFn 5009 p.DiffFn = testDiffFn 5010 5011 var state *State 5012 var err error 5013 { 5014 ctx := testContext2(t, &ContextOpts{ 5015 Module: m, 5016 Providers: map[string]ResourceProviderFactory{ 5017 "aws": testProviderFuncFixed(p), 5018 }, 5019 }) 5020 5021 // First plan and apply a create operation 5022 if _, err := ctx.Plan(); err != nil { 5023 t.Fatalf("plan err: %s", err) 5024 } 5025 5026 state, err = ctx.Apply() 5027 if err != nil { 5028 t.Fatalf("apply err: %s", err) 5029 } 5030 } 5031 5032 { 5033 ctx := testContext2(t, &ContextOpts{ 5034 Destroy: true, 5035 Module: m, 5036 State: state, 5037 Providers: map[string]ResourceProviderFactory{ 5038 "aws": testProviderFuncFixed(p), 5039 }, 5040 Targets: []string{"module.child"}, 5041 }) 5042 5043 _, err := ctx.Plan() 5044 if err != nil { 5045 t.Fatalf("plan err: %s", err) 5046 } 5047 5048 // Destroy, targeting the module explicitly 5049 state, err = ctx.Apply() 5050 if err != nil { 5051 t.Fatalf("destroy apply err: %s", err) 5052 } 5053 } 5054 5055 //Test that things were destroyed 5056 actual := strings.TrimSpace(state.String()) 5057 expected := strings.TrimSpace(` 5058 <no state> 5059 module.child: 5060 <no state> 5061 `) 5062 if actual != expected { 5063 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5064 } 5065 } 5066 5067 func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { 5068 m := testModule(t, "apply-destroy-mod-var-and-count-nested") 5069 p := testProvider("aws") 5070 p.ApplyFn = testApplyFn 5071 p.DiffFn = testDiffFn 5072 5073 var state *State 5074 var err error 5075 { 5076 ctx := testContext2(t, &ContextOpts{ 5077 Module: m, 5078 Providers: map[string]ResourceProviderFactory{ 5079 "aws": testProviderFuncFixed(p), 5080 }, 5081 }) 5082 5083 // First plan and apply a create operation 5084 if _, err := ctx.Plan(); err != nil { 5085 t.Fatalf("plan err: %s", err) 5086 } 5087 5088 state, err = ctx.Apply() 5089 if err != nil { 5090 t.Fatalf("apply err: %s", err) 5091 } 5092 } 5093 5094 h := new(HookRecordApplyOrder) 5095 h.Active = true 5096 5097 { 5098 ctx := testContext2(t, &ContextOpts{ 5099 Destroy: true, 5100 Module: m, 5101 State: state, 5102 Hooks: []Hook{h}, 5103 Providers: map[string]ResourceProviderFactory{ 5104 "aws": testProviderFuncFixed(p), 5105 }, 5106 }) 5107 5108 // First plan and apply a create operation 5109 plan, err := ctx.Plan() 5110 if err != nil { 5111 t.Fatalf("destroy plan err: %s", err) 5112 } 5113 5114 var buf bytes.Buffer 5115 if err := WritePlan(plan, &buf); err != nil { 5116 t.Fatalf("plan write err: %s", err) 5117 } 5118 5119 planFromFile, err := ReadPlan(&buf) 5120 if err != nil { 5121 t.Fatalf("plan read err: %s", err) 5122 } 5123 5124 ctx, err = planFromFile.Context(&ContextOpts{ 5125 Providers: map[string]ResourceProviderFactory{ 5126 "aws": testProviderFuncFixed(p), 5127 }, 5128 }) 5129 if err != nil { 5130 t.Fatalf("err: %s", err) 5131 } 5132 5133 state, err = ctx.Apply() 5134 if err != nil { 5135 t.Fatalf("destroy apply err: %s", err) 5136 } 5137 } 5138 5139 //Test that things were destroyed 5140 actual := strings.TrimSpace(state.String()) 5141 expected := strings.TrimSpace(` 5142 <no state> 5143 module.child: 5144 <no state> 5145 module.child.child2: 5146 <no state> 5147 `) 5148 if actual != expected { 5149 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5150 } 5151 } 5152 5153 func TestContext2Apply_destroyOutputs(t *testing.T) { 5154 m := testModule(t, "apply-destroy-outputs") 5155 h := new(HookRecordApplyOrder) 5156 p := testProvider("aws") 5157 p.ApplyFn = testApplyFn 5158 p.DiffFn = testDiffFn 5159 ctx := testContext2(t, &ContextOpts{ 5160 Module: m, 5161 Hooks: []Hook{h}, 5162 Providers: map[string]ResourceProviderFactory{ 5163 "aws": testProviderFuncFixed(p), 5164 }, 5165 }) 5166 5167 // First plan and apply a create operation 5168 if _, err := ctx.Plan(); err != nil { 5169 t.Fatalf("err: %s", err) 5170 } 5171 5172 state, err := ctx.Apply() 5173 5174 if err != nil { 5175 t.Fatalf("err: %s", err) 5176 } 5177 5178 // Next, plan and apply a destroy operation 5179 h.Active = true 5180 ctx = testContext2(t, &ContextOpts{ 5181 Destroy: true, 5182 State: state, 5183 Module: m, 5184 Hooks: []Hook{h}, 5185 Providers: map[string]ResourceProviderFactory{ 5186 "aws": testProviderFuncFixed(p), 5187 }, 5188 }) 5189 5190 if _, err := ctx.Plan(); err != nil { 5191 t.Fatalf("err: %s", err) 5192 } 5193 5194 state, err = ctx.Apply() 5195 if err != nil { 5196 t.Fatalf("err: %s", err) 5197 } 5198 5199 mod := state.RootModule() 5200 if len(mod.Resources) > 0 { 5201 t.Fatalf("bad: %#v", mod) 5202 } 5203 } 5204 5205 func TestContext2Apply_destroyOrphan(t *testing.T) { 5206 m := testModule(t, "apply-error") 5207 p := testProvider("aws") 5208 s := &State{ 5209 Modules: []*ModuleState{ 5210 &ModuleState{ 5211 Path: rootModulePath, 5212 Resources: map[string]*ResourceState{ 5213 "aws_instance.baz": &ResourceState{ 5214 Type: "aws_instance", 5215 Primary: &InstanceState{ 5216 ID: "bar", 5217 }, 5218 }, 5219 }, 5220 }, 5221 }, 5222 } 5223 ctx := testContext2(t, &ContextOpts{ 5224 Module: m, 5225 Providers: map[string]ResourceProviderFactory{ 5226 "aws": testProviderFuncFixed(p), 5227 }, 5228 State: s, 5229 }) 5230 5231 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5232 if d.Destroy { 5233 return nil, nil 5234 } 5235 5236 result := s.MergeDiff(d) 5237 result.ID = "foo" 5238 return result, nil 5239 } 5240 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5241 return &InstanceDiff{ 5242 Attributes: map[string]*ResourceAttrDiff{ 5243 "num": &ResourceAttrDiff{ 5244 New: "bar", 5245 }, 5246 }, 5247 }, nil 5248 } 5249 5250 if _, err := ctx.Plan(); err != nil { 5251 t.Fatalf("err: %s", err) 5252 } 5253 5254 state, err := ctx.Apply() 5255 if err != nil { 5256 t.Fatalf("err: %s", err) 5257 } 5258 5259 mod := state.RootModule() 5260 if _, ok := mod.Resources["aws_instance.baz"]; ok { 5261 t.Fatalf("bad: %#v", mod.Resources) 5262 } 5263 } 5264 5265 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 5266 m := testModule(t, "apply-destroy-provisioner") 5267 p := testProvider("aws") 5268 pr := testProvisioner() 5269 p.ApplyFn = testApplyFn 5270 p.DiffFn = testDiffFn 5271 5272 called := false 5273 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5274 called = true 5275 return nil 5276 } 5277 5278 s := &State{ 5279 Modules: []*ModuleState{ 5280 &ModuleState{ 5281 Path: rootModulePath, 5282 Resources: map[string]*ResourceState{ 5283 "aws_instance.foo": &ResourceState{ 5284 Type: "aws_instance", 5285 Primary: &InstanceState{ 5286 ID: "bar", 5287 Attributes: map[string]string{ 5288 "id": "bar", 5289 }, 5290 Tainted: true, 5291 }, 5292 }, 5293 }, 5294 }, 5295 }, 5296 } 5297 5298 ctx := testContext2(t, &ContextOpts{ 5299 Module: m, 5300 Providers: map[string]ResourceProviderFactory{ 5301 "aws": testProviderFuncFixed(p), 5302 }, 5303 Provisioners: map[string]ResourceProvisionerFactory{ 5304 "shell": testProvisionerFuncFixed(pr), 5305 }, 5306 State: s, 5307 Destroy: true, 5308 }) 5309 5310 if _, err := ctx.Plan(); err != nil { 5311 t.Fatalf("err: %s", err) 5312 } 5313 5314 state, err := ctx.Apply() 5315 if err != nil { 5316 t.Fatalf("err: %s", err) 5317 } 5318 5319 if called { 5320 t.Fatal("provisioner should not be called") 5321 } 5322 5323 actual := strings.TrimSpace(state.String()) 5324 expected := strings.TrimSpace("<no state>") 5325 if actual != expected { 5326 t.Fatalf("bad: \n%s", actual) 5327 } 5328 } 5329 5330 func TestContext2Apply_error(t *testing.T) { 5331 errored := false 5332 5333 m := testModule(t, "apply-error") 5334 p := testProvider("aws") 5335 ctx := testContext2(t, &ContextOpts{ 5336 Module: m, 5337 Providers: map[string]ResourceProviderFactory{ 5338 "aws": testProviderFuncFixed(p), 5339 }, 5340 }) 5341 5342 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 5343 if errored { 5344 state := &InstanceState{ 5345 ID: "bar", 5346 } 5347 return state, fmt.Errorf("error") 5348 } 5349 errored = true 5350 5351 return &InstanceState{ 5352 ID: "foo", 5353 Attributes: map[string]string{ 5354 "num": "2", 5355 }, 5356 }, nil 5357 } 5358 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5359 return &InstanceDiff{ 5360 Attributes: map[string]*ResourceAttrDiff{ 5361 "num": &ResourceAttrDiff{ 5362 New: "bar", 5363 }, 5364 }, 5365 }, nil 5366 } 5367 5368 if _, err := ctx.Plan(); err != nil { 5369 t.Fatalf("err: %s", err) 5370 } 5371 5372 state, err := ctx.Apply() 5373 if err == nil { 5374 t.Fatal("should have error") 5375 } 5376 5377 actual := strings.TrimSpace(state.String()) 5378 expected := strings.TrimSpace(testTerraformApplyErrorStr) 5379 if actual != expected { 5380 t.Fatalf("bad: \n%s", actual) 5381 } 5382 } 5383 5384 func TestContext2Apply_errorPartial(t *testing.T) { 5385 errored := false 5386 5387 m := testModule(t, "apply-error") 5388 p := testProvider("aws") 5389 s := &State{ 5390 Modules: []*ModuleState{ 5391 &ModuleState{ 5392 Path: rootModulePath, 5393 Resources: map[string]*ResourceState{ 5394 "aws_instance.bar": &ResourceState{ 5395 Type: "aws_instance", 5396 Primary: &InstanceState{ 5397 ID: "bar", 5398 }, 5399 }, 5400 }, 5401 }, 5402 }, 5403 } 5404 ctx := testContext2(t, &ContextOpts{ 5405 Module: m, 5406 Providers: map[string]ResourceProviderFactory{ 5407 "aws": testProviderFuncFixed(p), 5408 }, 5409 State: s, 5410 }) 5411 5412 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5413 if errored { 5414 return s, fmt.Errorf("error") 5415 } 5416 errored = true 5417 5418 return &InstanceState{ 5419 ID: "foo", 5420 Attributes: map[string]string{ 5421 "num": "2", 5422 }, 5423 }, nil 5424 } 5425 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5426 return &InstanceDiff{ 5427 Attributes: map[string]*ResourceAttrDiff{ 5428 "num": &ResourceAttrDiff{ 5429 New: "bar", 5430 }, 5431 }, 5432 }, nil 5433 } 5434 5435 if _, err := ctx.Plan(); err != nil { 5436 t.Fatalf("err: %s", err) 5437 } 5438 5439 state, err := ctx.Apply() 5440 if err == nil { 5441 t.Fatal("should have error") 5442 } 5443 5444 mod := state.RootModule() 5445 if len(mod.Resources) != 2 { 5446 t.Fatalf("bad: %#v", mod.Resources) 5447 } 5448 5449 actual := strings.TrimSpace(state.String()) 5450 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 5451 if actual != expected { 5452 t.Fatalf("bad: \n%s", actual) 5453 } 5454 } 5455 5456 func TestContext2Apply_hook(t *testing.T) { 5457 m := testModule(t, "apply-good") 5458 h := new(MockHook) 5459 p := testProvider("aws") 5460 p.ApplyFn = testApplyFn 5461 p.DiffFn = testDiffFn 5462 ctx := testContext2(t, &ContextOpts{ 5463 Module: m, 5464 Hooks: []Hook{h}, 5465 Providers: map[string]ResourceProviderFactory{ 5466 "aws": testProviderFuncFixed(p), 5467 }, 5468 }) 5469 5470 if _, err := ctx.Plan(); err != nil { 5471 t.Fatalf("err: %s", err) 5472 } 5473 5474 if _, err := ctx.Apply(); err != nil { 5475 t.Fatalf("err: %s", err) 5476 } 5477 5478 if !h.PreApplyCalled { 5479 t.Fatal("should be called") 5480 } 5481 if !h.PostApplyCalled { 5482 t.Fatal("should be called") 5483 } 5484 if !h.PostStateUpdateCalled { 5485 t.Fatalf("should call post state update") 5486 } 5487 } 5488 5489 func TestContext2Apply_hookOrphan(t *testing.T) { 5490 m := testModule(t, "apply-blank") 5491 h := new(MockHook) 5492 p := testProvider("aws") 5493 p.ApplyFn = testApplyFn 5494 p.DiffFn = testDiffFn 5495 5496 state := &State{ 5497 Modules: []*ModuleState{ 5498 &ModuleState{ 5499 Path: rootModulePath, 5500 Resources: map[string]*ResourceState{ 5501 "aws_instance.bar": &ResourceState{ 5502 Type: "aws_instance", 5503 Primary: &InstanceState{ 5504 ID: "bar", 5505 }, 5506 }, 5507 }, 5508 }, 5509 }, 5510 } 5511 5512 ctx := testContext2(t, &ContextOpts{ 5513 Module: m, 5514 State: state, 5515 Hooks: []Hook{h}, 5516 Providers: map[string]ResourceProviderFactory{ 5517 "aws": testProviderFuncFixed(p), 5518 }, 5519 }) 5520 5521 if _, err := ctx.Plan(); err != nil { 5522 t.Fatalf("err: %s", err) 5523 } 5524 5525 if _, err := ctx.Apply(); err != nil { 5526 t.Fatalf("err: %s", err) 5527 } 5528 5529 if !h.PreApplyCalled { 5530 t.Fatal("should be called") 5531 } 5532 if !h.PostApplyCalled { 5533 t.Fatal("should be called") 5534 } 5535 if !h.PostStateUpdateCalled { 5536 t.Fatalf("should call post state update") 5537 } 5538 } 5539 5540 func TestContext2Apply_idAttr(t *testing.T) { 5541 m := testModule(t, "apply-idattr") 5542 p := testProvider("aws") 5543 ctx := testContext2(t, &ContextOpts{ 5544 Module: m, 5545 Providers: map[string]ResourceProviderFactory{ 5546 "aws": testProviderFuncFixed(p), 5547 }, 5548 }) 5549 5550 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5551 result := s.MergeDiff(d) 5552 result.ID = "foo" 5553 result.Attributes = map[string]string{ 5554 "id": "bar", 5555 } 5556 5557 return result, nil 5558 } 5559 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5560 return &InstanceDiff{ 5561 Attributes: map[string]*ResourceAttrDiff{ 5562 "num": &ResourceAttrDiff{ 5563 New: "bar", 5564 }, 5565 }, 5566 }, nil 5567 } 5568 5569 if _, err := ctx.Plan(); err != nil { 5570 t.Fatalf("err: %s", err) 5571 } 5572 5573 state, err := ctx.Apply() 5574 if err != nil { 5575 t.Fatalf("err: %s", err) 5576 } 5577 5578 mod := state.RootModule() 5579 rs, ok := mod.Resources["aws_instance.foo"] 5580 if !ok { 5581 t.Fatal("not in state") 5582 } 5583 if rs.Primary.ID != "foo" { 5584 t.Fatalf("bad: %#v", rs.Primary.ID) 5585 } 5586 if rs.Primary.Attributes["id"] != "foo" { 5587 t.Fatalf("bad: %#v", rs.Primary.Attributes) 5588 } 5589 } 5590 5591 func TestContext2Apply_outputBasic(t *testing.T) { 5592 m := testModule(t, "apply-output") 5593 p := testProvider("aws") 5594 p.ApplyFn = testApplyFn 5595 p.DiffFn = testDiffFn 5596 ctx := testContext2(t, &ContextOpts{ 5597 Module: m, 5598 Providers: map[string]ResourceProviderFactory{ 5599 "aws": testProviderFuncFixed(p), 5600 }, 5601 }) 5602 5603 if _, err := ctx.Plan(); err != nil { 5604 t.Fatalf("err: %s", err) 5605 } 5606 5607 state, err := ctx.Apply() 5608 if err != nil { 5609 t.Fatalf("err: %s", err) 5610 } 5611 5612 actual := strings.TrimSpace(state.String()) 5613 expected := strings.TrimSpace(testTerraformApplyOutputStr) 5614 if actual != expected { 5615 t.Fatalf("bad: \n%s", actual) 5616 } 5617 } 5618 5619 func TestContext2Apply_outputInvalid(t *testing.T) { 5620 m := testModule(t, "apply-output-invalid") 5621 p := testProvider("aws") 5622 p.ApplyFn = testApplyFn 5623 p.DiffFn = testDiffFn 5624 ctx := testContext2(t, &ContextOpts{ 5625 Module: m, 5626 Providers: map[string]ResourceProviderFactory{ 5627 "aws": testProviderFuncFixed(p), 5628 }, 5629 }) 5630 5631 _, err := ctx.Plan() 5632 if err == nil { 5633 t.Fatalf("err: %s", err) 5634 } 5635 if !strings.Contains(err.Error(), "is not a valid type") { 5636 t.Fatalf("err: %s", err) 5637 } 5638 } 5639 5640 func TestContext2Apply_outputAdd(t *testing.T) { 5641 m1 := testModule(t, "apply-output-add-before") 5642 p1 := testProvider("aws") 5643 p1.ApplyFn = testApplyFn 5644 p1.DiffFn = testDiffFn 5645 ctx1 := testContext2(t, &ContextOpts{ 5646 Module: m1, 5647 Providers: map[string]ResourceProviderFactory{ 5648 "aws": testProviderFuncFixed(p1), 5649 }, 5650 }) 5651 5652 if _, err := ctx1.Plan(); err != nil { 5653 t.Fatalf("err: %s", err) 5654 } 5655 5656 state1, err := ctx1.Apply() 5657 if err != nil { 5658 t.Fatalf("err: %s", err) 5659 } 5660 5661 m2 := testModule(t, "apply-output-add-after") 5662 p2 := testProvider("aws") 5663 p2.ApplyFn = testApplyFn 5664 p2.DiffFn = testDiffFn 5665 ctx2 := testContext2(t, &ContextOpts{ 5666 Module: m2, 5667 Providers: map[string]ResourceProviderFactory{ 5668 "aws": testProviderFuncFixed(p2), 5669 }, 5670 State: state1, 5671 }) 5672 5673 if _, err := ctx2.Plan(); err != nil { 5674 t.Fatalf("err: %s", err) 5675 } 5676 5677 state2, err := ctx2.Apply() 5678 if err != nil { 5679 t.Fatalf("err: %s", err) 5680 } 5681 5682 actual := strings.TrimSpace(state2.String()) 5683 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 5684 if actual != expected { 5685 t.Fatalf("bad: \n%s", actual) 5686 } 5687 } 5688 5689 func TestContext2Apply_outputList(t *testing.T) { 5690 m := testModule(t, "apply-output-list") 5691 p := testProvider("aws") 5692 p.ApplyFn = testApplyFn 5693 p.DiffFn = testDiffFn 5694 ctx := testContext2(t, &ContextOpts{ 5695 Module: m, 5696 Providers: map[string]ResourceProviderFactory{ 5697 "aws": testProviderFuncFixed(p), 5698 }, 5699 }) 5700 5701 if _, err := ctx.Plan(); err != nil { 5702 t.Fatalf("err: %s", err) 5703 } 5704 5705 state, err := ctx.Apply() 5706 if err != nil { 5707 t.Fatalf("err: %s", err) 5708 } 5709 5710 actual := strings.TrimSpace(state.String()) 5711 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 5712 if actual != expected { 5713 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5714 } 5715 } 5716 5717 func TestContext2Apply_outputMulti(t *testing.T) { 5718 m := testModule(t, "apply-output-multi") 5719 p := testProvider("aws") 5720 p.ApplyFn = testApplyFn 5721 p.DiffFn = testDiffFn 5722 ctx := testContext2(t, &ContextOpts{ 5723 Module: m, 5724 Providers: map[string]ResourceProviderFactory{ 5725 "aws": testProviderFuncFixed(p), 5726 }, 5727 }) 5728 5729 if _, err := ctx.Plan(); err != nil { 5730 t.Fatalf("err: %s", err) 5731 } 5732 5733 state, err := ctx.Apply() 5734 if err != nil { 5735 t.Fatalf("err: %s", err) 5736 } 5737 5738 actual := strings.TrimSpace(state.String()) 5739 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 5740 if actual != expected { 5741 t.Fatalf("bad: \n%s", actual) 5742 } 5743 } 5744 5745 func TestContext2Apply_outputMultiIndex(t *testing.T) { 5746 m := testModule(t, "apply-output-multi-index") 5747 p := testProvider("aws") 5748 p.ApplyFn = testApplyFn 5749 p.DiffFn = testDiffFn 5750 ctx := testContext2(t, &ContextOpts{ 5751 Module: m, 5752 Providers: map[string]ResourceProviderFactory{ 5753 "aws": testProviderFuncFixed(p), 5754 }, 5755 }) 5756 5757 if _, err := ctx.Plan(); err != nil { 5758 t.Fatalf("err: %s", err) 5759 } 5760 5761 state, err := ctx.Apply() 5762 if err != nil { 5763 t.Fatalf("err: %s", err) 5764 } 5765 5766 actual := strings.TrimSpace(state.String()) 5767 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 5768 if actual != expected { 5769 t.Fatalf("bad: \n%s", actual) 5770 } 5771 } 5772 5773 func TestContext2Apply_taintX(t *testing.T) { 5774 m := testModule(t, "apply-taint") 5775 p := testProvider("aws") 5776 5777 // destroyCount tests against regression of 5778 // https://github.com/hashicorp/terraform/issues/1056 5779 var destroyCount = int32(0) 5780 var once sync.Once 5781 simulateProviderDelay := func() { 5782 time.Sleep(10 * time.Millisecond) 5783 } 5784 5785 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5786 once.Do(simulateProviderDelay) 5787 if d.Destroy { 5788 atomic.AddInt32(&destroyCount, 1) 5789 } 5790 return testApplyFn(info, s, d) 5791 } 5792 p.DiffFn = testDiffFn 5793 s := &State{ 5794 Modules: []*ModuleState{ 5795 &ModuleState{ 5796 Path: rootModulePath, 5797 Resources: map[string]*ResourceState{ 5798 "aws_instance.bar": &ResourceState{ 5799 Type: "aws_instance", 5800 Primary: &InstanceState{ 5801 ID: "baz", 5802 Attributes: map[string]string{ 5803 "num": "2", 5804 "type": "aws_instance", 5805 }, 5806 Tainted: true, 5807 }, 5808 }, 5809 }, 5810 }, 5811 }, 5812 } 5813 ctx := testContext2(t, &ContextOpts{ 5814 Module: m, 5815 Providers: map[string]ResourceProviderFactory{ 5816 "aws": testProviderFuncFixed(p), 5817 }, 5818 State: s, 5819 }) 5820 5821 if p, err := ctx.Plan(); err != nil { 5822 t.Fatalf("err: %s", err) 5823 } else { 5824 t.Logf("plan: %s", p) 5825 } 5826 5827 state, err := ctx.Apply() 5828 if err != nil { 5829 t.Fatalf("err: %s", err) 5830 } 5831 5832 actual := strings.TrimSpace(state.String()) 5833 expected := strings.TrimSpace(testTerraformApplyTaintStr) 5834 if actual != expected { 5835 t.Fatalf("bad:\n%s", actual) 5836 } 5837 5838 if destroyCount != 1 { 5839 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 5840 } 5841 } 5842 5843 func TestContext2Apply_taintDep(t *testing.T) { 5844 m := testModule(t, "apply-taint-dep") 5845 p := testProvider("aws") 5846 p.ApplyFn = testApplyFn 5847 p.DiffFn = testDiffFn 5848 s := &State{ 5849 Modules: []*ModuleState{ 5850 &ModuleState{ 5851 Path: rootModulePath, 5852 Resources: map[string]*ResourceState{ 5853 "aws_instance.foo": &ResourceState{ 5854 Type: "aws_instance", 5855 Primary: &InstanceState{ 5856 ID: "baz", 5857 Attributes: map[string]string{ 5858 "num": "2", 5859 "type": "aws_instance", 5860 }, 5861 Tainted: true, 5862 }, 5863 }, 5864 "aws_instance.bar": &ResourceState{ 5865 Type: "aws_instance", 5866 Primary: &InstanceState{ 5867 ID: "bar", 5868 Attributes: map[string]string{ 5869 "foo": "baz", 5870 "num": "2", 5871 "type": "aws_instance", 5872 }, 5873 }, 5874 }, 5875 }, 5876 }, 5877 }, 5878 } 5879 ctx := testContext2(t, &ContextOpts{ 5880 Module: m, 5881 Providers: map[string]ResourceProviderFactory{ 5882 "aws": testProviderFuncFixed(p), 5883 }, 5884 State: s, 5885 }) 5886 5887 if p, err := ctx.Plan(); err != nil { 5888 t.Fatalf("err: %s", err) 5889 } else { 5890 t.Logf("plan: %s", p) 5891 } 5892 5893 state, err := ctx.Apply() 5894 if err != nil { 5895 t.Fatalf("err: %s", err) 5896 } 5897 5898 actual := strings.TrimSpace(state.String()) 5899 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 5900 if actual != expected { 5901 t.Fatalf("bad:\n%s", actual) 5902 } 5903 } 5904 5905 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 5906 m := testModule(t, "apply-taint-dep-requires-new") 5907 p := testProvider("aws") 5908 p.ApplyFn = testApplyFn 5909 p.DiffFn = testDiffFn 5910 s := &State{ 5911 Modules: []*ModuleState{ 5912 &ModuleState{ 5913 Path: rootModulePath, 5914 Resources: map[string]*ResourceState{ 5915 "aws_instance.foo": &ResourceState{ 5916 Type: "aws_instance", 5917 Primary: &InstanceState{ 5918 ID: "baz", 5919 Attributes: map[string]string{ 5920 "num": "2", 5921 "type": "aws_instance", 5922 }, 5923 Tainted: true, 5924 }, 5925 }, 5926 "aws_instance.bar": &ResourceState{ 5927 Type: "aws_instance", 5928 Primary: &InstanceState{ 5929 ID: "bar", 5930 Attributes: map[string]string{ 5931 "foo": "baz", 5932 "num": "2", 5933 "type": "aws_instance", 5934 }, 5935 }, 5936 }, 5937 }, 5938 }, 5939 }, 5940 } 5941 ctx := testContext2(t, &ContextOpts{ 5942 Module: m, 5943 Providers: map[string]ResourceProviderFactory{ 5944 "aws": testProviderFuncFixed(p), 5945 }, 5946 State: s, 5947 }) 5948 5949 if p, err := ctx.Plan(); err != nil { 5950 t.Fatalf("err: %s", err) 5951 } else { 5952 t.Logf("plan: %s", p) 5953 } 5954 5955 state, err := ctx.Apply() 5956 if err != nil { 5957 t.Fatalf("err: %s", err) 5958 } 5959 5960 actual := strings.TrimSpace(state.String()) 5961 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 5962 if actual != expected { 5963 t.Fatalf("bad:\n%s", actual) 5964 } 5965 } 5966 5967 func TestContext2Apply_targeted(t *testing.T) { 5968 m := testModule(t, "apply-targeted") 5969 p := testProvider("aws") 5970 p.ApplyFn = testApplyFn 5971 p.DiffFn = testDiffFn 5972 ctx := testContext2(t, &ContextOpts{ 5973 Module: m, 5974 Providers: map[string]ResourceProviderFactory{ 5975 "aws": testProviderFuncFixed(p), 5976 }, 5977 Targets: []string{"aws_instance.foo"}, 5978 }) 5979 5980 if _, err := ctx.Plan(); err != nil { 5981 t.Fatalf("err: %s", err) 5982 } 5983 5984 state, err := ctx.Apply() 5985 if err != nil { 5986 t.Fatalf("err: %s", err) 5987 } 5988 5989 mod := state.RootModule() 5990 if len(mod.Resources) != 1 { 5991 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 5992 } 5993 5994 checkStateString(t, state, ` 5995 aws_instance.foo: 5996 ID = foo 5997 num = 2 5998 type = aws_instance 5999 `) 6000 } 6001 6002 func TestContext2Apply_targetedCount(t *testing.T) { 6003 m := testModule(t, "apply-targeted-count") 6004 p := testProvider("aws") 6005 p.ApplyFn = testApplyFn 6006 p.DiffFn = testDiffFn 6007 ctx := testContext2(t, &ContextOpts{ 6008 Module: m, 6009 Providers: map[string]ResourceProviderFactory{ 6010 "aws": testProviderFuncFixed(p), 6011 }, 6012 Targets: []string{"aws_instance.foo"}, 6013 }) 6014 6015 if _, err := ctx.Plan(); err != nil { 6016 t.Fatalf("err: %s", err) 6017 } 6018 6019 state, err := ctx.Apply() 6020 if err != nil { 6021 t.Fatalf("err: %s", err) 6022 } 6023 6024 checkStateString(t, state, ` 6025 aws_instance.foo.0: 6026 ID = foo 6027 aws_instance.foo.1: 6028 ID = foo 6029 aws_instance.foo.2: 6030 ID = foo 6031 `) 6032 } 6033 6034 func TestContext2Apply_targetedCountIndex(t *testing.T) { 6035 m := testModule(t, "apply-targeted-count") 6036 p := testProvider("aws") 6037 p.ApplyFn = testApplyFn 6038 p.DiffFn = testDiffFn 6039 ctx := testContext2(t, &ContextOpts{ 6040 Module: m, 6041 Providers: map[string]ResourceProviderFactory{ 6042 "aws": testProviderFuncFixed(p), 6043 }, 6044 Targets: []string{"aws_instance.foo[1]"}, 6045 }) 6046 6047 if _, err := ctx.Plan(); err != nil { 6048 t.Fatalf("err: %s", err) 6049 } 6050 6051 state, err := ctx.Apply() 6052 if err != nil { 6053 t.Fatalf("err: %s", err) 6054 } 6055 6056 checkStateString(t, state, ` 6057 aws_instance.foo.1: 6058 ID = foo 6059 `) 6060 } 6061 6062 func TestContext2Apply_targetedDestroy(t *testing.T) { 6063 m := testModule(t, "apply-targeted") 6064 p := testProvider("aws") 6065 p.ApplyFn = testApplyFn 6066 p.DiffFn = testDiffFn 6067 ctx := testContext2(t, &ContextOpts{ 6068 Module: m, 6069 Providers: map[string]ResourceProviderFactory{ 6070 "aws": testProviderFuncFixed(p), 6071 }, 6072 State: &State{ 6073 Modules: []*ModuleState{ 6074 &ModuleState{ 6075 Path: rootModulePath, 6076 Resources: map[string]*ResourceState{ 6077 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6078 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6079 }, 6080 }, 6081 }, 6082 }, 6083 Targets: []string{"aws_instance.foo"}, 6084 Destroy: true, 6085 }) 6086 6087 if _, err := ctx.Plan(); err != nil { 6088 t.Fatalf("err: %s", err) 6089 } 6090 6091 state, err := ctx.Apply() 6092 if err != nil { 6093 t.Fatalf("err: %s", err) 6094 } 6095 6096 mod := state.RootModule() 6097 if len(mod.Resources) != 1 { 6098 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 6099 } 6100 6101 checkStateString(t, state, ` 6102 aws_instance.bar: 6103 ID = i-abc123 6104 `) 6105 } 6106 6107 func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) { 6108 m := testModule(t, "apply-destroy-targeted-count") 6109 p := testProvider("aws") 6110 p.ApplyFn = testApplyFn 6111 p.DiffFn = testDiffFn 6112 ctx := testContext2(t, &ContextOpts{ 6113 Module: m, 6114 Providers: map[string]ResourceProviderFactory{ 6115 "aws": testProviderFuncFixed(p), 6116 }, 6117 State: &State{ 6118 Modules: []*ModuleState{ 6119 &ModuleState{ 6120 Path: rootModulePath, 6121 Resources: map[string]*ResourceState{ 6122 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6123 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6124 }, 6125 }, 6126 }, 6127 }, 6128 Targets: []string{"aws_instance.foo"}, 6129 Destroy: true, 6130 }) 6131 6132 if _, err := ctx.Plan(); err != nil { 6133 t.Fatalf("err: %s", err) 6134 } 6135 6136 state, err := ctx.Apply() 6137 if err != nil { 6138 t.Fatalf("err: %s", err) 6139 } 6140 6141 checkStateString(t, state, `<no state>`) 6142 } 6143 6144 // https://github.com/hashicorp/terraform/issues/4462 6145 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 6146 m := testModule(t, "apply-targeted-module") 6147 p := testProvider("aws") 6148 p.ApplyFn = testApplyFn 6149 p.DiffFn = testDiffFn 6150 ctx := testContext2(t, &ContextOpts{ 6151 Module: m, 6152 Providers: map[string]ResourceProviderFactory{ 6153 "aws": testProviderFuncFixed(p), 6154 }, 6155 State: &State{ 6156 Modules: []*ModuleState{ 6157 &ModuleState{ 6158 Path: rootModulePath, 6159 Resources: map[string]*ResourceState{ 6160 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6161 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6162 }, 6163 }, 6164 &ModuleState{ 6165 Path: []string{"root", "child"}, 6166 Resources: map[string]*ResourceState{ 6167 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6168 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6169 }, 6170 }, 6171 }, 6172 }, 6173 Targets: []string{"module.child.aws_instance.foo"}, 6174 Destroy: true, 6175 }) 6176 6177 if _, err := ctx.Plan(); err != nil { 6178 t.Fatalf("err: %s", err) 6179 } 6180 6181 state, err := ctx.Apply() 6182 if err != nil { 6183 t.Fatalf("err: %s", err) 6184 } 6185 6186 checkStateString(t, state, ` 6187 aws_instance.bar: 6188 ID = i-abc123 6189 aws_instance.foo: 6190 ID = i-bcd345 6191 6192 module.child: 6193 aws_instance.bar: 6194 ID = i-abc123 6195 `) 6196 } 6197 6198 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 6199 m := testModule(t, "apply-targeted-count") 6200 p := testProvider("aws") 6201 p.ApplyFn = testApplyFn 6202 p.DiffFn = testDiffFn 6203 ctx := testContext2(t, &ContextOpts{ 6204 Module: m, 6205 Providers: map[string]ResourceProviderFactory{ 6206 "aws": testProviderFuncFixed(p), 6207 }, 6208 State: &State{ 6209 Modules: []*ModuleState{ 6210 &ModuleState{ 6211 Path: rootModulePath, 6212 Resources: map[string]*ResourceState{ 6213 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 6214 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 6215 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 6216 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 6217 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 6218 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 6219 }, 6220 }, 6221 }, 6222 }, 6223 Targets: []string{ 6224 "aws_instance.foo[2]", 6225 "aws_instance.bar[1]", 6226 }, 6227 Destroy: true, 6228 }) 6229 6230 if _, err := ctx.Plan(); err != nil { 6231 t.Fatalf("err: %s", err) 6232 } 6233 6234 state, err := ctx.Apply() 6235 if err != nil { 6236 t.Fatalf("err: %s", err) 6237 } 6238 6239 checkStateString(t, state, ` 6240 aws_instance.bar.0: 6241 ID = i-abc123 6242 aws_instance.bar.2: 6243 ID = i-abc123 6244 aws_instance.foo.0: 6245 ID = i-bcd345 6246 aws_instance.foo.1: 6247 ID = i-bcd345 6248 `) 6249 } 6250 6251 func TestContext2Apply_targetedModule(t *testing.T) { 6252 m := testModule(t, "apply-targeted-module") 6253 p := testProvider("aws") 6254 p.ApplyFn = testApplyFn 6255 p.DiffFn = testDiffFn 6256 ctx := testContext2(t, &ContextOpts{ 6257 Module: m, 6258 Providers: map[string]ResourceProviderFactory{ 6259 "aws": testProviderFuncFixed(p), 6260 }, 6261 Targets: []string{"module.child"}, 6262 }) 6263 6264 if _, err := ctx.Plan(); err != nil { 6265 t.Fatalf("err: %s", err) 6266 } 6267 6268 state, err := ctx.Apply() 6269 if err != nil { 6270 t.Fatalf("err: %s", err) 6271 } 6272 6273 mod := state.ModuleByPath([]string{"root", "child"}) 6274 if mod == nil { 6275 t.Fatalf("no child module found in the state!\n\n%#v", state) 6276 } 6277 if len(mod.Resources) != 2 { 6278 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 6279 } 6280 6281 checkStateString(t, state, ` 6282 <no state> 6283 module.child: 6284 aws_instance.bar: 6285 ID = foo 6286 num = 2 6287 type = aws_instance 6288 aws_instance.foo: 6289 ID = foo 6290 num = 2 6291 type = aws_instance 6292 `) 6293 } 6294 6295 // GH-1858 6296 func TestContext2Apply_targetedModuleDep(t *testing.T) { 6297 m := testModule(t, "apply-targeted-module-dep") 6298 p := testProvider("aws") 6299 p.ApplyFn = testApplyFn 6300 p.DiffFn = testDiffFn 6301 ctx := testContext2(t, &ContextOpts{ 6302 Module: m, 6303 Providers: map[string]ResourceProviderFactory{ 6304 "aws": testProviderFuncFixed(p), 6305 }, 6306 Targets: []string{"aws_instance.foo"}, 6307 }) 6308 6309 if p, err := ctx.Plan(); err != nil { 6310 t.Fatalf("err: %s", err) 6311 } else { 6312 t.Logf("Diff: %s", p) 6313 } 6314 6315 state, err := ctx.Apply() 6316 if err != nil { 6317 t.Fatalf("err: %s", err) 6318 } 6319 6320 checkStateString(t, state, ` 6321 aws_instance.foo: 6322 ID = foo 6323 foo = foo 6324 type = aws_instance 6325 6326 Dependencies: 6327 module.child 6328 6329 module.child: 6330 aws_instance.mod: 6331 ID = foo 6332 6333 Outputs: 6334 6335 output = foo 6336 `) 6337 } 6338 6339 func TestContext2Apply_targetedModuleResource(t *testing.T) { 6340 m := testModule(t, "apply-targeted-module-resource") 6341 p := testProvider("aws") 6342 p.ApplyFn = testApplyFn 6343 p.DiffFn = testDiffFn 6344 ctx := testContext2(t, &ContextOpts{ 6345 Module: m, 6346 Providers: map[string]ResourceProviderFactory{ 6347 "aws": testProviderFuncFixed(p), 6348 }, 6349 Targets: []string{"module.child.aws_instance.foo"}, 6350 }) 6351 6352 if _, err := ctx.Plan(); err != nil { 6353 t.Fatalf("err: %s", err) 6354 } 6355 6356 state, err := ctx.Apply() 6357 if err != nil { 6358 t.Fatalf("err: %s", err) 6359 } 6360 6361 mod := state.ModuleByPath([]string{"root", "child"}) 6362 if mod == nil || len(mod.Resources) != 1 { 6363 t.Fatalf("expected 1 resource, got: %#v", mod) 6364 } 6365 6366 checkStateString(t, state, ` 6367 <no state> 6368 module.child: 6369 aws_instance.foo: 6370 ID = foo 6371 num = 2 6372 type = aws_instance 6373 `) 6374 } 6375 6376 func TestContext2Apply_unknownAttribute(t *testing.T) { 6377 m := testModule(t, "apply-unknown") 6378 p := testProvider("aws") 6379 p.ApplyFn = testApplyFn 6380 p.DiffFn = testDiffFn 6381 ctx := testContext2(t, &ContextOpts{ 6382 Module: m, 6383 Providers: map[string]ResourceProviderFactory{ 6384 "aws": testProviderFuncFixed(p), 6385 }, 6386 }) 6387 6388 if _, err := ctx.Plan(); err != nil { 6389 t.Fatalf("err: %s", err) 6390 } 6391 6392 state, err := ctx.Apply() 6393 if err == nil { 6394 t.Fatal("should error") 6395 } 6396 6397 actual := strings.TrimSpace(state.String()) 6398 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 6399 if actual != expected { 6400 t.Fatalf("bad: \n%s", actual) 6401 } 6402 } 6403 6404 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 6405 m := testModule(t, "apply-unknown-interpolate") 6406 p := testProvider("aws") 6407 p.ApplyFn = testApplyFn 6408 p.DiffFn = testDiffFn 6409 ctx := testContext2(t, &ContextOpts{ 6410 Module: m, 6411 Providers: map[string]ResourceProviderFactory{ 6412 "aws": testProviderFuncFixed(p), 6413 }, 6414 }) 6415 6416 if _, err := ctx.Plan(); err == nil { 6417 t.Fatal("should error") 6418 } 6419 } 6420 6421 func TestContext2Apply_vars(t *testing.T) { 6422 m := testModule(t, "apply-vars") 6423 p := testProvider("aws") 6424 p.ApplyFn = testApplyFn 6425 p.DiffFn = testDiffFn 6426 ctx := testContext2(t, &ContextOpts{ 6427 Module: m, 6428 Providers: map[string]ResourceProviderFactory{ 6429 "aws": testProviderFuncFixed(p), 6430 }, 6431 Variables: map[string]interface{}{ 6432 "foo": "us-west-2", 6433 "test_list": []interface{}{"Hello", "World"}, 6434 "test_map": map[string]interface{}{ 6435 "Hello": "World", 6436 "Foo": "Bar", 6437 "Baz": "Foo", 6438 }, 6439 "amis": []map[string]interface{}{ 6440 map[string]interface{}{ 6441 "us-east-1": "override", 6442 }, 6443 }, 6444 }, 6445 }) 6446 6447 w, e := ctx.Validate() 6448 if len(w) > 0 { 6449 t.Fatalf("bad: %#v", w) 6450 } 6451 if len(e) > 0 { 6452 t.Fatalf("bad: %s", e) 6453 } 6454 6455 if _, err := ctx.Plan(); err != nil { 6456 t.Fatalf("err: %s", err) 6457 } 6458 6459 state, err := ctx.Apply() 6460 if err != nil { 6461 t.Fatalf("err: %s", err) 6462 } 6463 6464 actual := strings.TrimSpace(state.String()) 6465 expected := strings.TrimSpace(testTerraformApplyVarsStr) 6466 if actual != expected { 6467 t.Fatalf("expected: %s\n got:\n%s", expected, actual) 6468 } 6469 } 6470 6471 func TestContext2Apply_varsEnv(t *testing.T) { 6472 // Set the env var 6473 defer tempEnv(t, "TF_VAR_ami", "baz")() 6474 defer tempEnv(t, "TF_VAR_list", `["Hello", "World"]`)() 6475 defer tempEnv(t, "TF_VAR_map", `{"Hello" = "World", "Foo" = "Bar", "Baz" = "Foo"}`)() 6476 6477 m := testModule(t, "apply-vars-env") 6478 p := testProvider("aws") 6479 p.ApplyFn = testApplyFn 6480 p.DiffFn = testDiffFn 6481 ctx := testContext2(t, &ContextOpts{ 6482 Module: m, 6483 Providers: map[string]ResourceProviderFactory{ 6484 "aws": testProviderFuncFixed(p), 6485 }, 6486 }) 6487 6488 w, e := ctx.Validate() 6489 if len(w) > 0 { 6490 t.Fatalf("bad: %#v", w) 6491 } 6492 if len(e) > 0 { 6493 t.Fatalf("bad: %s", e) 6494 } 6495 6496 if _, err := ctx.Plan(); err != nil { 6497 t.Fatalf("err: %s", err) 6498 } 6499 6500 state, err := ctx.Apply() 6501 if err != nil { 6502 t.Fatalf("err: %s", err) 6503 } 6504 6505 actual := strings.TrimSpace(state.String()) 6506 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 6507 if actual != expected { 6508 t.Fatalf("bad: \n%s", actual) 6509 } 6510 } 6511 6512 func TestContext2Apply_createBefore_depends(t *testing.T) { 6513 m := testModule(t, "apply-depends-create-before") 6514 h := new(HookRecordApplyOrder) 6515 p := testProvider("aws") 6516 p.ApplyFn = testApplyFn 6517 p.DiffFn = testDiffFn 6518 state := &State{ 6519 Modules: []*ModuleState{ 6520 &ModuleState{ 6521 Path: rootModulePath, 6522 Resources: map[string]*ResourceState{ 6523 "aws_instance.web": &ResourceState{ 6524 Type: "aws_instance", 6525 Primary: &InstanceState{ 6526 ID: "bar", 6527 Attributes: map[string]string{ 6528 "require_new": "ami-old", 6529 }, 6530 }, 6531 }, 6532 "aws_instance.lb": &ResourceState{ 6533 Type: "aws_instance", 6534 Primary: &InstanceState{ 6535 ID: "baz", 6536 Attributes: map[string]string{ 6537 "instance": "bar", 6538 }, 6539 }, 6540 }, 6541 }, 6542 }, 6543 }, 6544 } 6545 ctx := testContext2(t, &ContextOpts{ 6546 Module: m, 6547 Hooks: []Hook{h}, 6548 Providers: map[string]ResourceProviderFactory{ 6549 "aws": testProviderFuncFixed(p), 6550 }, 6551 State: state, 6552 }) 6553 6554 if p, err := ctx.Plan(); err != nil { 6555 t.Fatalf("err: %s", err) 6556 } else { 6557 t.Logf("plan: %s", p) 6558 } 6559 6560 h.Active = true 6561 state, err := ctx.Apply() 6562 if err != nil { 6563 t.Fatalf("err: %s", err) 6564 } 6565 6566 mod := state.RootModule() 6567 if len(mod.Resources) < 2 { 6568 t.Fatalf("bad: %#v", mod.Resources) 6569 } 6570 6571 actual := strings.TrimSpace(state.String()) 6572 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 6573 if actual != expected { 6574 t.Fatalf("bad: \n%s\n\n%s", actual, expected) 6575 } 6576 6577 // Test that things were managed _in the right order_ 6578 order := h.States 6579 diffs := h.Diffs 6580 if order[0].ID != "" || diffs[0].Destroy { 6581 t.Fatalf("should create new instance first: %#v", order) 6582 } 6583 6584 if order[1].ID != "baz" { 6585 t.Fatalf("update must happen after create: %#v", order) 6586 } 6587 6588 if order[2].ID != "bar" || !diffs[2].Destroy { 6589 t.Fatalf("destroy must happen after update: %#v", order) 6590 } 6591 } 6592 6593 func TestContext2Apply_singleDestroy(t *testing.T) { 6594 m := testModule(t, "apply-depends-create-before") 6595 h := new(HookRecordApplyOrder) 6596 p := testProvider("aws") 6597 6598 invokeCount := 0 6599 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6600 invokeCount++ 6601 switch invokeCount { 6602 case 1: 6603 if d.Destroy { 6604 t.Fatalf("should not destroy") 6605 } 6606 if s.ID != "" { 6607 t.Fatalf("should not have ID") 6608 } 6609 case 2: 6610 if d.Destroy { 6611 t.Fatalf("should not destroy") 6612 } 6613 if s.ID != "baz" { 6614 t.Fatalf("should have id") 6615 } 6616 case 3: 6617 if !d.Destroy { 6618 t.Fatalf("should destroy") 6619 } 6620 if s.ID == "" { 6621 t.Fatalf("should have ID") 6622 } 6623 default: 6624 t.Fatalf("bad invoke count %d", invokeCount) 6625 } 6626 return testApplyFn(info, s, d) 6627 } 6628 p.DiffFn = testDiffFn 6629 state := &State{ 6630 Modules: []*ModuleState{ 6631 &ModuleState{ 6632 Path: rootModulePath, 6633 Resources: map[string]*ResourceState{ 6634 "aws_instance.web": &ResourceState{ 6635 Type: "aws_instance", 6636 Primary: &InstanceState{ 6637 ID: "bar", 6638 Attributes: map[string]string{ 6639 "require_new": "ami-old", 6640 }, 6641 }, 6642 }, 6643 "aws_instance.lb": &ResourceState{ 6644 Type: "aws_instance", 6645 Primary: &InstanceState{ 6646 ID: "baz", 6647 Attributes: map[string]string{ 6648 "instance": "bar", 6649 }, 6650 }, 6651 }, 6652 }, 6653 }, 6654 }, 6655 } 6656 ctx := testContext2(t, &ContextOpts{ 6657 Module: m, 6658 Hooks: []Hook{h}, 6659 Providers: map[string]ResourceProviderFactory{ 6660 "aws": testProviderFuncFixed(p), 6661 }, 6662 State: state, 6663 }) 6664 6665 if _, err := ctx.Plan(); err != nil { 6666 t.Fatalf("err: %s", err) 6667 } 6668 6669 h.Active = true 6670 state, err := ctx.Apply() 6671 if err != nil { 6672 t.Fatalf("err: %s", err) 6673 } 6674 6675 if invokeCount != 3 { 6676 t.Fatalf("bad: %d", invokeCount) 6677 } 6678 } 6679 6680 // GH-7824 6681 func TestContext2Apply_issue7824(t *testing.T) { 6682 p := testProvider("template") 6683 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 6684 Name: "template_file", 6685 }) 6686 6687 p.ApplyFn = testApplyFn 6688 p.DiffFn = testDiffFn 6689 6690 // Apply cleanly step 0 6691 ctx := testContext2(t, &ContextOpts{ 6692 Module: testModule(t, "issue-7824"), 6693 Providers: map[string]ResourceProviderFactory{ 6694 "template": testProviderFuncFixed(p), 6695 }, 6696 }) 6697 6698 plan, err := ctx.Plan() 6699 if err != nil { 6700 t.Fatalf("err: %s", err) 6701 } 6702 6703 // Write / Read plan to simulate running it through a Plan file 6704 var buf bytes.Buffer 6705 if err := WritePlan(plan, &buf); err != nil { 6706 t.Fatalf("err: %s", err) 6707 } 6708 6709 planFromFile, err := ReadPlan(&buf) 6710 if err != nil { 6711 t.Fatalf("err: %s", err) 6712 } 6713 6714 ctx, err = planFromFile.Context(&ContextOpts{ 6715 Providers: map[string]ResourceProviderFactory{ 6716 "template": testProviderFuncFixed(p), 6717 }, 6718 }) 6719 if err != nil { 6720 t.Fatalf("err: %s", err) 6721 } 6722 6723 _, err = ctx.Apply() 6724 if err != nil { 6725 t.Fatalf("err: %s", err) 6726 } 6727 } 6728 6729 // GH-5254 6730 func TestContext2Apply_issue5254(t *testing.T) { 6731 // Create a provider. We use "template" here just to match the repro 6732 // we got from the issue itself. 6733 p := testProvider("template") 6734 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 6735 Name: "template_file", 6736 }) 6737 6738 p.ApplyFn = testApplyFn 6739 p.DiffFn = testDiffFn 6740 6741 // Apply cleanly step 0 6742 ctx := testContext2(t, &ContextOpts{ 6743 Module: testModule(t, "issue-5254/step-0"), 6744 Providers: map[string]ResourceProviderFactory{ 6745 "template": testProviderFuncFixed(p), 6746 }, 6747 }) 6748 6749 plan, err := ctx.Plan() 6750 if err != nil { 6751 t.Fatalf("err: %s", err) 6752 } 6753 6754 state, err := ctx.Apply() 6755 if err != nil { 6756 t.Fatalf("err: %s", err) 6757 } 6758 6759 // Application success. Now make the modification and store a plan 6760 ctx = testContext2(t, &ContextOpts{ 6761 Module: testModule(t, "issue-5254/step-1"), 6762 State: state, 6763 Providers: map[string]ResourceProviderFactory{ 6764 "template": testProviderFuncFixed(p), 6765 }, 6766 }) 6767 6768 plan, err = ctx.Plan() 6769 if err != nil { 6770 t.Fatalf("err: %s", err) 6771 } 6772 6773 // Write / Read plan to simulate running it through a Plan file 6774 var buf bytes.Buffer 6775 if err := WritePlan(plan, &buf); err != nil { 6776 t.Fatalf("err: %s", err) 6777 } 6778 6779 planFromFile, err := ReadPlan(&buf) 6780 if err != nil { 6781 t.Fatalf("err: %s", err) 6782 } 6783 6784 ctx, err = planFromFile.Context(&ContextOpts{ 6785 Providers: map[string]ResourceProviderFactory{ 6786 "template": testProviderFuncFixed(p), 6787 }, 6788 }) 6789 if err != nil { 6790 t.Fatalf("err: %s", err) 6791 } 6792 6793 state, err = ctx.Apply() 6794 if err != nil { 6795 t.Fatalf("err: %s", err) 6796 } 6797 6798 actual := strings.TrimSpace(state.String()) 6799 expected := strings.TrimSpace(` 6800 template_file.child: 6801 ID = foo 6802 template = Hi 6803 type = template_file 6804 6805 Dependencies: 6806 template_file.parent 6807 template_file.parent: 6808 ID = foo 6809 template = Hi 6810 type = template_file 6811 `) 6812 if actual != expected { 6813 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 6814 } 6815 } 6816 6817 func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { 6818 p := testProvider("aws") 6819 p.DiffFn = testDiffFn 6820 p.ApplyFn = testApplyFn 6821 ctx := testContext2(t, &ContextOpts{ 6822 Module: testModule(t, "apply-tainted-targets"), 6823 Providers: map[string]ResourceProviderFactory{ 6824 "aws": testProviderFuncFixed(p), 6825 }, 6826 Targets: []string{"aws_instance.iambeingadded"}, 6827 State: &State{ 6828 Modules: []*ModuleState{ 6829 &ModuleState{ 6830 Path: rootModulePath, 6831 Resources: map[string]*ResourceState{ 6832 "aws_instance.ifailedprovisioners": &ResourceState{ 6833 Primary: &InstanceState{ 6834 ID: "ifailedprovisioners", 6835 Tainted: true, 6836 }, 6837 }, 6838 }, 6839 }, 6840 }, 6841 }, 6842 }) 6843 6844 plan, err := ctx.Plan() 6845 if err != nil { 6846 t.Fatalf("err: %s", err) 6847 } 6848 6849 // Write / Read plan to simulate running it through a Plan file 6850 var buf bytes.Buffer 6851 if err := WritePlan(plan, &buf); err != nil { 6852 t.Fatalf("err: %s", err) 6853 } 6854 6855 planFromFile, err := ReadPlan(&buf) 6856 if err != nil { 6857 t.Fatalf("err: %s", err) 6858 } 6859 6860 ctx, err = planFromFile.Context(&ContextOpts{ 6861 Module: testModule(t, "apply-tainted-targets"), 6862 Providers: map[string]ResourceProviderFactory{ 6863 "aws": testProviderFuncFixed(p), 6864 }, 6865 }) 6866 if err != nil { 6867 t.Fatalf("err: %s", err) 6868 } 6869 6870 state, err := ctx.Apply() 6871 if err != nil { 6872 t.Fatalf("err: %s", err) 6873 } 6874 6875 actual := strings.TrimSpace(state.String()) 6876 expected := strings.TrimSpace(` 6877 aws_instance.iambeingadded: 6878 ID = foo 6879 aws_instance.ifailedprovisioners: (tainted) 6880 ID = ifailedprovisioners 6881 `) 6882 if actual != expected { 6883 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 6884 } 6885 } 6886 6887 // Higher level test exposing the bug this covers in 6888 // TestResource_ignoreChangesRequired 6889 func TestContext2Apply_ignoreChangesCreate(t *testing.T) { 6890 m := testModule(t, "apply-ignore-changes-create") 6891 p := testProvider("aws") 6892 p.ApplyFn = testApplyFn 6893 p.DiffFn = testDiffFn 6894 ctx := testContext2(t, &ContextOpts{ 6895 Module: m, 6896 Providers: map[string]ResourceProviderFactory{ 6897 "aws": testProviderFuncFixed(p), 6898 }, 6899 }) 6900 6901 if p, err := ctx.Plan(); err != nil { 6902 t.Fatalf("err: %s", err) 6903 } else { 6904 t.Logf(p.String()) 6905 } 6906 6907 state, err := ctx.Apply() 6908 if err != nil { 6909 t.Fatalf("err: %s", err) 6910 } 6911 6912 mod := state.RootModule() 6913 if len(mod.Resources) != 1 { 6914 t.Fatalf("bad: %s", state) 6915 } 6916 6917 actual := strings.TrimSpace(state.String()) 6918 // Expect no changes from original state 6919 expected := strings.TrimSpace(` 6920 aws_instance.foo: 6921 ID = foo 6922 required_field = set 6923 type = aws_instance 6924 `) 6925 if actual != expected { 6926 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 6927 } 6928 } 6929 6930 func TestContext2Apply_ignoreChangesWithDep(t *testing.T) { 6931 m := testModule(t, "apply-ignore-changes-dep") 6932 p := testProvider("aws") 6933 p.ApplyFn = testApplyFn 6934 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 6935 switch i.Type { 6936 case "aws_instance": 6937 newAmi, _ := c.Get("ami") 6938 return &InstanceDiff{ 6939 Attributes: map[string]*ResourceAttrDiff{ 6940 "ami": &ResourceAttrDiff{ 6941 Old: s.Attributes["ami"], 6942 New: newAmi.(string), 6943 RequiresNew: true, 6944 }, 6945 }, 6946 }, nil 6947 case "aws_eip": 6948 return testDiffFn(i, s, c) 6949 default: 6950 t.Fatalf("Unexpected type: %s", i.Type) 6951 return nil, nil 6952 } 6953 } 6954 s := &State{ 6955 Modules: []*ModuleState{ 6956 &ModuleState{ 6957 Path: rootModulePath, 6958 Resources: map[string]*ResourceState{ 6959 "aws_instance.foo.0": &ResourceState{ 6960 Primary: &InstanceState{ 6961 ID: "i-abc123", 6962 Attributes: map[string]string{ 6963 "ami": "ami-abcd1234", 6964 "id": "i-abc123", 6965 }, 6966 }, 6967 }, 6968 "aws_instance.foo.1": &ResourceState{ 6969 Primary: &InstanceState{ 6970 ID: "i-bcd234", 6971 Attributes: map[string]string{ 6972 "ami": "ami-abcd1234", 6973 "id": "i-bcd234", 6974 }, 6975 }, 6976 }, 6977 "aws_eip.foo.0": &ResourceState{ 6978 Primary: &InstanceState{ 6979 ID: "eip-abc123", 6980 Attributes: map[string]string{ 6981 "id": "eip-abc123", 6982 "instance": "i-abc123", 6983 }, 6984 }, 6985 }, 6986 "aws_eip.foo.1": &ResourceState{ 6987 Primary: &InstanceState{ 6988 ID: "eip-bcd234", 6989 Attributes: map[string]string{ 6990 "id": "eip-bcd234", 6991 "instance": "i-bcd234", 6992 }, 6993 }, 6994 }, 6995 }, 6996 }, 6997 }, 6998 } 6999 ctx := testContext2(t, &ContextOpts{ 7000 Module: m, 7001 Providers: map[string]ResourceProviderFactory{ 7002 "aws": testProviderFuncFixed(p), 7003 }, 7004 State: s, 7005 }) 7006 7007 if p, err := ctx.Plan(); err != nil { 7008 t.Fatalf("err: %s", err) 7009 } else { 7010 t.Logf(p.String()) 7011 } 7012 7013 state, err := ctx.Apply() 7014 if err != nil { 7015 t.Fatalf("err: %s", err) 7016 } 7017 7018 actual := strings.TrimSpace(state.String()) 7019 expected := strings.TrimSpace(s.String()) 7020 if actual != expected { 7021 t.Fatalf("bad: \n%s", actual) 7022 } 7023 } 7024 7025 func TestContext2Apply_ignoreChangesWildcard(t *testing.T) { 7026 m := testModule(t, "apply-ignore-changes-wildcard") 7027 p := testProvider("aws") 7028 p.ApplyFn = testApplyFn 7029 p.DiffFn = testDiffFn 7030 ctx := testContext2(t, &ContextOpts{ 7031 Module: m, 7032 Providers: map[string]ResourceProviderFactory{ 7033 "aws": testProviderFuncFixed(p), 7034 }, 7035 }) 7036 7037 if p, err := ctx.Plan(); err != nil { 7038 t.Fatalf("err: %s", err) 7039 } else { 7040 t.Logf(p.String()) 7041 } 7042 7043 state, err := ctx.Apply() 7044 if err != nil { 7045 t.Fatalf("err: %s", err) 7046 } 7047 7048 mod := state.RootModule() 7049 if len(mod.Resources) != 1 { 7050 t.Fatalf("bad: %s", state) 7051 } 7052 7053 actual := strings.TrimSpace(state.String()) 7054 // Expect no changes from original state 7055 expected := strings.TrimSpace(` 7056 aws_instance.foo: 7057 ID = foo 7058 required_field = set 7059 type = aws_instance 7060 `) 7061 if actual != expected { 7062 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 7063 } 7064 } 7065 7066 // https://github.com/hashicorp/terraform/issues/7378 7067 func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) { 7068 m := testModule(t, "apply-destroy-nested-module-with-attrs") 7069 p := testProvider("null") 7070 p.ApplyFn = testApplyFn 7071 p.DiffFn = testDiffFn 7072 7073 var state *State 7074 var err error 7075 { 7076 ctx := testContext2(t, &ContextOpts{ 7077 Module: m, 7078 Providers: map[string]ResourceProviderFactory{ 7079 "null": testProviderFuncFixed(p), 7080 }, 7081 }) 7082 7083 // First plan and apply a create operation 7084 if _, err := ctx.Plan(); err != nil { 7085 t.Fatalf("plan err: %s", err) 7086 } 7087 7088 state, err = ctx.Apply() 7089 if err != nil { 7090 t.Fatalf("apply err: %s", err) 7091 } 7092 } 7093 7094 { 7095 ctx := testContext2(t, &ContextOpts{ 7096 Destroy: true, 7097 Module: m, 7098 State: state, 7099 Providers: map[string]ResourceProviderFactory{ 7100 "null": testProviderFuncFixed(p), 7101 }, 7102 }) 7103 7104 plan, err := ctx.Plan() 7105 if err != nil { 7106 t.Fatalf("destroy plan err: %s", err) 7107 } 7108 7109 var buf bytes.Buffer 7110 if err := WritePlan(plan, &buf); err != nil { 7111 t.Fatalf("plan write err: %s", err) 7112 } 7113 7114 planFromFile, err := ReadPlan(&buf) 7115 if err != nil { 7116 t.Fatalf("plan read err: %s", err) 7117 } 7118 7119 ctx, err = planFromFile.Context(&ContextOpts{ 7120 Providers: map[string]ResourceProviderFactory{ 7121 "null": testProviderFuncFixed(p), 7122 }, 7123 }) 7124 if err != nil { 7125 t.Fatalf("err: %s", err) 7126 } 7127 7128 state, err = ctx.Apply() 7129 if err != nil { 7130 t.Fatalf("destroy apply err: %s", err) 7131 } 7132 } 7133 7134 //Test that things were destroyed 7135 actual := strings.TrimSpace(state.String()) 7136 expected := strings.TrimSpace(` 7137 <no state> 7138 module.middle: 7139 <no state> 7140 module.middle.bottom: 7141 <no state> 7142 `) 7143 if actual != expected { 7144 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 7145 } 7146 } 7147 7148 // If a data source explicitly depends on another resource, it's because we need 7149 // that resource to be applied first. 7150 func TestContext2Apply_dataDependsOn(t *testing.T) { 7151 p := testProvider("null") 7152 m := testModule(t, "apply-data-depends-on") 7153 7154 ctx := testContext2(t, &ContextOpts{ 7155 Module: m, 7156 Providers: map[string]ResourceProviderFactory{ 7157 "null": testProviderFuncFixed(p), 7158 }, 7159 }) 7160 7161 // the "provisioner" here writes to this variable, because the intent is to 7162 // create a dependency which can't be viewed through the graph, and depends 7163 // solely on the configuration providing "depends_on" 7164 provisionerOutput := "" 7165 7166 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 7167 // the side effect of the resource being applied 7168 provisionerOutput = "APPLIED" 7169 return testApplyFn(info, s, d) 7170 } 7171 7172 p.DiffFn = testDiffFn 7173 p.ReadDataDiffFn = testDataDiffFn 7174 7175 p.ReadDataApplyFn = func(*InstanceInfo, *InstanceDiff) (*InstanceState, error) { 7176 // Read the artifact created by our dependency being applied. 7177 // Without any "depends_on", this would be skipped as it's assumed the 7178 // initial diff during refresh was all that's needed. 7179 return &InstanceState{ 7180 ID: "read", 7181 Attributes: map[string]string{ 7182 "foo": provisionerOutput, 7183 }, 7184 }, nil 7185 } 7186 7187 _, err := ctx.Refresh() 7188 if err != nil { 7189 t.Fatalf("err: %s", err) 7190 } 7191 7192 if _, err := ctx.Plan(); err != nil { 7193 t.Fatalf("err: %s", err) 7194 } 7195 7196 state, err := ctx.Apply() 7197 if err != nil { 7198 t.Fatalf("err: %s", err) 7199 } 7200 7201 root := state.ModuleByPath(RootModulePath) 7202 actual := root.Resources["data.null_data_source.read"].Primary.Attributes["foo"] 7203 7204 expected := "APPLIED" 7205 if actual != expected { 7206 t.Fatalf("bad:\n%s", strings.TrimSpace(state.String())) 7207 } 7208 }