github.com/pbthorste/terraform@v0.8.6-0.20170127005045-deb56bd93da2/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 // Verify that a normal provisioner with on_failure "continue" set won't 4002 // taint the resource and continues executing. 4003 func TestContext2Apply_provisionerFailContinue(t *testing.T) { 4004 m := testModule(t, "apply-provisioner-fail-continue") 4005 p := testProvider("aws") 4006 pr := testProvisioner() 4007 p.ApplyFn = testApplyFn 4008 p.DiffFn = testDiffFn 4009 4010 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4011 return fmt.Errorf("provisioner error") 4012 } 4013 4014 ctx := testContext2(t, &ContextOpts{ 4015 Module: m, 4016 Providers: map[string]ResourceProviderFactory{ 4017 "aws": testProviderFuncFixed(p), 4018 }, 4019 Provisioners: map[string]ResourceProvisionerFactory{ 4020 "shell": testProvisionerFuncFixed(pr), 4021 }, 4022 }) 4023 4024 if _, err := ctx.Plan(); err != nil { 4025 t.Fatalf("err: %s", err) 4026 } 4027 4028 state, err := ctx.Apply() 4029 if err != nil { 4030 t.Fatalf("err: %s", err) 4031 } 4032 4033 checkStateString(t, state, ` 4034 aws_instance.foo: 4035 ID = foo 4036 foo = bar 4037 type = aws_instance 4038 `) 4039 4040 // Verify apply was invoked 4041 if !pr.ApplyCalled { 4042 t.Fatalf("provisioner not invoked") 4043 } 4044 } 4045 4046 // Verify that a normal provisioner with on_failure "continue" records 4047 // the error with the hook. 4048 func TestContext2Apply_provisionerFailContinueHook(t *testing.T) { 4049 h := new(MockHook) 4050 m := testModule(t, "apply-provisioner-fail-continue") 4051 p := testProvider("aws") 4052 pr := testProvisioner() 4053 p.ApplyFn = testApplyFn 4054 p.DiffFn = testDiffFn 4055 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4056 return fmt.Errorf("provisioner error") 4057 } 4058 4059 ctx := testContext2(t, &ContextOpts{ 4060 Module: m, 4061 Hooks: []Hook{h}, 4062 Providers: map[string]ResourceProviderFactory{ 4063 "aws": testProviderFuncFixed(p), 4064 }, 4065 Provisioners: map[string]ResourceProvisionerFactory{ 4066 "shell": testProvisionerFuncFixed(pr), 4067 }, 4068 }) 4069 4070 if _, err := ctx.Plan(); err != nil { 4071 t.Fatalf("err: %s", err) 4072 } 4073 4074 if _, err := ctx.Apply(); err != nil { 4075 t.Fatalf("err: %s", err) 4076 } 4077 4078 if !h.PostProvisionCalled { 4079 t.Fatal("PostProvision not called") 4080 } 4081 if h.PostProvisionErrorArg == nil { 4082 t.Fatal("should have error") 4083 } 4084 } 4085 4086 func TestContext2Apply_provisionerDestroy(t *testing.T) { 4087 m := testModule(t, "apply-provisioner-destroy") 4088 p := testProvider("aws") 4089 pr := testProvisioner() 4090 p.ApplyFn = testApplyFn 4091 p.DiffFn = testDiffFn 4092 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4093 val, ok := c.Config["foo"] 4094 if !ok || val != "destroy" { 4095 t.Fatalf("bad value for foo: %v %#v", val, c) 4096 } 4097 4098 return nil 4099 } 4100 4101 state := &State{ 4102 Modules: []*ModuleState{ 4103 &ModuleState{ 4104 Path: rootModulePath, 4105 Resources: map[string]*ResourceState{ 4106 "aws_instance.foo": &ResourceState{ 4107 Type: "aws_instance", 4108 Primary: &InstanceState{ 4109 ID: "bar", 4110 }, 4111 }, 4112 }, 4113 }, 4114 }, 4115 } 4116 4117 ctx := testContext2(t, &ContextOpts{ 4118 Module: m, 4119 State: state, 4120 Destroy: true, 4121 Providers: map[string]ResourceProviderFactory{ 4122 "aws": testProviderFuncFixed(p), 4123 }, 4124 Provisioners: map[string]ResourceProvisionerFactory{ 4125 "shell": testProvisionerFuncFixed(pr), 4126 }, 4127 }) 4128 4129 if _, err := ctx.Plan(); err != nil { 4130 t.Fatalf("err: %s", err) 4131 } 4132 4133 state, err := ctx.Apply() 4134 if err != nil { 4135 t.Fatalf("err: %s", err) 4136 } 4137 4138 checkStateString(t, state, `<no state>`) 4139 4140 // Verify apply was invoked 4141 if !pr.ApplyCalled { 4142 t.Fatalf("provisioner not invoked") 4143 } 4144 } 4145 4146 // Verify that on destroy provisioner failure, nothing happens to the instance 4147 func TestContext2Apply_provisionerDestroyFail(t *testing.T) { 4148 m := testModule(t, "apply-provisioner-destroy") 4149 p := testProvider("aws") 4150 pr := testProvisioner() 4151 p.ApplyFn = testApplyFn 4152 p.DiffFn = testDiffFn 4153 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4154 return fmt.Errorf("provisioner error") 4155 } 4156 4157 state := &State{ 4158 Modules: []*ModuleState{ 4159 &ModuleState{ 4160 Path: rootModulePath, 4161 Resources: map[string]*ResourceState{ 4162 "aws_instance.foo": &ResourceState{ 4163 Type: "aws_instance", 4164 Primary: &InstanceState{ 4165 ID: "bar", 4166 }, 4167 }, 4168 }, 4169 }, 4170 }, 4171 } 4172 4173 ctx := testContext2(t, &ContextOpts{ 4174 Module: m, 4175 State: state, 4176 Destroy: true, 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.Fatal("should error") 4192 } 4193 4194 checkStateString(t, state, ` 4195 aws_instance.foo: 4196 ID = bar 4197 `) 4198 4199 // Verify apply was invoked 4200 if !pr.ApplyCalled { 4201 t.Fatalf("provisioner not invoked") 4202 } 4203 } 4204 4205 // Verify that on destroy provisioner failure with "continue" that 4206 // we continue to the next provisioner. 4207 func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) { 4208 m := testModule(t, "apply-provisioner-destroy-continue") 4209 p := testProvider("aws") 4210 pr := testProvisioner() 4211 p.ApplyFn = testApplyFn 4212 p.DiffFn = testDiffFn 4213 4214 var calls []string 4215 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4216 val, ok := c.Config["foo"] 4217 if !ok { 4218 t.Fatalf("bad value for foo: %v %#v", val, c) 4219 } 4220 4221 calls = append(calls, val.(string)) 4222 return fmt.Errorf("provisioner error") 4223 } 4224 4225 state := &State{ 4226 Modules: []*ModuleState{ 4227 &ModuleState{ 4228 Path: rootModulePath, 4229 Resources: map[string]*ResourceState{ 4230 "aws_instance.foo": &ResourceState{ 4231 Type: "aws_instance", 4232 Primary: &InstanceState{ 4233 ID: "bar", 4234 }, 4235 }, 4236 }, 4237 }, 4238 }, 4239 } 4240 4241 ctx := testContext2(t, &ContextOpts{ 4242 Module: m, 4243 State: state, 4244 Destroy: true, 4245 Providers: map[string]ResourceProviderFactory{ 4246 "aws": testProviderFuncFixed(p), 4247 }, 4248 Provisioners: map[string]ResourceProvisionerFactory{ 4249 "shell": testProvisionerFuncFixed(pr), 4250 }, 4251 }) 4252 4253 if _, err := ctx.Plan(); err != nil { 4254 t.Fatalf("err: %s", err) 4255 } 4256 4257 state, err := ctx.Apply() 4258 if err != nil { 4259 t.Fatalf("err: %s", err) 4260 } 4261 4262 checkStateString(t, state, `<no state>`) 4263 4264 // Verify apply was invoked 4265 if !pr.ApplyCalled { 4266 t.Fatalf("provisioner not invoked") 4267 } 4268 4269 expected := []string{"one", "two"} 4270 if !reflect.DeepEqual(calls, expected) { 4271 t.Fatalf("bad: %#v", calls) 4272 } 4273 } 4274 4275 // Verify that on destroy provisioner failure with "continue" that 4276 // we continue to the next provisioner. But if the next provisioner defines 4277 // to fail, then we fail after running it. 4278 func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) { 4279 m := testModule(t, "apply-provisioner-destroy-fail") 4280 p := testProvider("aws") 4281 pr := testProvisioner() 4282 p.ApplyFn = testApplyFn 4283 p.DiffFn = testDiffFn 4284 4285 var calls []string 4286 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4287 val, ok := c.Config["foo"] 4288 if !ok { 4289 t.Fatalf("bad value for foo: %v %#v", val, c) 4290 } 4291 4292 calls = append(calls, val.(string)) 4293 return fmt.Errorf("provisioner error") 4294 } 4295 4296 state := &State{ 4297 Modules: []*ModuleState{ 4298 &ModuleState{ 4299 Path: rootModulePath, 4300 Resources: map[string]*ResourceState{ 4301 "aws_instance.foo": &ResourceState{ 4302 Type: "aws_instance", 4303 Primary: &InstanceState{ 4304 ID: "bar", 4305 }, 4306 }, 4307 }, 4308 }, 4309 }, 4310 } 4311 4312 ctx := testContext2(t, &ContextOpts{ 4313 Module: m, 4314 State: state, 4315 Destroy: true, 4316 Providers: map[string]ResourceProviderFactory{ 4317 "aws": testProviderFuncFixed(p), 4318 }, 4319 Provisioners: map[string]ResourceProvisionerFactory{ 4320 "shell": testProvisionerFuncFixed(pr), 4321 }, 4322 }) 4323 4324 if _, err := ctx.Plan(); err != nil { 4325 t.Fatalf("err: %s", err) 4326 } 4327 4328 state, err := ctx.Apply() 4329 if err == nil { 4330 t.Fatal("should error") 4331 } 4332 4333 checkStateString(t, state, ` 4334 aws_instance.foo: 4335 ID = bar 4336 `) 4337 4338 // Verify apply was invoked 4339 if !pr.ApplyCalled { 4340 t.Fatalf("provisioner not invoked") 4341 } 4342 4343 expected := []string{"one", "two"} 4344 if !reflect.DeepEqual(calls, expected) { 4345 t.Fatalf("bad: %#v", calls) 4346 } 4347 } 4348 4349 // Verify destroy provisioners are not run for tainted instances. 4350 func TestContext2Apply_provisionerDestroyTainted(t *testing.T) { 4351 m := testModule(t, "apply-provisioner-destroy") 4352 p := testProvider("aws") 4353 pr := testProvisioner() 4354 p.ApplyFn = testApplyFn 4355 p.DiffFn = testDiffFn 4356 4357 destroyCalled := false 4358 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4359 expected := "create" 4360 if rs.ID == "bar" { 4361 destroyCalled = true 4362 return nil 4363 } 4364 4365 val, ok := c.Config["foo"] 4366 if !ok || val != expected { 4367 t.Fatalf("bad value for foo: %v %#v", val, c) 4368 } 4369 4370 return nil 4371 } 4372 4373 state := &State{ 4374 Modules: []*ModuleState{ 4375 &ModuleState{ 4376 Path: rootModulePath, 4377 Resources: map[string]*ResourceState{ 4378 "aws_instance.foo": &ResourceState{ 4379 Type: "aws_instance", 4380 Primary: &InstanceState{ 4381 ID: "bar", 4382 Tainted: true, 4383 }, 4384 }, 4385 }, 4386 }, 4387 }, 4388 } 4389 4390 ctx := testContext2(t, &ContextOpts{ 4391 Module: m, 4392 State: state, 4393 Providers: map[string]ResourceProviderFactory{ 4394 "aws": testProviderFuncFixed(p), 4395 }, 4396 Provisioners: map[string]ResourceProvisionerFactory{ 4397 "shell": testProvisionerFuncFixed(pr), 4398 }, 4399 }) 4400 4401 if _, err := ctx.Plan(); err != nil { 4402 t.Fatalf("err: %s", err) 4403 } 4404 4405 state, err := ctx.Apply() 4406 if err != nil { 4407 t.Fatalf("err: %s", err) 4408 } 4409 4410 checkStateString(t, state, ` 4411 aws_instance.foo: 4412 ID = foo 4413 foo = bar 4414 type = aws_instance 4415 `) 4416 4417 // Verify apply was invoked 4418 if !pr.ApplyCalled { 4419 t.Fatalf("provisioner not invoked") 4420 } 4421 4422 if destroyCalled { 4423 t.Fatal("destroy should not be called") 4424 } 4425 } 4426 4427 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 4428 m := testModule(t, "apply-provisioner-resource-ref") 4429 p := testProvider("aws") 4430 pr := testProvisioner() 4431 p.ApplyFn = testApplyFn 4432 p.DiffFn = testDiffFn 4433 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4434 val, ok := c.Config["foo"] 4435 if !ok || val != "2" { 4436 t.Fatalf("bad value for foo: %v %#v", val, c) 4437 } 4438 4439 return nil 4440 } 4441 4442 ctx := testContext2(t, &ContextOpts{ 4443 Module: m, 4444 Providers: map[string]ResourceProviderFactory{ 4445 "aws": testProviderFuncFixed(p), 4446 }, 4447 Provisioners: map[string]ResourceProvisionerFactory{ 4448 "shell": testProvisionerFuncFixed(pr), 4449 }, 4450 }) 4451 4452 if _, err := ctx.Plan(); err != nil { 4453 t.Fatalf("err: %s", err) 4454 } 4455 4456 state, err := ctx.Apply() 4457 if err != nil { 4458 t.Fatalf("err: %s", err) 4459 } 4460 4461 actual := strings.TrimSpace(state.String()) 4462 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 4463 if actual != expected { 4464 t.Fatalf("bad: \n%s", actual) 4465 } 4466 4467 // Verify apply was invoked 4468 if !pr.ApplyCalled { 4469 t.Fatalf("provisioner not invoked") 4470 } 4471 } 4472 4473 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 4474 m := testModule(t, "apply-provisioner-self-ref") 4475 p := testProvider("aws") 4476 pr := testProvisioner() 4477 p.ApplyFn = testApplyFn 4478 p.DiffFn = testDiffFn 4479 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4480 val, ok := c.Config["command"] 4481 if !ok || val != "bar" { 4482 t.Fatalf("bad value for command: %v %#v", val, c) 4483 } 4484 4485 return nil 4486 } 4487 4488 ctx := testContext2(t, &ContextOpts{ 4489 Module: m, 4490 Providers: map[string]ResourceProviderFactory{ 4491 "aws": testProviderFuncFixed(p), 4492 }, 4493 Provisioners: map[string]ResourceProvisionerFactory{ 4494 "shell": testProvisionerFuncFixed(pr), 4495 }, 4496 }) 4497 4498 if _, err := ctx.Plan(); err != nil { 4499 t.Fatalf("err: %s", err) 4500 } 4501 4502 state, err := ctx.Apply() 4503 if err != nil { 4504 t.Fatalf("err: %s", err) 4505 } 4506 4507 actual := strings.TrimSpace(state.String()) 4508 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 4509 if actual != expected { 4510 t.Fatalf("bad: \n%s", actual) 4511 } 4512 4513 // Verify apply was invoked 4514 if !pr.ApplyCalled { 4515 t.Fatalf("provisioner not invoked") 4516 } 4517 } 4518 4519 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 4520 var lock sync.Mutex 4521 commands := make([]string, 0, 5) 4522 4523 m := testModule(t, "apply-provisioner-multi-self-ref") 4524 p := testProvider("aws") 4525 pr := testProvisioner() 4526 p.ApplyFn = testApplyFn 4527 p.DiffFn = testDiffFn 4528 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4529 lock.Lock() 4530 defer lock.Unlock() 4531 4532 val, ok := c.Config["command"] 4533 if !ok { 4534 t.Fatalf("bad value for command: %v %#v", val, c) 4535 } 4536 4537 commands = append(commands, val.(string)) 4538 return nil 4539 } 4540 4541 ctx := testContext2(t, &ContextOpts{ 4542 Module: m, 4543 Providers: map[string]ResourceProviderFactory{ 4544 "aws": testProviderFuncFixed(p), 4545 }, 4546 Provisioners: map[string]ResourceProvisionerFactory{ 4547 "shell": testProvisionerFuncFixed(pr), 4548 }, 4549 }) 4550 4551 if _, err := ctx.Plan(); err != nil { 4552 t.Fatalf("err: %s", err) 4553 } 4554 4555 state, err := ctx.Apply() 4556 if err != nil { 4557 t.Fatalf("err: %s", err) 4558 } 4559 4560 actual := strings.TrimSpace(state.String()) 4561 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 4562 if actual != expected { 4563 t.Fatalf("bad: \n%s", actual) 4564 } 4565 4566 // Verify apply was invoked 4567 if !pr.ApplyCalled { 4568 t.Fatalf("provisioner not invoked") 4569 } 4570 4571 // Verify our result 4572 sort.Strings(commands) 4573 expectedCommands := []string{"number 0", "number 1", "number 2"} 4574 if !reflect.DeepEqual(commands, expectedCommands) { 4575 t.Fatalf("bad: %#v", commands) 4576 } 4577 } 4578 4579 func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) { 4580 var lock sync.Mutex 4581 order := make([]string, 0, 5) 4582 4583 m := testModule(t, "apply-provisioner-multi-self-ref-single") 4584 p := testProvider("aws") 4585 pr := testProvisioner() 4586 p.ApplyFn = testApplyFn 4587 p.DiffFn = testDiffFn 4588 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4589 lock.Lock() 4590 defer lock.Unlock() 4591 4592 val, ok := c.Config["order"] 4593 if !ok { 4594 t.Fatalf("bad value for order: %v %#v", val, c) 4595 } 4596 4597 order = append(order, val.(string)) 4598 return nil 4599 } 4600 4601 ctx := testContext2(t, &ContextOpts{ 4602 Module: m, 4603 Providers: map[string]ResourceProviderFactory{ 4604 "aws": testProviderFuncFixed(p), 4605 }, 4606 Provisioners: map[string]ResourceProvisionerFactory{ 4607 "shell": testProvisionerFuncFixed(pr), 4608 }, 4609 }) 4610 4611 if _, err := ctx.Plan(); err != nil { 4612 t.Fatalf("err: %s", err) 4613 } 4614 4615 state, err := ctx.Apply() 4616 if err != nil { 4617 t.Fatalf("err: %s", err) 4618 } 4619 4620 actual := strings.TrimSpace(state.String()) 4621 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr) 4622 if actual != expected { 4623 t.Fatalf("bad: \n%s", actual) 4624 } 4625 4626 // Verify apply was invoked 4627 if !pr.ApplyCalled { 4628 t.Fatalf("provisioner not invoked") 4629 } 4630 4631 // Verify our result 4632 sort.Strings(order) 4633 expectedOrder := []string{"0", "1", "2"} 4634 if !reflect.DeepEqual(order, expectedOrder) { 4635 t.Fatalf("bad: %#v", order) 4636 } 4637 } 4638 4639 func TestContext2Apply_provisionerMultiSelfRefCount(t *testing.T) { 4640 var lock sync.Mutex 4641 commands := make([]string, 0, 5) 4642 4643 m := testModule(t, "apply-provisioner-multi-self-ref-count") 4644 p := testProvider("aws") 4645 pr := testProvisioner() 4646 p.ApplyFn = testApplyFn 4647 p.DiffFn = testDiffFn 4648 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4649 lock.Lock() 4650 defer lock.Unlock() 4651 4652 val, ok := c.Config["command"] 4653 if !ok { 4654 t.Fatalf("bad value for command: %v %#v", val, c) 4655 } 4656 4657 commands = append(commands, val.(string)) 4658 return nil 4659 } 4660 4661 ctx := testContext2(t, &ContextOpts{ 4662 Module: m, 4663 Providers: map[string]ResourceProviderFactory{ 4664 "aws": testProviderFuncFixed(p), 4665 }, 4666 Provisioners: map[string]ResourceProvisionerFactory{ 4667 "shell": testProvisionerFuncFixed(pr), 4668 }, 4669 }) 4670 4671 if _, err := ctx.Plan(); err != nil { 4672 t.Fatalf("err: %s", err) 4673 } 4674 4675 if _, err := ctx.Apply(); err != nil { 4676 t.Fatalf("err: %s", err) 4677 } 4678 4679 // Verify apply was invoked 4680 if !pr.ApplyCalled { 4681 t.Fatalf("provisioner not invoked") 4682 } 4683 4684 // Verify our result 4685 sort.Strings(commands) 4686 expectedCommands := []string{"3", "3", "3"} 4687 if !reflect.DeepEqual(commands, expectedCommands) { 4688 t.Fatalf("bad: %#v", commands) 4689 } 4690 } 4691 4692 func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) { 4693 m := testModule(t, "apply-provisioner-explicit-self-ref") 4694 p := testProvider("aws") 4695 pr := testProvisioner() 4696 p.ApplyFn = testApplyFn 4697 p.DiffFn = testDiffFn 4698 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4699 val, ok := c.Config["command"] 4700 if !ok || val != "bar" { 4701 t.Fatalf("bad value for command: %v %#v", val, c) 4702 } 4703 4704 return nil 4705 } 4706 4707 var state *State 4708 { 4709 ctx := testContext2(t, &ContextOpts{ 4710 Module: m, 4711 Providers: map[string]ResourceProviderFactory{ 4712 "aws": testProviderFuncFixed(p), 4713 }, 4714 Provisioners: map[string]ResourceProvisionerFactory{ 4715 "shell": testProvisionerFuncFixed(pr), 4716 }, 4717 }) 4718 4719 _, err := ctx.Plan() 4720 if err != nil { 4721 t.Fatalf("err: %s", err) 4722 } 4723 4724 state, err = ctx.Apply() 4725 if err != nil { 4726 t.Fatalf("err: %s", err) 4727 } 4728 4729 // Verify apply was invoked 4730 if !pr.ApplyCalled { 4731 t.Fatalf("provisioner not invoked") 4732 } 4733 } 4734 4735 { 4736 ctx := testContext2(t, &ContextOpts{ 4737 Module: m, 4738 Destroy: true, 4739 State: state, 4740 Providers: map[string]ResourceProviderFactory{ 4741 "aws": testProviderFuncFixed(p), 4742 }, 4743 Provisioners: map[string]ResourceProvisionerFactory{ 4744 "shell": testProvisionerFuncFixed(pr), 4745 }, 4746 }) 4747 4748 _, err := ctx.Plan() 4749 if err != nil { 4750 t.Fatalf("err: %s", err) 4751 } 4752 4753 state, err = ctx.Apply() 4754 if err != nil { 4755 t.Fatalf("err: %s", err) 4756 } 4757 4758 checkStateString(t, state, `<no state>`) 4759 } 4760 } 4761 4762 // Provisioner should NOT run on a diff, only create 4763 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 4764 m := testModule(t, "apply-provisioner-diff") 4765 p := testProvider("aws") 4766 pr := testProvisioner() 4767 p.ApplyFn = testApplyFn 4768 p.DiffFn = testDiffFn 4769 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4770 return nil 4771 } 4772 ctx := testContext2(t, &ContextOpts{ 4773 Module: m, 4774 Providers: map[string]ResourceProviderFactory{ 4775 "aws": testProviderFuncFixed(p), 4776 }, 4777 Provisioners: map[string]ResourceProvisionerFactory{ 4778 "shell": testProvisionerFuncFixed(pr), 4779 }, 4780 }) 4781 4782 if _, err := ctx.Plan(); err != nil { 4783 t.Fatalf("err: %s", err) 4784 } 4785 4786 state, err := ctx.Apply() 4787 if err != nil { 4788 t.Fatalf("err: %s", err) 4789 } 4790 4791 actual := strings.TrimSpace(state.String()) 4792 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 4793 if actual != expected { 4794 t.Fatalf("bad: \n%s", actual) 4795 } 4796 4797 // Verify apply was invoked 4798 if !pr.ApplyCalled { 4799 t.Fatalf("provisioner not invoked") 4800 } 4801 pr.ApplyCalled = false 4802 4803 // Change the state to force a diff 4804 mod := state.RootModule() 4805 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 4806 4807 // Re-create context with state 4808 ctx = testContext2(t, &ContextOpts{ 4809 Module: m, 4810 Providers: map[string]ResourceProviderFactory{ 4811 "aws": testProviderFuncFixed(p), 4812 }, 4813 Provisioners: map[string]ResourceProvisionerFactory{ 4814 "shell": testProvisionerFuncFixed(pr), 4815 }, 4816 State: state, 4817 }) 4818 4819 if _, err := ctx.Plan(); err != nil { 4820 t.Fatalf("err: %s", err) 4821 } 4822 4823 state2, err := ctx.Apply() 4824 if err != nil { 4825 t.Fatalf("err: %s", err) 4826 } 4827 4828 actual = strings.TrimSpace(state2.String()) 4829 if actual != expected { 4830 t.Fatalf("bad: \n%s", actual) 4831 } 4832 4833 // Verify apply was NOT invoked 4834 if pr.ApplyCalled { 4835 t.Fatalf("provisioner invoked") 4836 } 4837 } 4838 4839 func TestContext2Apply_outputDiffVars(t *testing.T) { 4840 m := testModule(t, "apply-good") 4841 p := testProvider("aws") 4842 s := &State{ 4843 Modules: []*ModuleState{ 4844 &ModuleState{ 4845 Path: rootModulePath, 4846 Resources: map[string]*ResourceState{ 4847 "aws_instance.baz": &ResourceState{ 4848 Type: "aws_instance", 4849 Primary: &InstanceState{ 4850 ID: "bar", 4851 }, 4852 }, 4853 }, 4854 }, 4855 }, 4856 } 4857 ctx := testContext2(t, &ContextOpts{ 4858 Module: m, 4859 Providers: map[string]ResourceProviderFactory{ 4860 "aws": testProviderFuncFixed(p), 4861 }, 4862 State: s, 4863 }) 4864 4865 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4866 for k, ad := range d.Attributes { 4867 if ad.NewComputed { 4868 return nil, fmt.Errorf("%s: computed", k) 4869 } 4870 } 4871 4872 result := s.MergeDiff(d) 4873 result.ID = "foo" 4874 return result, nil 4875 } 4876 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4877 return &InstanceDiff{ 4878 Attributes: map[string]*ResourceAttrDiff{ 4879 "foo": &ResourceAttrDiff{ 4880 NewComputed: true, 4881 Type: DiffAttrOutput, 4882 }, 4883 "bar": &ResourceAttrDiff{ 4884 New: "baz", 4885 }, 4886 }, 4887 }, nil 4888 } 4889 4890 if _, err := ctx.Plan(); err != nil { 4891 t.Fatalf("err: %s", err) 4892 } 4893 if _, err := ctx.Apply(); err != nil { 4894 t.Fatalf("err: %s", err) 4895 } 4896 } 4897 4898 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 4899 m := testModule(t, "apply-provisioner-conninfo") 4900 p := testProvider("aws") 4901 pr := testProvisioner() 4902 4903 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4904 if s.Ephemeral.ConnInfo == nil { 4905 t.Fatalf("ConnInfo not initialized") 4906 } 4907 4908 result, _ := testApplyFn(info, s, d) 4909 result.Ephemeral.ConnInfo = map[string]string{ 4910 "type": "ssh", 4911 "host": "127.0.0.1", 4912 "port": "22", 4913 } 4914 return result, nil 4915 } 4916 p.DiffFn = testDiffFn 4917 4918 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4919 conn := rs.Ephemeral.ConnInfo 4920 if conn["type"] != "telnet" { 4921 t.Fatalf("Bad: %#v", conn) 4922 } 4923 if conn["host"] != "127.0.0.1" { 4924 t.Fatalf("Bad: %#v", conn) 4925 } 4926 if conn["port"] != "2222" { 4927 t.Fatalf("Bad: %#v", conn) 4928 } 4929 if conn["user"] != "superuser" { 4930 t.Fatalf("Bad: %#v", conn) 4931 } 4932 if conn["pass"] != "test" { 4933 t.Fatalf("Bad: %#v", conn) 4934 } 4935 4936 return nil 4937 } 4938 4939 ctx := testContext2(t, &ContextOpts{ 4940 Module: m, 4941 Providers: map[string]ResourceProviderFactory{ 4942 "aws": testProviderFuncFixed(p), 4943 }, 4944 Provisioners: map[string]ResourceProvisionerFactory{ 4945 "shell": testProvisionerFuncFixed(pr), 4946 }, 4947 Variables: map[string]interface{}{ 4948 "value": "1", 4949 "pass": "test", 4950 }, 4951 }) 4952 4953 if _, err := ctx.Plan(); err != nil { 4954 t.Fatalf("err: %s", err) 4955 } 4956 4957 state, err := ctx.Apply() 4958 if err != nil { 4959 t.Fatalf("err: %s", err) 4960 } 4961 4962 actual := strings.TrimSpace(state.String()) 4963 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 4964 if actual != expected { 4965 t.Fatalf("bad: \n%s", actual) 4966 } 4967 4968 // Verify apply was invoked 4969 if !pr.ApplyCalled { 4970 t.Fatalf("provisioner not invoked") 4971 } 4972 } 4973 4974 func TestContext2Apply_destroyX(t *testing.T) { 4975 m := testModule(t, "apply-destroy") 4976 h := new(HookRecordApplyOrder) 4977 p := testProvider("aws") 4978 p.ApplyFn = testApplyFn 4979 p.DiffFn = testDiffFn 4980 ctx := testContext2(t, &ContextOpts{ 4981 Module: m, 4982 Hooks: []Hook{h}, 4983 Providers: map[string]ResourceProviderFactory{ 4984 "aws": testProviderFuncFixed(p), 4985 }, 4986 }) 4987 4988 // First plan and apply a create operation 4989 if _, err := ctx.Plan(); err != nil { 4990 t.Fatalf("err: %s", err) 4991 } 4992 4993 state, err := ctx.Apply() 4994 if err != nil { 4995 t.Fatalf("err: %s", err) 4996 } 4997 4998 // Next, plan and apply a destroy operation 4999 h.Active = true 5000 ctx = testContext2(t, &ContextOpts{ 5001 Destroy: true, 5002 State: state, 5003 Module: m, 5004 Hooks: []Hook{h}, 5005 Providers: map[string]ResourceProviderFactory{ 5006 "aws": testProviderFuncFixed(p), 5007 }, 5008 }) 5009 5010 if _, err := ctx.Plan(); err != nil { 5011 t.Fatalf("err: %s", err) 5012 } 5013 5014 state, err = ctx.Apply() 5015 if err != nil { 5016 t.Fatalf("err: %s", err) 5017 } 5018 5019 // Test that things were destroyed 5020 actual := strings.TrimSpace(state.String()) 5021 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 5022 if actual != expected { 5023 t.Fatalf("bad: \n%s", actual) 5024 } 5025 5026 // Test that things were destroyed _in the right order_ 5027 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 5028 actual2 := h.IDs 5029 if !reflect.DeepEqual(actual2, expected2) { 5030 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 5031 } 5032 } 5033 5034 func TestContext2Apply_destroyOrder(t *testing.T) { 5035 m := testModule(t, "apply-destroy") 5036 h := new(HookRecordApplyOrder) 5037 p := testProvider("aws") 5038 p.ApplyFn = testApplyFn 5039 p.DiffFn = testDiffFn 5040 ctx := testContext2(t, &ContextOpts{ 5041 Module: m, 5042 Hooks: []Hook{h}, 5043 Providers: map[string]ResourceProviderFactory{ 5044 "aws": testProviderFuncFixed(p), 5045 }, 5046 }) 5047 5048 // First plan and apply a create operation 5049 if _, err := ctx.Plan(); err != nil { 5050 t.Fatalf("err: %s", err) 5051 } 5052 5053 state, err := ctx.Apply() 5054 if err != nil { 5055 t.Fatalf("err: %s", err) 5056 } 5057 5058 t.Logf("State 1: %s", state) 5059 5060 // Next, plan and apply config-less to force a destroy with "apply" 5061 h.Active = true 5062 ctx = testContext2(t, &ContextOpts{ 5063 State: state, 5064 Module: module.NewEmptyTree(), 5065 Hooks: []Hook{h}, 5066 Providers: map[string]ResourceProviderFactory{ 5067 "aws": testProviderFuncFixed(p), 5068 }, 5069 }) 5070 5071 if _, err := ctx.Plan(); err != nil { 5072 t.Fatalf("err: %s", err) 5073 } 5074 5075 state, err = ctx.Apply() 5076 if err != nil { 5077 t.Fatalf("err: %s", err) 5078 } 5079 5080 // Test that things were destroyed 5081 actual := strings.TrimSpace(state.String()) 5082 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 5083 if actual != expected { 5084 t.Fatalf("bad: \n%s", actual) 5085 } 5086 5087 // Test that things were destroyed _in the right order_ 5088 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 5089 actual2 := h.IDs 5090 if !reflect.DeepEqual(actual2, expected2) { 5091 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 5092 } 5093 } 5094 5095 // https://github.com/hashicorp/terraform/issues/2767 5096 func TestContext2Apply_destroyModulePrefix(t *testing.T) { 5097 m := testModule(t, "apply-destroy-module-resource-prefix") 5098 h := new(MockHook) 5099 p := testProvider("aws") 5100 p.ApplyFn = testApplyFn 5101 p.DiffFn = testDiffFn 5102 ctx := testContext2(t, &ContextOpts{ 5103 Module: m, 5104 Hooks: []Hook{h}, 5105 Providers: map[string]ResourceProviderFactory{ 5106 "aws": testProviderFuncFixed(p), 5107 }, 5108 }) 5109 5110 // First plan and apply a create operation 5111 if _, err := ctx.Plan(); err != nil { 5112 t.Fatalf("err: %s", err) 5113 } 5114 5115 state, err := ctx.Apply() 5116 if err != nil { 5117 t.Fatalf("err: %s", err) 5118 } 5119 5120 // Verify that we got the apply info correct 5121 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 5122 t.Fatalf("bad: %s", v) 5123 } 5124 5125 // Next, plan and apply a destroy operation and reset the hook 5126 h = new(MockHook) 5127 ctx = testContext2(t, &ContextOpts{ 5128 Destroy: true, 5129 State: state, 5130 Module: m, 5131 Hooks: []Hook{h}, 5132 Providers: map[string]ResourceProviderFactory{ 5133 "aws": testProviderFuncFixed(p), 5134 }, 5135 }) 5136 5137 if _, err := ctx.Plan(); err != nil { 5138 t.Fatalf("err: %s", err) 5139 } 5140 5141 state, err = ctx.Apply() 5142 if err != nil { 5143 t.Fatalf("err: %s", err) 5144 } 5145 5146 // Test that things were destroyed 5147 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 5148 t.Fatalf("bad: %s", v) 5149 } 5150 } 5151 5152 func TestContext2Apply_destroyNestedModule(t *testing.T) { 5153 m := testModule(t, "apply-destroy-nested-module") 5154 p := testProvider("aws") 5155 p.ApplyFn = testApplyFn 5156 p.DiffFn = testDiffFn 5157 5158 s := &State{ 5159 Modules: []*ModuleState{ 5160 &ModuleState{ 5161 Path: []string{"root", "child", "subchild"}, 5162 Resources: map[string]*ResourceState{ 5163 "aws_instance.bar": &ResourceState{ 5164 Type: "aws_instance", 5165 Primary: &InstanceState{ 5166 ID: "bar", 5167 }, 5168 }, 5169 }, 5170 }, 5171 }, 5172 } 5173 5174 ctx := testContext2(t, &ContextOpts{ 5175 Module: m, 5176 Providers: map[string]ResourceProviderFactory{ 5177 "aws": testProviderFuncFixed(p), 5178 }, 5179 State: s, 5180 }) 5181 5182 // First plan and apply a create operation 5183 if _, err := ctx.Plan(); err != nil { 5184 t.Fatalf("err: %s", err) 5185 } 5186 5187 state, err := ctx.Apply() 5188 if err != nil { 5189 t.Fatalf("err: %s", err) 5190 } 5191 5192 // Test that things were destroyed 5193 actual := strings.TrimSpace(state.String()) 5194 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 5195 if actual != expected { 5196 t.Fatalf("bad: \n%s", actual) 5197 } 5198 } 5199 5200 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 5201 m := testModule(t, "apply-destroy-deeply-nested-module") 5202 p := testProvider("aws") 5203 p.ApplyFn = testApplyFn 5204 p.DiffFn = testDiffFn 5205 5206 s := &State{ 5207 Modules: []*ModuleState{ 5208 &ModuleState{ 5209 Path: []string{"root", "child", "subchild", "subsubchild"}, 5210 Resources: map[string]*ResourceState{ 5211 "aws_instance.bar": &ResourceState{ 5212 Type: "aws_instance", 5213 Primary: &InstanceState{ 5214 ID: "bar", 5215 }, 5216 }, 5217 }, 5218 }, 5219 }, 5220 } 5221 5222 ctx := testContext2(t, &ContextOpts{ 5223 Module: m, 5224 Providers: map[string]ResourceProviderFactory{ 5225 "aws": testProviderFuncFixed(p), 5226 }, 5227 State: s, 5228 }) 5229 5230 // First plan and apply a create operation 5231 if _, err := ctx.Plan(); err != nil { 5232 t.Fatalf("err: %s", err) 5233 } 5234 5235 state, err := ctx.Apply() 5236 if err != nil { 5237 t.Fatalf("err: %s", err) 5238 } 5239 5240 // Test that things were destroyed 5241 actual := strings.TrimSpace(state.String()) 5242 expected := strings.TrimSpace(` 5243 module.child.subchild.subsubchild: 5244 <no state> 5245 `) 5246 if actual != expected { 5247 t.Fatalf("bad: \n%s", actual) 5248 } 5249 } 5250 5251 // https://github.com/hashicorp/terraform/issues/5440 5252 func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { 5253 m := testModule(t, "apply-destroy-module-with-attrs") 5254 p := testProvider("aws") 5255 p.ApplyFn = testApplyFn 5256 p.DiffFn = testDiffFn 5257 5258 var state *State 5259 var err error 5260 { 5261 ctx := testContext2(t, &ContextOpts{ 5262 Module: m, 5263 Providers: map[string]ResourceProviderFactory{ 5264 "aws": testProviderFuncFixed(p), 5265 }, 5266 }) 5267 5268 // First plan and apply a create operation 5269 if p, err := ctx.Plan(); err != nil { 5270 t.Fatalf("plan err: %s", err) 5271 } else { 5272 t.Logf("Step 1 plan: %s", p) 5273 } 5274 5275 state, err = ctx.Apply() 5276 if err != nil { 5277 t.Fatalf("apply err: %s", err) 5278 } 5279 5280 t.Logf("Step 1 state: %s", state) 5281 } 5282 5283 h := new(HookRecordApplyOrder) 5284 h.Active = true 5285 5286 { 5287 ctx := testContext2(t, &ContextOpts{ 5288 Destroy: true, 5289 Module: m, 5290 State: state, 5291 Hooks: []Hook{h}, 5292 Providers: map[string]ResourceProviderFactory{ 5293 "aws": testProviderFuncFixed(p), 5294 }, 5295 Variables: map[string]interface{}{ 5296 "key_name": "foobarkey", 5297 }, 5298 }) 5299 5300 // First plan and apply a create operation 5301 plan, err := ctx.Plan() 5302 if err != nil { 5303 t.Fatalf("destroy plan err: %s", err) 5304 } 5305 5306 t.Logf("Step 2 plan: %s", plan) 5307 5308 var buf bytes.Buffer 5309 if err := WritePlan(plan, &buf); err != nil { 5310 t.Fatalf("plan write err: %s", err) 5311 } 5312 5313 planFromFile, err := ReadPlan(&buf) 5314 if err != nil { 5315 t.Fatalf("plan read err: %s", err) 5316 } 5317 5318 ctx, err = planFromFile.Context(&ContextOpts{ 5319 Providers: map[string]ResourceProviderFactory{ 5320 "aws": testProviderFuncFixed(p), 5321 }, 5322 }) 5323 if err != nil { 5324 t.Fatalf("err: %s", err) 5325 } 5326 5327 state, err = ctx.Apply() 5328 if err != nil { 5329 t.Fatalf("destroy apply err: %s", err) 5330 } 5331 5332 t.Logf("Step 2 state: %s", state) 5333 } 5334 5335 //Test that things were destroyed 5336 actual := strings.TrimSpace(state.String()) 5337 expected := strings.TrimSpace(` 5338 <no state> 5339 module.child: 5340 <no state> 5341 `) 5342 if actual != expected { 5343 t.Fatalf("expected:\n\n%s\n\nactual:\n\n%s", expected, actual) 5344 } 5345 } 5346 5347 func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { 5348 m := testModule(t, "apply-destroy-mod-var-and-count") 5349 p := testProvider("aws") 5350 p.ApplyFn = testApplyFn 5351 p.DiffFn = testDiffFn 5352 5353 var state *State 5354 var err error 5355 { 5356 ctx := testContext2(t, &ContextOpts{ 5357 Module: m, 5358 Providers: map[string]ResourceProviderFactory{ 5359 "aws": testProviderFuncFixed(p), 5360 }, 5361 }) 5362 5363 // First plan and apply a create operation 5364 if _, err := ctx.Plan(); err != nil { 5365 t.Fatalf("plan err: %s", err) 5366 } 5367 5368 state, err = ctx.Apply() 5369 if err != nil { 5370 t.Fatalf("apply err: %s", err) 5371 } 5372 } 5373 5374 h := new(HookRecordApplyOrder) 5375 h.Active = true 5376 5377 { 5378 ctx := testContext2(t, &ContextOpts{ 5379 Destroy: true, 5380 Module: m, 5381 State: state, 5382 Hooks: []Hook{h}, 5383 Providers: map[string]ResourceProviderFactory{ 5384 "aws": testProviderFuncFixed(p), 5385 }, 5386 }) 5387 5388 // First plan and apply a create operation 5389 plan, err := ctx.Plan() 5390 if err != nil { 5391 t.Fatalf("destroy plan err: %s", err) 5392 } 5393 5394 var buf bytes.Buffer 5395 if err := WritePlan(plan, &buf); err != nil { 5396 t.Fatalf("plan write err: %s", err) 5397 } 5398 5399 planFromFile, err := ReadPlan(&buf) 5400 if err != nil { 5401 t.Fatalf("plan read err: %s", err) 5402 } 5403 5404 ctx, err = planFromFile.Context(&ContextOpts{ 5405 Providers: map[string]ResourceProviderFactory{ 5406 "aws": testProviderFuncFixed(p), 5407 }, 5408 }) 5409 if err != nil { 5410 t.Fatalf("err: %s", err) 5411 } 5412 5413 state, err = ctx.Apply() 5414 if err != nil { 5415 t.Fatalf("destroy apply err: %s", err) 5416 } 5417 } 5418 5419 //Test that things were destroyed 5420 actual := strings.TrimSpace(state.String()) 5421 expected := strings.TrimSpace(` 5422 <no state> 5423 module.child: 5424 <no state> 5425 `) 5426 if actual != expected { 5427 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5428 } 5429 } 5430 5431 func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) { 5432 m := testModule(t, "apply-destroy-mod-var-and-count") 5433 p := testProvider("aws") 5434 p.ApplyFn = testApplyFn 5435 p.DiffFn = testDiffFn 5436 5437 var state *State 5438 var err error 5439 { 5440 ctx := testContext2(t, &ContextOpts{ 5441 Module: m, 5442 Providers: map[string]ResourceProviderFactory{ 5443 "aws": testProviderFuncFixed(p), 5444 }, 5445 }) 5446 5447 // First plan and apply a create operation 5448 if _, err := ctx.Plan(); err != nil { 5449 t.Fatalf("plan err: %s", err) 5450 } 5451 5452 state, err = ctx.Apply() 5453 if err != nil { 5454 t.Fatalf("apply err: %s", err) 5455 } 5456 } 5457 5458 { 5459 ctx := testContext2(t, &ContextOpts{ 5460 Destroy: true, 5461 Module: m, 5462 State: state, 5463 Providers: map[string]ResourceProviderFactory{ 5464 "aws": testProviderFuncFixed(p), 5465 }, 5466 Targets: []string{"module.child"}, 5467 }) 5468 5469 _, err := ctx.Plan() 5470 if err != nil { 5471 t.Fatalf("plan err: %s", err) 5472 } 5473 5474 // Destroy, targeting the module explicitly 5475 state, err = ctx.Apply() 5476 if err != nil { 5477 t.Fatalf("destroy apply err: %s", err) 5478 } 5479 } 5480 5481 //Test that things were destroyed 5482 actual := strings.TrimSpace(state.String()) 5483 expected := strings.TrimSpace(` 5484 <no state> 5485 module.child: 5486 <no state> 5487 `) 5488 if actual != expected { 5489 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5490 } 5491 } 5492 5493 func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { 5494 m := testModule(t, "apply-destroy-mod-var-and-count-nested") 5495 p := testProvider("aws") 5496 p.ApplyFn = testApplyFn 5497 p.DiffFn = testDiffFn 5498 5499 var state *State 5500 var err error 5501 { 5502 ctx := testContext2(t, &ContextOpts{ 5503 Module: m, 5504 Providers: map[string]ResourceProviderFactory{ 5505 "aws": testProviderFuncFixed(p), 5506 }, 5507 }) 5508 5509 // First plan and apply a create operation 5510 if _, err := ctx.Plan(); err != nil { 5511 t.Fatalf("plan err: %s", err) 5512 } 5513 5514 state, err = ctx.Apply() 5515 if err != nil { 5516 t.Fatalf("apply err: %s", err) 5517 } 5518 } 5519 5520 h := new(HookRecordApplyOrder) 5521 h.Active = true 5522 5523 { 5524 ctx := testContext2(t, &ContextOpts{ 5525 Destroy: true, 5526 Module: m, 5527 State: state, 5528 Hooks: []Hook{h}, 5529 Providers: map[string]ResourceProviderFactory{ 5530 "aws": testProviderFuncFixed(p), 5531 }, 5532 }) 5533 5534 // First plan and apply a create operation 5535 plan, err := ctx.Plan() 5536 if err != nil { 5537 t.Fatalf("destroy plan err: %s", err) 5538 } 5539 5540 var buf bytes.Buffer 5541 if err := WritePlan(plan, &buf); err != nil { 5542 t.Fatalf("plan write err: %s", err) 5543 } 5544 5545 planFromFile, err := ReadPlan(&buf) 5546 if err != nil { 5547 t.Fatalf("plan read err: %s", err) 5548 } 5549 5550 ctx, err = planFromFile.Context(&ContextOpts{ 5551 Providers: map[string]ResourceProviderFactory{ 5552 "aws": testProviderFuncFixed(p), 5553 }, 5554 }) 5555 if err != nil { 5556 t.Fatalf("err: %s", err) 5557 } 5558 5559 state, err = ctx.Apply() 5560 if err != nil { 5561 t.Fatalf("destroy apply err: %s", err) 5562 } 5563 } 5564 5565 //Test that things were destroyed 5566 actual := strings.TrimSpace(state.String()) 5567 expected := strings.TrimSpace(` 5568 <no state> 5569 module.child: 5570 <no state> 5571 module.child.child2: 5572 <no state> 5573 `) 5574 if actual != expected { 5575 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5576 } 5577 } 5578 5579 func TestContext2Apply_destroyOutputs(t *testing.T) { 5580 m := testModule(t, "apply-destroy-outputs") 5581 h := new(HookRecordApplyOrder) 5582 p := testProvider("aws") 5583 p.ApplyFn = testApplyFn 5584 p.DiffFn = testDiffFn 5585 ctx := testContext2(t, &ContextOpts{ 5586 Module: m, 5587 Hooks: []Hook{h}, 5588 Providers: map[string]ResourceProviderFactory{ 5589 "aws": testProviderFuncFixed(p), 5590 }, 5591 }) 5592 5593 // First plan and apply a create operation 5594 if _, err := ctx.Plan(); err != nil { 5595 t.Fatalf("err: %s", err) 5596 } 5597 5598 state, err := ctx.Apply() 5599 5600 if err != nil { 5601 t.Fatalf("err: %s", err) 5602 } 5603 5604 // Next, plan and apply a destroy operation 5605 h.Active = true 5606 ctx = testContext2(t, &ContextOpts{ 5607 Destroy: true, 5608 State: state, 5609 Module: m, 5610 Hooks: []Hook{h}, 5611 Providers: map[string]ResourceProviderFactory{ 5612 "aws": testProviderFuncFixed(p), 5613 }, 5614 }) 5615 5616 if _, err := ctx.Plan(); err != nil { 5617 t.Fatalf("err: %s", err) 5618 } 5619 5620 state, err = ctx.Apply() 5621 if err != nil { 5622 t.Fatalf("err: %s", err) 5623 } 5624 5625 mod := state.RootModule() 5626 if len(mod.Resources) > 0 { 5627 t.Fatalf("bad: %#v", mod) 5628 } 5629 } 5630 5631 func TestContext2Apply_destroyOrphan(t *testing.T) { 5632 m := testModule(t, "apply-error") 5633 p := testProvider("aws") 5634 s := &State{ 5635 Modules: []*ModuleState{ 5636 &ModuleState{ 5637 Path: rootModulePath, 5638 Resources: map[string]*ResourceState{ 5639 "aws_instance.baz": &ResourceState{ 5640 Type: "aws_instance", 5641 Primary: &InstanceState{ 5642 ID: "bar", 5643 }, 5644 }, 5645 }, 5646 }, 5647 }, 5648 } 5649 ctx := testContext2(t, &ContextOpts{ 5650 Module: m, 5651 Providers: map[string]ResourceProviderFactory{ 5652 "aws": testProviderFuncFixed(p), 5653 }, 5654 State: s, 5655 }) 5656 5657 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5658 if d.Destroy { 5659 return nil, nil 5660 } 5661 5662 result := s.MergeDiff(d) 5663 result.ID = "foo" 5664 return result, nil 5665 } 5666 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5667 return &InstanceDiff{ 5668 Attributes: map[string]*ResourceAttrDiff{ 5669 "num": &ResourceAttrDiff{ 5670 New: "bar", 5671 }, 5672 }, 5673 }, nil 5674 } 5675 5676 if _, err := ctx.Plan(); err != nil { 5677 t.Fatalf("err: %s", err) 5678 } 5679 5680 state, err := ctx.Apply() 5681 if err != nil { 5682 t.Fatalf("err: %s", err) 5683 } 5684 5685 mod := state.RootModule() 5686 if _, ok := mod.Resources["aws_instance.baz"]; ok { 5687 t.Fatalf("bad: %#v", mod.Resources) 5688 } 5689 } 5690 5691 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 5692 m := testModule(t, "apply-destroy-provisioner") 5693 p := testProvider("aws") 5694 pr := testProvisioner() 5695 p.ApplyFn = testApplyFn 5696 p.DiffFn = testDiffFn 5697 5698 called := false 5699 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5700 called = true 5701 return nil 5702 } 5703 5704 s := &State{ 5705 Modules: []*ModuleState{ 5706 &ModuleState{ 5707 Path: rootModulePath, 5708 Resources: map[string]*ResourceState{ 5709 "aws_instance.foo": &ResourceState{ 5710 Type: "aws_instance", 5711 Primary: &InstanceState{ 5712 ID: "bar", 5713 Attributes: map[string]string{ 5714 "id": "bar", 5715 }, 5716 Tainted: true, 5717 }, 5718 }, 5719 }, 5720 }, 5721 }, 5722 } 5723 5724 ctx := testContext2(t, &ContextOpts{ 5725 Module: m, 5726 Providers: map[string]ResourceProviderFactory{ 5727 "aws": testProviderFuncFixed(p), 5728 }, 5729 Provisioners: map[string]ResourceProvisionerFactory{ 5730 "shell": testProvisionerFuncFixed(pr), 5731 }, 5732 State: s, 5733 Destroy: true, 5734 }) 5735 5736 if _, err := ctx.Plan(); err != nil { 5737 t.Fatalf("err: %s", err) 5738 } 5739 5740 state, err := ctx.Apply() 5741 if err != nil { 5742 t.Fatalf("err: %s", err) 5743 } 5744 5745 if called { 5746 t.Fatal("provisioner should not be called") 5747 } 5748 5749 actual := strings.TrimSpace(state.String()) 5750 expected := strings.TrimSpace("<no state>") 5751 if actual != expected { 5752 t.Fatalf("bad: \n%s", actual) 5753 } 5754 } 5755 5756 func TestContext2Apply_error(t *testing.T) { 5757 errored := false 5758 5759 m := testModule(t, "apply-error") 5760 p := testProvider("aws") 5761 ctx := testContext2(t, &ContextOpts{ 5762 Module: m, 5763 Providers: map[string]ResourceProviderFactory{ 5764 "aws": testProviderFuncFixed(p), 5765 }, 5766 }) 5767 5768 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 5769 if errored { 5770 state := &InstanceState{ 5771 ID: "bar", 5772 } 5773 return state, fmt.Errorf("error") 5774 } 5775 errored = true 5776 5777 return &InstanceState{ 5778 ID: "foo", 5779 Attributes: map[string]string{ 5780 "num": "2", 5781 }, 5782 }, nil 5783 } 5784 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5785 return &InstanceDiff{ 5786 Attributes: map[string]*ResourceAttrDiff{ 5787 "num": &ResourceAttrDiff{ 5788 New: "bar", 5789 }, 5790 }, 5791 }, nil 5792 } 5793 5794 if _, err := ctx.Plan(); err != nil { 5795 t.Fatalf("err: %s", err) 5796 } 5797 5798 state, err := ctx.Apply() 5799 if err == nil { 5800 t.Fatal("should have error") 5801 } 5802 5803 actual := strings.TrimSpace(state.String()) 5804 expected := strings.TrimSpace(testTerraformApplyErrorStr) 5805 if actual != expected { 5806 t.Fatalf("bad: \n%s", actual) 5807 } 5808 } 5809 5810 func TestContext2Apply_errorPartial(t *testing.T) { 5811 errored := false 5812 5813 m := testModule(t, "apply-error") 5814 p := testProvider("aws") 5815 s := &State{ 5816 Modules: []*ModuleState{ 5817 &ModuleState{ 5818 Path: rootModulePath, 5819 Resources: map[string]*ResourceState{ 5820 "aws_instance.bar": &ResourceState{ 5821 Type: "aws_instance", 5822 Primary: &InstanceState{ 5823 ID: "bar", 5824 }, 5825 }, 5826 }, 5827 }, 5828 }, 5829 } 5830 ctx := testContext2(t, &ContextOpts{ 5831 Module: m, 5832 Providers: map[string]ResourceProviderFactory{ 5833 "aws": testProviderFuncFixed(p), 5834 }, 5835 State: s, 5836 }) 5837 5838 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5839 if errored { 5840 return s, fmt.Errorf("error") 5841 } 5842 errored = true 5843 5844 return &InstanceState{ 5845 ID: "foo", 5846 Attributes: map[string]string{ 5847 "num": "2", 5848 }, 5849 }, nil 5850 } 5851 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5852 return &InstanceDiff{ 5853 Attributes: map[string]*ResourceAttrDiff{ 5854 "num": &ResourceAttrDiff{ 5855 New: "bar", 5856 }, 5857 }, 5858 }, nil 5859 } 5860 5861 if _, err := ctx.Plan(); err != nil { 5862 t.Fatalf("err: %s", err) 5863 } 5864 5865 state, err := ctx.Apply() 5866 if err == nil { 5867 t.Fatal("should have error") 5868 } 5869 5870 mod := state.RootModule() 5871 if len(mod.Resources) != 2 { 5872 t.Fatalf("bad: %#v", mod.Resources) 5873 } 5874 5875 actual := strings.TrimSpace(state.String()) 5876 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 5877 if actual != expected { 5878 t.Fatalf("bad: \n%s", actual) 5879 } 5880 } 5881 5882 func TestContext2Apply_hook(t *testing.T) { 5883 m := testModule(t, "apply-good") 5884 h := new(MockHook) 5885 p := testProvider("aws") 5886 p.ApplyFn = testApplyFn 5887 p.DiffFn = testDiffFn 5888 ctx := testContext2(t, &ContextOpts{ 5889 Module: m, 5890 Hooks: []Hook{h}, 5891 Providers: map[string]ResourceProviderFactory{ 5892 "aws": testProviderFuncFixed(p), 5893 }, 5894 }) 5895 5896 if _, err := ctx.Plan(); err != nil { 5897 t.Fatalf("err: %s", err) 5898 } 5899 5900 if _, err := ctx.Apply(); err != nil { 5901 t.Fatalf("err: %s", err) 5902 } 5903 5904 if !h.PreApplyCalled { 5905 t.Fatal("should be called") 5906 } 5907 if !h.PostApplyCalled { 5908 t.Fatal("should be called") 5909 } 5910 if !h.PostStateUpdateCalled { 5911 t.Fatalf("should call post state update") 5912 } 5913 } 5914 5915 func TestContext2Apply_hookOrphan(t *testing.T) { 5916 m := testModule(t, "apply-blank") 5917 h := new(MockHook) 5918 p := testProvider("aws") 5919 p.ApplyFn = testApplyFn 5920 p.DiffFn = testDiffFn 5921 5922 state := &State{ 5923 Modules: []*ModuleState{ 5924 &ModuleState{ 5925 Path: rootModulePath, 5926 Resources: map[string]*ResourceState{ 5927 "aws_instance.bar": &ResourceState{ 5928 Type: "aws_instance", 5929 Primary: &InstanceState{ 5930 ID: "bar", 5931 }, 5932 }, 5933 }, 5934 }, 5935 }, 5936 } 5937 5938 ctx := testContext2(t, &ContextOpts{ 5939 Module: m, 5940 State: state, 5941 Hooks: []Hook{h}, 5942 Providers: map[string]ResourceProviderFactory{ 5943 "aws": testProviderFuncFixed(p), 5944 }, 5945 }) 5946 5947 if _, err := ctx.Plan(); err != nil { 5948 t.Fatalf("err: %s", err) 5949 } 5950 5951 if _, err := ctx.Apply(); err != nil { 5952 t.Fatalf("err: %s", err) 5953 } 5954 5955 if !h.PreApplyCalled { 5956 t.Fatal("should be called") 5957 } 5958 if !h.PostApplyCalled { 5959 t.Fatal("should be called") 5960 } 5961 if !h.PostStateUpdateCalled { 5962 t.Fatalf("should call post state update") 5963 } 5964 } 5965 5966 func TestContext2Apply_idAttr(t *testing.T) { 5967 m := testModule(t, "apply-idattr") 5968 p := testProvider("aws") 5969 ctx := testContext2(t, &ContextOpts{ 5970 Module: m, 5971 Providers: map[string]ResourceProviderFactory{ 5972 "aws": testProviderFuncFixed(p), 5973 }, 5974 }) 5975 5976 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5977 result := s.MergeDiff(d) 5978 result.ID = "foo" 5979 result.Attributes = map[string]string{ 5980 "id": "bar", 5981 } 5982 5983 return result, nil 5984 } 5985 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5986 return &InstanceDiff{ 5987 Attributes: map[string]*ResourceAttrDiff{ 5988 "num": &ResourceAttrDiff{ 5989 New: "bar", 5990 }, 5991 }, 5992 }, nil 5993 } 5994 5995 if _, err := ctx.Plan(); err != nil { 5996 t.Fatalf("err: %s", err) 5997 } 5998 5999 state, err := ctx.Apply() 6000 if err != nil { 6001 t.Fatalf("err: %s", err) 6002 } 6003 6004 mod := state.RootModule() 6005 rs, ok := mod.Resources["aws_instance.foo"] 6006 if !ok { 6007 t.Fatal("not in state") 6008 } 6009 if rs.Primary.ID != "foo" { 6010 t.Fatalf("bad: %#v", rs.Primary.ID) 6011 } 6012 if rs.Primary.Attributes["id"] != "foo" { 6013 t.Fatalf("bad: %#v", rs.Primary.Attributes) 6014 } 6015 } 6016 6017 func TestContext2Apply_outputBasic(t *testing.T) { 6018 m := testModule(t, "apply-output") 6019 p := testProvider("aws") 6020 p.ApplyFn = testApplyFn 6021 p.DiffFn = testDiffFn 6022 ctx := testContext2(t, &ContextOpts{ 6023 Module: m, 6024 Providers: map[string]ResourceProviderFactory{ 6025 "aws": testProviderFuncFixed(p), 6026 }, 6027 }) 6028 6029 if _, err := ctx.Plan(); err != nil { 6030 t.Fatalf("err: %s", err) 6031 } 6032 6033 state, err := ctx.Apply() 6034 if err != nil { 6035 t.Fatalf("err: %s", err) 6036 } 6037 6038 actual := strings.TrimSpace(state.String()) 6039 expected := strings.TrimSpace(testTerraformApplyOutputStr) 6040 if actual != expected { 6041 t.Fatalf("bad: \n%s", actual) 6042 } 6043 } 6044 6045 func TestContext2Apply_outputInvalid(t *testing.T) { 6046 m := testModule(t, "apply-output-invalid") 6047 p := testProvider("aws") 6048 p.ApplyFn = testApplyFn 6049 p.DiffFn = testDiffFn 6050 ctx := testContext2(t, &ContextOpts{ 6051 Module: m, 6052 Providers: map[string]ResourceProviderFactory{ 6053 "aws": testProviderFuncFixed(p), 6054 }, 6055 }) 6056 6057 _, err := ctx.Plan() 6058 if err == nil { 6059 t.Fatalf("err: %s", err) 6060 } 6061 if !strings.Contains(err.Error(), "is not a valid type") { 6062 t.Fatalf("err: %s", err) 6063 } 6064 } 6065 6066 func TestContext2Apply_outputAdd(t *testing.T) { 6067 m1 := testModule(t, "apply-output-add-before") 6068 p1 := testProvider("aws") 6069 p1.ApplyFn = testApplyFn 6070 p1.DiffFn = testDiffFn 6071 ctx1 := testContext2(t, &ContextOpts{ 6072 Module: m1, 6073 Providers: map[string]ResourceProviderFactory{ 6074 "aws": testProviderFuncFixed(p1), 6075 }, 6076 }) 6077 6078 if _, err := ctx1.Plan(); err != nil { 6079 t.Fatalf("err: %s", err) 6080 } 6081 6082 state1, err := ctx1.Apply() 6083 if err != nil { 6084 t.Fatalf("err: %s", err) 6085 } 6086 6087 m2 := testModule(t, "apply-output-add-after") 6088 p2 := testProvider("aws") 6089 p2.ApplyFn = testApplyFn 6090 p2.DiffFn = testDiffFn 6091 ctx2 := testContext2(t, &ContextOpts{ 6092 Module: m2, 6093 Providers: map[string]ResourceProviderFactory{ 6094 "aws": testProviderFuncFixed(p2), 6095 }, 6096 State: state1, 6097 }) 6098 6099 if _, err := ctx2.Plan(); err != nil { 6100 t.Fatalf("err: %s", err) 6101 } 6102 6103 state2, err := ctx2.Apply() 6104 if err != nil { 6105 t.Fatalf("err: %s", err) 6106 } 6107 6108 actual := strings.TrimSpace(state2.String()) 6109 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 6110 if actual != expected { 6111 t.Fatalf("bad: \n%s", actual) 6112 } 6113 } 6114 6115 func TestContext2Apply_outputList(t *testing.T) { 6116 m := testModule(t, "apply-output-list") 6117 p := testProvider("aws") 6118 p.ApplyFn = testApplyFn 6119 p.DiffFn = testDiffFn 6120 ctx := testContext2(t, &ContextOpts{ 6121 Module: m, 6122 Providers: map[string]ResourceProviderFactory{ 6123 "aws": testProviderFuncFixed(p), 6124 }, 6125 }) 6126 6127 if _, err := ctx.Plan(); err != nil { 6128 t.Fatalf("err: %s", err) 6129 } 6130 6131 state, err := ctx.Apply() 6132 if err != nil { 6133 t.Fatalf("err: %s", err) 6134 } 6135 6136 actual := strings.TrimSpace(state.String()) 6137 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 6138 if actual != expected { 6139 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 6140 } 6141 } 6142 6143 func TestContext2Apply_outputMulti(t *testing.T) { 6144 m := testModule(t, "apply-output-multi") 6145 p := testProvider("aws") 6146 p.ApplyFn = testApplyFn 6147 p.DiffFn = testDiffFn 6148 ctx := testContext2(t, &ContextOpts{ 6149 Module: m, 6150 Providers: map[string]ResourceProviderFactory{ 6151 "aws": testProviderFuncFixed(p), 6152 }, 6153 }) 6154 6155 if _, err := ctx.Plan(); err != nil { 6156 t.Fatalf("err: %s", err) 6157 } 6158 6159 state, err := ctx.Apply() 6160 if err != nil { 6161 t.Fatalf("err: %s", err) 6162 } 6163 6164 actual := strings.TrimSpace(state.String()) 6165 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 6166 if actual != expected { 6167 t.Fatalf("bad: \n%s", actual) 6168 } 6169 } 6170 6171 func TestContext2Apply_outputMultiIndex(t *testing.T) { 6172 m := testModule(t, "apply-output-multi-index") 6173 p := testProvider("aws") 6174 p.ApplyFn = testApplyFn 6175 p.DiffFn = testDiffFn 6176 ctx := testContext2(t, &ContextOpts{ 6177 Module: m, 6178 Providers: map[string]ResourceProviderFactory{ 6179 "aws": testProviderFuncFixed(p), 6180 }, 6181 }) 6182 6183 if _, err := ctx.Plan(); err != nil { 6184 t.Fatalf("err: %s", err) 6185 } 6186 6187 state, err := ctx.Apply() 6188 if err != nil { 6189 t.Fatalf("err: %s", err) 6190 } 6191 6192 actual := strings.TrimSpace(state.String()) 6193 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 6194 if actual != expected { 6195 t.Fatalf("bad: \n%s", actual) 6196 } 6197 } 6198 6199 func TestContext2Apply_taintX(t *testing.T) { 6200 m := testModule(t, "apply-taint") 6201 p := testProvider("aws") 6202 6203 // destroyCount tests against regression of 6204 // https://github.com/hashicorp/terraform/issues/1056 6205 var destroyCount = int32(0) 6206 var once sync.Once 6207 simulateProviderDelay := func() { 6208 time.Sleep(10 * time.Millisecond) 6209 } 6210 6211 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6212 once.Do(simulateProviderDelay) 6213 if d.Destroy { 6214 atomic.AddInt32(&destroyCount, 1) 6215 } 6216 return testApplyFn(info, s, d) 6217 } 6218 p.DiffFn = testDiffFn 6219 s := &State{ 6220 Modules: []*ModuleState{ 6221 &ModuleState{ 6222 Path: rootModulePath, 6223 Resources: map[string]*ResourceState{ 6224 "aws_instance.bar": &ResourceState{ 6225 Type: "aws_instance", 6226 Primary: &InstanceState{ 6227 ID: "baz", 6228 Attributes: map[string]string{ 6229 "num": "2", 6230 "type": "aws_instance", 6231 }, 6232 Tainted: true, 6233 }, 6234 }, 6235 }, 6236 }, 6237 }, 6238 } 6239 ctx := testContext2(t, &ContextOpts{ 6240 Module: m, 6241 Providers: map[string]ResourceProviderFactory{ 6242 "aws": testProviderFuncFixed(p), 6243 }, 6244 State: s, 6245 }) 6246 6247 if p, err := ctx.Plan(); err != nil { 6248 t.Fatalf("err: %s", err) 6249 } else { 6250 t.Logf("plan: %s", p) 6251 } 6252 6253 state, err := ctx.Apply() 6254 if err != nil { 6255 t.Fatalf("err: %s", err) 6256 } 6257 6258 actual := strings.TrimSpace(state.String()) 6259 expected := strings.TrimSpace(testTerraformApplyTaintStr) 6260 if actual != expected { 6261 t.Fatalf("bad:\n%s", actual) 6262 } 6263 6264 if destroyCount != 1 { 6265 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 6266 } 6267 } 6268 6269 func TestContext2Apply_taintDep(t *testing.T) { 6270 m := testModule(t, "apply-taint-dep") 6271 p := testProvider("aws") 6272 p.ApplyFn = testApplyFn 6273 p.DiffFn = testDiffFn 6274 s := &State{ 6275 Modules: []*ModuleState{ 6276 &ModuleState{ 6277 Path: rootModulePath, 6278 Resources: map[string]*ResourceState{ 6279 "aws_instance.foo": &ResourceState{ 6280 Type: "aws_instance", 6281 Primary: &InstanceState{ 6282 ID: "baz", 6283 Attributes: map[string]string{ 6284 "num": "2", 6285 "type": "aws_instance", 6286 }, 6287 Tainted: true, 6288 }, 6289 }, 6290 "aws_instance.bar": &ResourceState{ 6291 Type: "aws_instance", 6292 Primary: &InstanceState{ 6293 ID: "bar", 6294 Attributes: map[string]string{ 6295 "foo": "baz", 6296 "num": "2", 6297 "type": "aws_instance", 6298 }, 6299 }, 6300 }, 6301 }, 6302 }, 6303 }, 6304 } 6305 ctx := testContext2(t, &ContextOpts{ 6306 Module: m, 6307 Providers: map[string]ResourceProviderFactory{ 6308 "aws": testProviderFuncFixed(p), 6309 }, 6310 State: s, 6311 }) 6312 6313 if p, err := ctx.Plan(); err != nil { 6314 t.Fatalf("err: %s", err) 6315 } else { 6316 t.Logf("plan: %s", p) 6317 } 6318 6319 state, err := ctx.Apply() 6320 if err != nil { 6321 t.Fatalf("err: %s", err) 6322 } 6323 6324 actual := strings.TrimSpace(state.String()) 6325 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 6326 if actual != expected { 6327 t.Fatalf("bad:\n%s", actual) 6328 } 6329 } 6330 6331 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 6332 m := testModule(t, "apply-taint-dep-requires-new") 6333 p := testProvider("aws") 6334 p.ApplyFn = testApplyFn 6335 p.DiffFn = testDiffFn 6336 s := &State{ 6337 Modules: []*ModuleState{ 6338 &ModuleState{ 6339 Path: rootModulePath, 6340 Resources: map[string]*ResourceState{ 6341 "aws_instance.foo": &ResourceState{ 6342 Type: "aws_instance", 6343 Primary: &InstanceState{ 6344 ID: "baz", 6345 Attributes: map[string]string{ 6346 "num": "2", 6347 "type": "aws_instance", 6348 }, 6349 Tainted: true, 6350 }, 6351 }, 6352 "aws_instance.bar": &ResourceState{ 6353 Type: "aws_instance", 6354 Primary: &InstanceState{ 6355 ID: "bar", 6356 Attributes: map[string]string{ 6357 "foo": "baz", 6358 "num": "2", 6359 "type": "aws_instance", 6360 }, 6361 }, 6362 }, 6363 }, 6364 }, 6365 }, 6366 } 6367 ctx := testContext2(t, &ContextOpts{ 6368 Module: m, 6369 Providers: map[string]ResourceProviderFactory{ 6370 "aws": testProviderFuncFixed(p), 6371 }, 6372 State: s, 6373 }) 6374 6375 if p, err := ctx.Plan(); err != nil { 6376 t.Fatalf("err: %s", err) 6377 } else { 6378 t.Logf("plan: %s", p) 6379 } 6380 6381 state, err := ctx.Apply() 6382 if err != nil { 6383 t.Fatalf("err: %s", err) 6384 } 6385 6386 actual := strings.TrimSpace(state.String()) 6387 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 6388 if actual != expected { 6389 t.Fatalf("bad:\n%s", actual) 6390 } 6391 } 6392 6393 func TestContext2Apply_targeted(t *testing.T) { 6394 m := testModule(t, "apply-targeted") 6395 p := testProvider("aws") 6396 p.ApplyFn = testApplyFn 6397 p.DiffFn = testDiffFn 6398 ctx := testContext2(t, &ContextOpts{ 6399 Module: m, 6400 Providers: map[string]ResourceProviderFactory{ 6401 "aws": testProviderFuncFixed(p), 6402 }, 6403 Targets: []string{"aws_instance.foo"}, 6404 }) 6405 6406 if _, err := ctx.Plan(); err != nil { 6407 t.Fatalf("err: %s", err) 6408 } 6409 6410 state, err := ctx.Apply() 6411 if err != nil { 6412 t.Fatalf("err: %s", err) 6413 } 6414 6415 mod := state.RootModule() 6416 if len(mod.Resources) != 1 { 6417 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 6418 } 6419 6420 checkStateString(t, state, ` 6421 aws_instance.foo: 6422 ID = foo 6423 num = 2 6424 type = aws_instance 6425 `) 6426 } 6427 6428 func TestContext2Apply_targetedCount(t *testing.T) { 6429 m := testModule(t, "apply-targeted-count") 6430 p := testProvider("aws") 6431 p.ApplyFn = testApplyFn 6432 p.DiffFn = testDiffFn 6433 ctx := testContext2(t, &ContextOpts{ 6434 Module: m, 6435 Providers: map[string]ResourceProviderFactory{ 6436 "aws": testProviderFuncFixed(p), 6437 }, 6438 Targets: []string{"aws_instance.foo"}, 6439 }) 6440 6441 if _, err := ctx.Plan(); err != nil { 6442 t.Fatalf("err: %s", err) 6443 } 6444 6445 state, err := ctx.Apply() 6446 if err != nil { 6447 t.Fatalf("err: %s", err) 6448 } 6449 6450 checkStateString(t, state, ` 6451 aws_instance.foo.0: 6452 ID = foo 6453 aws_instance.foo.1: 6454 ID = foo 6455 aws_instance.foo.2: 6456 ID = foo 6457 `) 6458 } 6459 6460 func TestContext2Apply_targetedCountIndex(t *testing.T) { 6461 m := testModule(t, "apply-targeted-count") 6462 p := testProvider("aws") 6463 p.ApplyFn = testApplyFn 6464 p.DiffFn = testDiffFn 6465 ctx := testContext2(t, &ContextOpts{ 6466 Module: m, 6467 Providers: map[string]ResourceProviderFactory{ 6468 "aws": testProviderFuncFixed(p), 6469 }, 6470 Targets: []string{"aws_instance.foo[1]"}, 6471 }) 6472 6473 if _, err := ctx.Plan(); err != nil { 6474 t.Fatalf("err: %s", err) 6475 } 6476 6477 state, err := ctx.Apply() 6478 if err != nil { 6479 t.Fatalf("err: %s", err) 6480 } 6481 6482 checkStateString(t, state, ` 6483 aws_instance.foo.1: 6484 ID = foo 6485 `) 6486 } 6487 6488 func TestContext2Apply_targetedDestroy(t *testing.T) { 6489 m := testModule(t, "apply-targeted") 6490 p := testProvider("aws") 6491 p.ApplyFn = testApplyFn 6492 p.DiffFn = testDiffFn 6493 ctx := testContext2(t, &ContextOpts{ 6494 Module: m, 6495 Providers: map[string]ResourceProviderFactory{ 6496 "aws": testProviderFuncFixed(p), 6497 }, 6498 State: &State{ 6499 Modules: []*ModuleState{ 6500 &ModuleState{ 6501 Path: rootModulePath, 6502 Resources: map[string]*ResourceState{ 6503 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6504 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6505 }, 6506 }, 6507 }, 6508 }, 6509 Targets: []string{"aws_instance.foo"}, 6510 Destroy: true, 6511 }) 6512 6513 if _, err := ctx.Plan(); err != nil { 6514 t.Fatalf("err: %s", err) 6515 } 6516 6517 state, err := ctx.Apply() 6518 if err != nil { 6519 t.Fatalf("err: %s", err) 6520 } 6521 6522 mod := state.RootModule() 6523 if len(mod.Resources) != 1 { 6524 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 6525 } 6526 6527 checkStateString(t, state, ` 6528 aws_instance.bar: 6529 ID = i-abc123 6530 `) 6531 } 6532 6533 func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) { 6534 m := testModule(t, "apply-destroy-targeted-count") 6535 p := testProvider("aws") 6536 p.ApplyFn = testApplyFn 6537 p.DiffFn = testDiffFn 6538 ctx := testContext2(t, &ContextOpts{ 6539 Module: m, 6540 Providers: map[string]ResourceProviderFactory{ 6541 "aws": testProviderFuncFixed(p), 6542 }, 6543 State: &State{ 6544 Modules: []*ModuleState{ 6545 &ModuleState{ 6546 Path: rootModulePath, 6547 Resources: map[string]*ResourceState{ 6548 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6549 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6550 }, 6551 }, 6552 }, 6553 }, 6554 Targets: []string{"aws_instance.foo"}, 6555 Destroy: true, 6556 }) 6557 6558 if _, err := ctx.Plan(); err != nil { 6559 t.Fatalf("err: %s", err) 6560 } 6561 6562 state, err := ctx.Apply() 6563 if err != nil { 6564 t.Fatalf("err: %s", err) 6565 } 6566 6567 checkStateString(t, state, `<no state>`) 6568 } 6569 6570 // https://github.com/hashicorp/terraform/issues/4462 6571 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 6572 m := testModule(t, "apply-targeted-module") 6573 p := testProvider("aws") 6574 p.ApplyFn = testApplyFn 6575 p.DiffFn = testDiffFn 6576 ctx := testContext2(t, &ContextOpts{ 6577 Module: m, 6578 Providers: map[string]ResourceProviderFactory{ 6579 "aws": testProviderFuncFixed(p), 6580 }, 6581 State: &State{ 6582 Modules: []*ModuleState{ 6583 &ModuleState{ 6584 Path: rootModulePath, 6585 Resources: map[string]*ResourceState{ 6586 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6587 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6588 }, 6589 }, 6590 &ModuleState{ 6591 Path: []string{"root", "child"}, 6592 Resources: map[string]*ResourceState{ 6593 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6594 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6595 }, 6596 }, 6597 }, 6598 }, 6599 Targets: []string{"module.child.aws_instance.foo"}, 6600 Destroy: true, 6601 }) 6602 6603 if _, err := ctx.Plan(); err != nil { 6604 t.Fatalf("err: %s", err) 6605 } 6606 6607 state, err := ctx.Apply() 6608 if err != nil { 6609 t.Fatalf("err: %s", err) 6610 } 6611 6612 checkStateString(t, state, ` 6613 aws_instance.bar: 6614 ID = i-abc123 6615 aws_instance.foo: 6616 ID = i-bcd345 6617 6618 module.child: 6619 aws_instance.bar: 6620 ID = i-abc123 6621 `) 6622 } 6623 6624 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 6625 m := testModule(t, "apply-targeted-count") 6626 p := testProvider("aws") 6627 p.ApplyFn = testApplyFn 6628 p.DiffFn = testDiffFn 6629 ctx := testContext2(t, &ContextOpts{ 6630 Module: m, 6631 Providers: map[string]ResourceProviderFactory{ 6632 "aws": testProviderFuncFixed(p), 6633 }, 6634 State: &State{ 6635 Modules: []*ModuleState{ 6636 &ModuleState{ 6637 Path: rootModulePath, 6638 Resources: map[string]*ResourceState{ 6639 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 6640 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 6641 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 6642 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 6643 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 6644 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 6645 }, 6646 }, 6647 }, 6648 }, 6649 Targets: []string{ 6650 "aws_instance.foo[2]", 6651 "aws_instance.bar[1]", 6652 }, 6653 Destroy: true, 6654 }) 6655 6656 if _, err := ctx.Plan(); err != nil { 6657 t.Fatalf("err: %s", err) 6658 } 6659 6660 state, err := ctx.Apply() 6661 if err != nil { 6662 t.Fatalf("err: %s", err) 6663 } 6664 6665 checkStateString(t, state, ` 6666 aws_instance.bar.0: 6667 ID = i-abc123 6668 aws_instance.bar.2: 6669 ID = i-abc123 6670 aws_instance.foo.0: 6671 ID = i-bcd345 6672 aws_instance.foo.1: 6673 ID = i-bcd345 6674 `) 6675 } 6676 6677 func TestContext2Apply_targetedModule(t *testing.T) { 6678 m := testModule(t, "apply-targeted-module") 6679 p := testProvider("aws") 6680 p.ApplyFn = testApplyFn 6681 p.DiffFn = testDiffFn 6682 ctx := testContext2(t, &ContextOpts{ 6683 Module: m, 6684 Providers: map[string]ResourceProviderFactory{ 6685 "aws": testProviderFuncFixed(p), 6686 }, 6687 Targets: []string{"module.child"}, 6688 }) 6689 6690 if _, err := ctx.Plan(); err != nil { 6691 t.Fatalf("err: %s", err) 6692 } 6693 6694 state, err := ctx.Apply() 6695 if err != nil { 6696 t.Fatalf("err: %s", err) 6697 } 6698 6699 mod := state.ModuleByPath([]string{"root", "child"}) 6700 if mod == nil { 6701 t.Fatalf("no child module found in the state!\n\n%#v", state) 6702 } 6703 if len(mod.Resources) != 2 { 6704 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 6705 } 6706 6707 checkStateString(t, state, ` 6708 <no state> 6709 module.child: 6710 aws_instance.bar: 6711 ID = foo 6712 num = 2 6713 type = aws_instance 6714 aws_instance.foo: 6715 ID = foo 6716 num = 2 6717 type = aws_instance 6718 `) 6719 } 6720 6721 // GH-1858 6722 func TestContext2Apply_targetedModuleDep(t *testing.T) { 6723 m := testModule(t, "apply-targeted-module-dep") 6724 p := testProvider("aws") 6725 p.ApplyFn = testApplyFn 6726 p.DiffFn = testDiffFn 6727 ctx := testContext2(t, &ContextOpts{ 6728 Module: m, 6729 Providers: map[string]ResourceProviderFactory{ 6730 "aws": testProviderFuncFixed(p), 6731 }, 6732 Targets: []string{"aws_instance.foo"}, 6733 }) 6734 6735 if p, err := ctx.Plan(); err != nil { 6736 t.Fatalf("err: %s", err) 6737 } else { 6738 t.Logf("Diff: %s", p) 6739 } 6740 6741 state, err := ctx.Apply() 6742 if err != nil { 6743 t.Fatalf("err: %s", err) 6744 } 6745 6746 checkStateString(t, state, ` 6747 aws_instance.foo: 6748 ID = foo 6749 foo = foo 6750 type = aws_instance 6751 6752 Dependencies: 6753 module.child 6754 6755 module.child: 6756 aws_instance.mod: 6757 ID = foo 6758 6759 Outputs: 6760 6761 output = foo 6762 `) 6763 } 6764 6765 func TestContext2Apply_targetedModuleResource(t *testing.T) { 6766 m := testModule(t, "apply-targeted-module-resource") 6767 p := testProvider("aws") 6768 p.ApplyFn = testApplyFn 6769 p.DiffFn = testDiffFn 6770 ctx := testContext2(t, &ContextOpts{ 6771 Module: m, 6772 Providers: map[string]ResourceProviderFactory{ 6773 "aws": testProviderFuncFixed(p), 6774 }, 6775 Targets: []string{"module.child.aws_instance.foo"}, 6776 }) 6777 6778 if _, err := ctx.Plan(); err != nil { 6779 t.Fatalf("err: %s", err) 6780 } 6781 6782 state, err := ctx.Apply() 6783 if err != nil { 6784 t.Fatalf("err: %s", err) 6785 } 6786 6787 mod := state.ModuleByPath([]string{"root", "child"}) 6788 if mod == nil || len(mod.Resources) != 1 { 6789 t.Fatalf("expected 1 resource, got: %#v", mod) 6790 } 6791 6792 checkStateString(t, state, ` 6793 <no state> 6794 module.child: 6795 aws_instance.foo: 6796 ID = foo 6797 num = 2 6798 type = aws_instance 6799 `) 6800 } 6801 6802 func TestContext2Apply_unknownAttribute(t *testing.T) { 6803 m := testModule(t, "apply-unknown") 6804 p := testProvider("aws") 6805 p.ApplyFn = testApplyFn 6806 p.DiffFn = testDiffFn 6807 ctx := testContext2(t, &ContextOpts{ 6808 Module: m, 6809 Providers: map[string]ResourceProviderFactory{ 6810 "aws": testProviderFuncFixed(p), 6811 }, 6812 }) 6813 6814 if _, err := ctx.Plan(); err != nil { 6815 t.Fatalf("err: %s", err) 6816 } 6817 6818 state, err := ctx.Apply() 6819 if err == nil { 6820 t.Fatal("should error") 6821 } 6822 6823 actual := strings.TrimSpace(state.String()) 6824 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 6825 if actual != expected { 6826 t.Fatalf("bad: \n%s", actual) 6827 } 6828 } 6829 6830 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 6831 m := testModule(t, "apply-unknown-interpolate") 6832 p := testProvider("aws") 6833 p.ApplyFn = testApplyFn 6834 p.DiffFn = testDiffFn 6835 ctx := testContext2(t, &ContextOpts{ 6836 Module: m, 6837 Providers: map[string]ResourceProviderFactory{ 6838 "aws": testProviderFuncFixed(p), 6839 }, 6840 }) 6841 6842 if _, err := ctx.Plan(); err == nil { 6843 t.Fatal("should error") 6844 } 6845 } 6846 6847 func TestContext2Apply_vars(t *testing.T) { 6848 m := testModule(t, "apply-vars") 6849 p := testProvider("aws") 6850 p.ApplyFn = testApplyFn 6851 p.DiffFn = testDiffFn 6852 ctx := testContext2(t, &ContextOpts{ 6853 Module: m, 6854 Providers: map[string]ResourceProviderFactory{ 6855 "aws": testProviderFuncFixed(p), 6856 }, 6857 Variables: map[string]interface{}{ 6858 "foo": "us-west-2", 6859 "test_list": []interface{}{"Hello", "World"}, 6860 "test_map": map[string]interface{}{ 6861 "Hello": "World", 6862 "Foo": "Bar", 6863 "Baz": "Foo", 6864 }, 6865 "amis": []map[string]interface{}{ 6866 map[string]interface{}{ 6867 "us-east-1": "override", 6868 }, 6869 }, 6870 }, 6871 }) 6872 6873 w, e := ctx.Validate() 6874 if len(w) > 0 { 6875 t.Fatalf("bad: %#v", w) 6876 } 6877 if len(e) > 0 { 6878 t.Fatalf("bad: %s", e) 6879 } 6880 6881 if _, err := ctx.Plan(); err != nil { 6882 t.Fatalf("err: %s", err) 6883 } 6884 6885 state, err := ctx.Apply() 6886 if err != nil { 6887 t.Fatalf("err: %s", err) 6888 } 6889 6890 actual := strings.TrimSpace(state.String()) 6891 expected := strings.TrimSpace(testTerraformApplyVarsStr) 6892 if actual != expected { 6893 t.Fatalf("expected: %s\n got:\n%s", expected, actual) 6894 } 6895 } 6896 6897 func TestContext2Apply_varsEnv(t *testing.T) { 6898 // Set the env var 6899 defer tempEnv(t, "TF_VAR_ami", "baz")() 6900 defer tempEnv(t, "TF_VAR_list", `["Hello", "World"]`)() 6901 defer tempEnv(t, "TF_VAR_map", `{"Hello" = "World", "Foo" = "Bar", "Baz" = "Foo"}`)() 6902 6903 m := testModule(t, "apply-vars-env") 6904 p := testProvider("aws") 6905 p.ApplyFn = testApplyFn 6906 p.DiffFn = testDiffFn 6907 ctx := testContext2(t, &ContextOpts{ 6908 Module: m, 6909 Providers: map[string]ResourceProviderFactory{ 6910 "aws": testProviderFuncFixed(p), 6911 }, 6912 }) 6913 6914 w, e := ctx.Validate() 6915 if len(w) > 0 { 6916 t.Fatalf("bad: %#v", w) 6917 } 6918 if len(e) > 0 { 6919 t.Fatalf("bad: %s", e) 6920 } 6921 6922 if _, err := ctx.Plan(); err != nil { 6923 t.Fatalf("err: %s", err) 6924 } 6925 6926 state, err := ctx.Apply() 6927 if err != nil { 6928 t.Fatalf("err: %s", err) 6929 } 6930 6931 actual := strings.TrimSpace(state.String()) 6932 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 6933 if actual != expected { 6934 t.Fatalf("bad: \n%s", actual) 6935 } 6936 } 6937 6938 func TestContext2Apply_createBefore_depends(t *testing.T) { 6939 m := testModule(t, "apply-depends-create-before") 6940 h := new(HookRecordApplyOrder) 6941 p := testProvider("aws") 6942 p.ApplyFn = testApplyFn 6943 p.DiffFn = testDiffFn 6944 state := &State{ 6945 Modules: []*ModuleState{ 6946 &ModuleState{ 6947 Path: rootModulePath, 6948 Resources: map[string]*ResourceState{ 6949 "aws_instance.web": &ResourceState{ 6950 Type: "aws_instance", 6951 Primary: &InstanceState{ 6952 ID: "bar", 6953 Attributes: map[string]string{ 6954 "require_new": "ami-old", 6955 }, 6956 }, 6957 }, 6958 "aws_instance.lb": &ResourceState{ 6959 Type: "aws_instance", 6960 Primary: &InstanceState{ 6961 ID: "baz", 6962 Attributes: map[string]string{ 6963 "instance": "bar", 6964 }, 6965 }, 6966 }, 6967 }, 6968 }, 6969 }, 6970 } 6971 ctx := testContext2(t, &ContextOpts{ 6972 Module: m, 6973 Hooks: []Hook{h}, 6974 Providers: map[string]ResourceProviderFactory{ 6975 "aws": testProviderFuncFixed(p), 6976 }, 6977 State: state, 6978 }) 6979 6980 if p, err := ctx.Plan(); err != nil { 6981 t.Fatalf("err: %s", err) 6982 } else { 6983 t.Logf("plan: %s", p) 6984 } 6985 6986 h.Active = true 6987 state, err := ctx.Apply() 6988 if err != nil { 6989 t.Fatalf("err: %s", err) 6990 } 6991 6992 mod := state.RootModule() 6993 if len(mod.Resources) < 2 { 6994 t.Fatalf("bad: %#v", mod.Resources) 6995 } 6996 6997 actual := strings.TrimSpace(state.String()) 6998 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 6999 if actual != expected { 7000 t.Fatalf("bad: \n%s\n\n%s", actual, expected) 7001 } 7002 7003 // Test that things were managed _in the right order_ 7004 order := h.States 7005 diffs := h.Diffs 7006 if order[0].ID != "" || diffs[0].Destroy { 7007 t.Fatalf("should create new instance first: %#v", order) 7008 } 7009 7010 if order[1].ID != "baz" { 7011 t.Fatalf("update must happen after create: %#v", order) 7012 } 7013 7014 if order[2].ID != "bar" || !diffs[2].Destroy { 7015 t.Fatalf("destroy must happen after update: %#v", order) 7016 } 7017 } 7018 7019 func TestContext2Apply_singleDestroy(t *testing.T) { 7020 m := testModule(t, "apply-depends-create-before") 7021 h := new(HookRecordApplyOrder) 7022 p := testProvider("aws") 7023 7024 invokeCount := 0 7025 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 7026 invokeCount++ 7027 switch invokeCount { 7028 case 1: 7029 if d.Destroy { 7030 t.Fatalf("should not destroy") 7031 } 7032 if s.ID != "" { 7033 t.Fatalf("should not have ID") 7034 } 7035 case 2: 7036 if d.Destroy { 7037 t.Fatalf("should not destroy") 7038 } 7039 if s.ID != "baz" { 7040 t.Fatalf("should have id") 7041 } 7042 case 3: 7043 if !d.Destroy { 7044 t.Fatalf("should destroy") 7045 } 7046 if s.ID == "" { 7047 t.Fatalf("should have ID") 7048 } 7049 default: 7050 t.Fatalf("bad invoke count %d", invokeCount) 7051 } 7052 return testApplyFn(info, s, d) 7053 } 7054 p.DiffFn = testDiffFn 7055 state := &State{ 7056 Modules: []*ModuleState{ 7057 &ModuleState{ 7058 Path: rootModulePath, 7059 Resources: map[string]*ResourceState{ 7060 "aws_instance.web": &ResourceState{ 7061 Type: "aws_instance", 7062 Primary: &InstanceState{ 7063 ID: "bar", 7064 Attributes: map[string]string{ 7065 "require_new": "ami-old", 7066 }, 7067 }, 7068 }, 7069 "aws_instance.lb": &ResourceState{ 7070 Type: "aws_instance", 7071 Primary: &InstanceState{ 7072 ID: "baz", 7073 Attributes: map[string]string{ 7074 "instance": "bar", 7075 }, 7076 }, 7077 }, 7078 }, 7079 }, 7080 }, 7081 } 7082 ctx := testContext2(t, &ContextOpts{ 7083 Module: m, 7084 Hooks: []Hook{h}, 7085 Providers: map[string]ResourceProviderFactory{ 7086 "aws": testProviderFuncFixed(p), 7087 }, 7088 State: state, 7089 }) 7090 7091 if _, err := ctx.Plan(); err != nil { 7092 t.Fatalf("err: %s", err) 7093 } 7094 7095 h.Active = true 7096 state, err := ctx.Apply() 7097 if err != nil { 7098 t.Fatalf("err: %s", err) 7099 } 7100 7101 if invokeCount != 3 { 7102 t.Fatalf("bad: %d", invokeCount) 7103 } 7104 } 7105 7106 // GH-7824 7107 func TestContext2Apply_issue7824(t *testing.T) { 7108 p := testProvider("template") 7109 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 7110 Name: "template_file", 7111 }) 7112 7113 p.ApplyFn = testApplyFn 7114 p.DiffFn = testDiffFn 7115 7116 // Apply cleanly step 0 7117 ctx := testContext2(t, &ContextOpts{ 7118 Module: testModule(t, "issue-7824"), 7119 Providers: map[string]ResourceProviderFactory{ 7120 "template": testProviderFuncFixed(p), 7121 }, 7122 }) 7123 7124 plan, err := ctx.Plan() 7125 if err != nil { 7126 t.Fatalf("err: %s", err) 7127 } 7128 7129 // Write / Read plan to simulate running it through a Plan file 7130 var buf bytes.Buffer 7131 if err := WritePlan(plan, &buf); err != nil { 7132 t.Fatalf("err: %s", err) 7133 } 7134 7135 planFromFile, err := ReadPlan(&buf) 7136 if err != nil { 7137 t.Fatalf("err: %s", err) 7138 } 7139 7140 ctx, err = planFromFile.Context(&ContextOpts{ 7141 Providers: map[string]ResourceProviderFactory{ 7142 "template": testProviderFuncFixed(p), 7143 }, 7144 }) 7145 if err != nil { 7146 t.Fatalf("err: %s", err) 7147 } 7148 7149 _, err = ctx.Apply() 7150 if err != nil { 7151 t.Fatalf("err: %s", err) 7152 } 7153 } 7154 7155 // GH-5254 7156 func TestContext2Apply_issue5254(t *testing.T) { 7157 // Create a provider. We use "template" here just to match the repro 7158 // we got from the issue itself. 7159 p := testProvider("template") 7160 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 7161 Name: "template_file", 7162 }) 7163 7164 p.ApplyFn = testApplyFn 7165 p.DiffFn = testDiffFn 7166 7167 // Apply cleanly step 0 7168 ctx := testContext2(t, &ContextOpts{ 7169 Module: testModule(t, "issue-5254/step-0"), 7170 Providers: map[string]ResourceProviderFactory{ 7171 "template": testProviderFuncFixed(p), 7172 }, 7173 }) 7174 7175 plan, err := ctx.Plan() 7176 if err != nil { 7177 t.Fatalf("err: %s", err) 7178 } 7179 7180 state, err := ctx.Apply() 7181 if err != nil { 7182 t.Fatalf("err: %s", err) 7183 } 7184 7185 // Application success. Now make the modification and store a plan 7186 ctx = testContext2(t, &ContextOpts{ 7187 Module: testModule(t, "issue-5254/step-1"), 7188 State: state, 7189 Providers: map[string]ResourceProviderFactory{ 7190 "template": testProviderFuncFixed(p), 7191 }, 7192 }) 7193 7194 plan, err = ctx.Plan() 7195 if err != nil { 7196 t.Fatalf("err: %s", err) 7197 } 7198 7199 // Write / Read plan to simulate running it through a Plan file 7200 var buf bytes.Buffer 7201 if err := WritePlan(plan, &buf); err != nil { 7202 t.Fatalf("err: %s", err) 7203 } 7204 7205 planFromFile, err := ReadPlan(&buf) 7206 if err != nil { 7207 t.Fatalf("err: %s", err) 7208 } 7209 7210 ctx, err = planFromFile.Context(&ContextOpts{ 7211 Providers: map[string]ResourceProviderFactory{ 7212 "template": testProviderFuncFixed(p), 7213 }, 7214 }) 7215 if err != nil { 7216 t.Fatalf("err: %s", err) 7217 } 7218 7219 state, err = ctx.Apply() 7220 if err != nil { 7221 t.Fatalf("err: %s", err) 7222 } 7223 7224 actual := strings.TrimSpace(state.String()) 7225 expected := strings.TrimSpace(` 7226 template_file.child: 7227 ID = foo 7228 template = Hi 7229 type = template_file 7230 7231 Dependencies: 7232 template_file.parent 7233 template_file.parent: 7234 ID = foo 7235 template = Hi 7236 type = template_file 7237 `) 7238 if actual != expected { 7239 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 7240 } 7241 } 7242 7243 func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { 7244 p := testProvider("aws") 7245 p.DiffFn = testDiffFn 7246 p.ApplyFn = testApplyFn 7247 ctx := testContext2(t, &ContextOpts{ 7248 Module: testModule(t, "apply-tainted-targets"), 7249 Providers: map[string]ResourceProviderFactory{ 7250 "aws": testProviderFuncFixed(p), 7251 }, 7252 Targets: []string{"aws_instance.iambeingadded"}, 7253 State: &State{ 7254 Modules: []*ModuleState{ 7255 &ModuleState{ 7256 Path: rootModulePath, 7257 Resources: map[string]*ResourceState{ 7258 "aws_instance.ifailedprovisioners": &ResourceState{ 7259 Primary: &InstanceState{ 7260 ID: "ifailedprovisioners", 7261 Tainted: true, 7262 }, 7263 }, 7264 }, 7265 }, 7266 }, 7267 }, 7268 }) 7269 7270 plan, err := ctx.Plan() 7271 if err != nil { 7272 t.Fatalf("err: %s", err) 7273 } 7274 7275 // Write / Read plan to simulate running it through a Plan file 7276 var buf bytes.Buffer 7277 if err := WritePlan(plan, &buf); err != nil { 7278 t.Fatalf("err: %s", err) 7279 } 7280 7281 planFromFile, err := ReadPlan(&buf) 7282 if err != nil { 7283 t.Fatalf("err: %s", err) 7284 } 7285 7286 ctx, err = planFromFile.Context(&ContextOpts{ 7287 Module: testModule(t, "apply-tainted-targets"), 7288 Providers: map[string]ResourceProviderFactory{ 7289 "aws": testProviderFuncFixed(p), 7290 }, 7291 }) 7292 if err != nil { 7293 t.Fatalf("err: %s", err) 7294 } 7295 7296 state, err := ctx.Apply() 7297 if err != nil { 7298 t.Fatalf("err: %s", err) 7299 } 7300 7301 actual := strings.TrimSpace(state.String()) 7302 expected := strings.TrimSpace(` 7303 aws_instance.iambeingadded: 7304 ID = foo 7305 aws_instance.ifailedprovisioners: (tainted) 7306 ID = ifailedprovisioners 7307 `) 7308 if actual != expected { 7309 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 7310 } 7311 } 7312 7313 // Higher level test exposing the bug this covers in 7314 // TestResource_ignoreChangesRequired 7315 func TestContext2Apply_ignoreChangesCreate(t *testing.T) { 7316 m := testModule(t, "apply-ignore-changes-create") 7317 p := testProvider("aws") 7318 p.ApplyFn = testApplyFn 7319 p.DiffFn = testDiffFn 7320 ctx := testContext2(t, &ContextOpts{ 7321 Module: m, 7322 Providers: map[string]ResourceProviderFactory{ 7323 "aws": testProviderFuncFixed(p), 7324 }, 7325 }) 7326 7327 if p, err := ctx.Plan(); err != nil { 7328 t.Fatalf("err: %s", err) 7329 } else { 7330 t.Logf(p.String()) 7331 } 7332 7333 state, err := ctx.Apply() 7334 if err != nil { 7335 t.Fatalf("err: %s", err) 7336 } 7337 7338 mod := state.RootModule() 7339 if len(mod.Resources) != 1 { 7340 t.Fatalf("bad: %s", state) 7341 } 7342 7343 actual := strings.TrimSpace(state.String()) 7344 // Expect no changes from original state 7345 expected := strings.TrimSpace(` 7346 aws_instance.foo: 7347 ID = foo 7348 required_field = set 7349 type = aws_instance 7350 `) 7351 if actual != expected { 7352 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 7353 } 7354 } 7355 7356 func TestContext2Apply_ignoreChangesWithDep(t *testing.T) { 7357 m := testModule(t, "apply-ignore-changes-dep") 7358 p := testProvider("aws") 7359 p.ApplyFn = testApplyFn 7360 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 7361 switch i.Type { 7362 case "aws_instance": 7363 newAmi, _ := c.Get("ami") 7364 return &InstanceDiff{ 7365 Attributes: map[string]*ResourceAttrDiff{ 7366 "ami": &ResourceAttrDiff{ 7367 Old: s.Attributes["ami"], 7368 New: newAmi.(string), 7369 RequiresNew: true, 7370 }, 7371 }, 7372 }, nil 7373 case "aws_eip": 7374 return testDiffFn(i, s, c) 7375 default: 7376 t.Fatalf("Unexpected type: %s", i.Type) 7377 return nil, nil 7378 } 7379 } 7380 s := &State{ 7381 Modules: []*ModuleState{ 7382 &ModuleState{ 7383 Path: rootModulePath, 7384 Resources: map[string]*ResourceState{ 7385 "aws_instance.foo.0": &ResourceState{ 7386 Primary: &InstanceState{ 7387 ID: "i-abc123", 7388 Attributes: map[string]string{ 7389 "ami": "ami-abcd1234", 7390 "id": "i-abc123", 7391 }, 7392 }, 7393 }, 7394 "aws_instance.foo.1": &ResourceState{ 7395 Primary: &InstanceState{ 7396 ID: "i-bcd234", 7397 Attributes: map[string]string{ 7398 "ami": "ami-abcd1234", 7399 "id": "i-bcd234", 7400 }, 7401 }, 7402 }, 7403 "aws_eip.foo.0": &ResourceState{ 7404 Primary: &InstanceState{ 7405 ID: "eip-abc123", 7406 Attributes: map[string]string{ 7407 "id": "eip-abc123", 7408 "instance": "i-abc123", 7409 }, 7410 }, 7411 }, 7412 "aws_eip.foo.1": &ResourceState{ 7413 Primary: &InstanceState{ 7414 ID: "eip-bcd234", 7415 Attributes: map[string]string{ 7416 "id": "eip-bcd234", 7417 "instance": "i-bcd234", 7418 }, 7419 }, 7420 }, 7421 }, 7422 }, 7423 }, 7424 } 7425 ctx := testContext2(t, &ContextOpts{ 7426 Module: m, 7427 Providers: map[string]ResourceProviderFactory{ 7428 "aws": testProviderFuncFixed(p), 7429 }, 7430 State: s, 7431 }) 7432 7433 if p, err := ctx.Plan(); err != nil { 7434 t.Fatalf("err: %s", err) 7435 } else { 7436 t.Logf(p.String()) 7437 } 7438 7439 state, err := ctx.Apply() 7440 if err != nil { 7441 t.Fatalf("err: %s", err) 7442 } 7443 7444 actual := strings.TrimSpace(state.String()) 7445 expected := strings.TrimSpace(s.String()) 7446 if actual != expected { 7447 t.Fatalf("bad: \n%s", actual) 7448 } 7449 } 7450 7451 func TestContext2Apply_ignoreChangesWildcard(t *testing.T) { 7452 m := testModule(t, "apply-ignore-changes-wildcard") 7453 p := testProvider("aws") 7454 p.ApplyFn = testApplyFn 7455 p.DiffFn = testDiffFn 7456 ctx := testContext2(t, &ContextOpts{ 7457 Module: m, 7458 Providers: map[string]ResourceProviderFactory{ 7459 "aws": testProviderFuncFixed(p), 7460 }, 7461 }) 7462 7463 if p, err := ctx.Plan(); err != nil { 7464 t.Fatalf("err: %s", err) 7465 } else { 7466 t.Logf(p.String()) 7467 } 7468 7469 state, err := ctx.Apply() 7470 if err != nil { 7471 t.Fatalf("err: %s", err) 7472 } 7473 7474 mod := state.RootModule() 7475 if len(mod.Resources) != 1 { 7476 t.Fatalf("bad: %s", state) 7477 } 7478 7479 actual := strings.TrimSpace(state.String()) 7480 // Expect no changes from original state 7481 expected := strings.TrimSpace(` 7482 aws_instance.foo: 7483 ID = foo 7484 required_field = set 7485 type = aws_instance 7486 `) 7487 if actual != expected { 7488 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 7489 } 7490 } 7491 7492 // https://github.com/hashicorp/terraform/issues/7378 7493 func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) { 7494 m := testModule(t, "apply-destroy-nested-module-with-attrs") 7495 p := testProvider("null") 7496 p.ApplyFn = testApplyFn 7497 p.DiffFn = testDiffFn 7498 7499 var state *State 7500 var err error 7501 { 7502 ctx := testContext2(t, &ContextOpts{ 7503 Module: m, 7504 Providers: map[string]ResourceProviderFactory{ 7505 "null": testProviderFuncFixed(p), 7506 }, 7507 }) 7508 7509 // First plan and apply a create operation 7510 if _, err := ctx.Plan(); err != nil { 7511 t.Fatalf("plan err: %s", err) 7512 } 7513 7514 state, err = ctx.Apply() 7515 if err != nil { 7516 t.Fatalf("apply err: %s", err) 7517 } 7518 } 7519 7520 { 7521 ctx := testContext2(t, &ContextOpts{ 7522 Destroy: true, 7523 Module: m, 7524 State: state, 7525 Providers: map[string]ResourceProviderFactory{ 7526 "null": testProviderFuncFixed(p), 7527 }, 7528 }) 7529 7530 plan, err := ctx.Plan() 7531 if err != nil { 7532 t.Fatalf("destroy plan err: %s", err) 7533 } 7534 7535 var buf bytes.Buffer 7536 if err := WritePlan(plan, &buf); err != nil { 7537 t.Fatalf("plan write err: %s", err) 7538 } 7539 7540 planFromFile, err := ReadPlan(&buf) 7541 if err != nil { 7542 t.Fatalf("plan read err: %s", err) 7543 } 7544 7545 ctx, err = planFromFile.Context(&ContextOpts{ 7546 Providers: map[string]ResourceProviderFactory{ 7547 "null": testProviderFuncFixed(p), 7548 }, 7549 }) 7550 if err != nil { 7551 t.Fatalf("err: %s", err) 7552 } 7553 7554 state, err = ctx.Apply() 7555 if err != nil { 7556 t.Fatalf("destroy apply err: %s", err) 7557 } 7558 } 7559 7560 //Test that things were destroyed 7561 actual := strings.TrimSpace(state.String()) 7562 expected := strings.TrimSpace(` 7563 <no state> 7564 module.middle: 7565 <no state> 7566 module.middle.bottom: 7567 <no state> 7568 `) 7569 if actual != expected { 7570 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 7571 } 7572 } 7573 7574 // If a data source explicitly depends on another resource, it's because we need 7575 // that resource to be applied first. 7576 func TestContext2Apply_dataDependsOn(t *testing.T) { 7577 p := testProvider("null") 7578 m := testModule(t, "apply-data-depends-on") 7579 7580 ctx := testContext2(t, &ContextOpts{ 7581 Module: m, 7582 Providers: map[string]ResourceProviderFactory{ 7583 "null": testProviderFuncFixed(p), 7584 }, 7585 }) 7586 7587 // the "provisioner" here writes to this variable, because the intent is to 7588 // create a dependency which can't be viewed through the graph, and depends 7589 // solely on the configuration providing "depends_on" 7590 provisionerOutput := "" 7591 7592 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 7593 // the side effect of the resource being applied 7594 provisionerOutput = "APPLIED" 7595 return testApplyFn(info, s, d) 7596 } 7597 7598 p.DiffFn = testDiffFn 7599 p.ReadDataDiffFn = testDataDiffFn 7600 7601 p.ReadDataApplyFn = func(*InstanceInfo, *InstanceDiff) (*InstanceState, error) { 7602 // Read the artifact created by our dependency being applied. 7603 // Without any "depends_on", this would be skipped as it's assumed the 7604 // initial diff during refresh was all that's needed. 7605 return &InstanceState{ 7606 ID: "read", 7607 Attributes: map[string]string{ 7608 "foo": provisionerOutput, 7609 }, 7610 }, nil 7611 } 7612 7613 _, err := ctx.Refresh() 7614 if err != nil { 7615 t.Fatalf("err: %s", err) 7616 } 7617 7618 if _, err := ctx.Plan(); err != nil { 7619 t.Fatalf("err: %s", err) 7620 } 7621 7622 state, err := ctx.Apply() 7623 if err != nil { 7624 t.Fatalf("err: %s", err) 7625 } 7626 7627 root := state.ModuleByPath(RootModulePath) 7628 actual := root.Resources["data.null_data_source.read"].Primary.Attributes["foo"] 7629 7630 expected := "APPLIED" 7631 if actual != expected { 7632 t.Fatalf("bad:\n%s", strings.TrimSpace(state.String())) 7633 } 7634 }