github.com/ggriffiths/terraform@v0.9.0-beta1.0.20170222213024-79c4935604cb/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 // Test that destroy ordering is correct with dependencies only 1333 // in the state within a module (GH-11749) 1334 func TestContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) { 1335 // It is possible for this to be racy, so we loop a number of times 1336 // just to check. 1337 for i := 0; i < 10; i++ { 1338 testContext2Apply_destroyDependsOnStateOnlyModule(t) 1339 } 1340 } 1341 1342 func testContext2Apply_destroyDependsOnStateOnlyModule(t *testing.T) { 1343 m := testModule(t, "empty") 1344 p := testProvider("aws") 1345 p.ApplyFn = testApplyFn 1346 p.DiffFn = testDiffFn 1347 state := &State{ 1348 Modules: []*ModuleState{ 1349 &ModuleState{ 1350 Path: []string{"root", "child"}, 1351 Resources: map[string]*ResourceState{ 1352 "aws_instance.foo": &ResourceState{ 1353 Type: "aws_instance", 1354 Primary: &InstanceState{ 1355 ID: "foo", 1356 Attributes: map[string]string{}, 1357 }, 1358 }, 1359 1360 "aws_instance.bar": &ResourceState{ 1361 Type: "aws_instance", 1362 Primary: &InstanceState{ 1363 ID: "bar", 1364 Attributes: map[string]string{}, 1365 }, 1366 Dependencies: []string{"aws_instance.foo"}, 1367 }, 1368 }, 1369 }, 1370 }, 1371 } 1372 1373 // Record the order we see Apply 1374 var actual []string 1375 var actualLock sync.Mutex 1376 p.ApplyFn = func( 1377 info *InstanceInfo, _ *InstanceState, _ *InstanceDiff) (*InstanceState, error) { 1378 actualLock.Lock() 1379 defer actualLock.Unlock() 1380 actual = append(actual, info.Id) 1381 return nil, nil 1382 } 1383 1384 ctx := testContext2(t, &ContextOpts{ 1385 Module: m, 1386 Providers: map[string]ResourceProviderFactory{ 1387 "aws": testProviderFuncFixed(p), 1388 }, 1389 State: state, 1390 Destroy: true, 1391 Parallelism: 1, // To check ordering 1392 }) 1393 1394 if _, err := ctx.Plan(); err != nil { 1395 t.Fatalf("err: %s", err) 1396 } 1397 1398 if _, err := ctx.Apply(); err != nil { 1399 t.Fatalf("err: %s", err) 1400 } 1401 1402 expected := []string{"aws_instance.bar", "aws_instance.foo"} 1403 if !reflect.DeepEqual(actual, expected) { 1404 t.Fatalf("bad: %#v", actual) 1405 } 1406 } 1407 1408 func TestContext2Apply_dataBasic(t *testing.T) { 1409 m := testModule(t, "apply-data-basic") 1410 p := testProvider("null") 1411 p.ApplyFn = testApplyFn 1412 p.DiffFn = testDiffFn 1413 p.ReadDataApplyReturn = &InstanceState{ID: "yo"} 1414 1415 ctx := testContext2(t, &ContextOpts{ 1416 Module: m, 1417 Providers: map[string]ResourceProviderFactory{ 1418 "null": testProviderFuncFixed(p), 1419 }, 1420 }) 1421 1422 if p, err := ctx.Plan(); err != nil { 1423 t.Fatalf("err: %s", err) 1424 } else { 1425 t.Logf(p.String()) 1426 } 1427 1428 state, err := ctx.Apply() 1429 if err != nil { 1430 t.Fatalf("err: %s", err) 1431 } 1432 1433 actual := strings.TrimSpace(state.String()) 1434 expected := strings.TrimSpace(testTerraformApplyDataBasicStr) 1435 if actual != expected { 1436 t.Fatalf("bad: \n%s", actual) 1437 } 1438 } 1439 1440 func TestContext2Apply_destroyData(t *testing.T) { 1441 m := testModule(t, "apply-destroy-data-resource") 1442 p := testProvider("null") 1443 p.ApplyFn = testApplyFn 1444 p.DiffFn = testDiffFn 1445 state := &State{ 1446 Modules: []*ModuleState{ 1447 &ModuleState{ 1448 Path: rootModulePath, 1449 Resources: map[string]*ResourceState{ 1450 "data.null_data_source.testing": &ResourceState{ 1451 Type: "aws_instance", 1452 Primary: &InstanceState{ 1453 ID: "-", 1454 Attributes: map[string]string{ 1455 "inputs.#": "1", 1456 "inputs.test": "yes", 1457 }, 1458 }, 1459 }, 1460 }, 1461 }, 1462 }, 1463 } 1464 ctx := testContext2(t, &ContextOpts{ 1465 Module: m, 1466 Providers: map[string]ResourceProviderFactory{ 1467 "null": testProviderFuncFixed(p), 1468 }, 1469 State: state, 1470 Destroy: true, 1471 }) 1472 1473 if p, err := ctx.Plan(); err != nil { 1474 t.Fatalf("err: %s", err) 1475 } else { 1476 t.Logf(p.String()) 1477 } 1478 1479 newState, err := ctx.Apply() 1480 if err != nil { 1481 t.Fatalf("err: %s", err) 1482 } 1483 1484 if got := len(newState.Modules); got != 1 { 1485 t.Fatalf("state has %d modules after destroy; want 1", got) 1486 } 1487 1488 if got := len(newState.Modules[0].Resources); got != 0 { 1489 t.Fatalf("state has %d resources after destroy; want 0", got) 1490 } 1491 } 1492 1493 // https://github.com/hashicorp/terraform/pull/5096 1494 func TestContext2Apply_destroySkipsCBD(t *testing.T) { 1495 // Config contains CBD resource depending on non-CBD resource, which triggers 1496 // a cycle if they are both replaced, but should _not_ trigger a cycle when 1497 // just doing a `terraform destroy`. 1498 m := testModule(t, "apply-destroy-cbd") 1499 p := testProvider("aws") 1500 p.ApplyFn = testApplyFn 1501 p.DiffFn = testDiffFn 1502 state := &State{ 1503 Modules: []*ModuleState{ 1504 &ModuleState{ 1505 Path: rootModulePath, 1506 Resources: map[string]*ResourceState{ 1507 "aws_instance.foo": &ResourceState{ 1508 Type: "aws_instance", 1509 Primary: &InstanceState{ 1510 ID: "foo", 1511 }, 1512 }, 1513 "aws_instance.bar": &ResourceState{ 1514 Type: "aws_instance", 1515 Primary: &InstanceState{ 1516 ID: "foo", 1517 }, 1518 }, 1519 }, 1520 }, 1521 }, 1522 } 1523 ctx := testContext2(t, &ContextOpts{ 1524 Module: m, 1525 Providers: map[string]ResourceProviderFactory{ 1526 "aws": testProviderFuncFixed(p), 1527 }, 1528 State: state, 1529 Destroy: true, 1530 }) 1531 1532 if p, err := ctx.Plan(); err != nil { 1533 t.Fatalf("err: %s", err) 1534 } else { 1535 t.Logf(p.String()) 1536 } 1537 1538 if _, err := ctx.Apply(); err != nil { 1539 t.Fatalf("err: %s", err) 1540 } 1541 } 1542 1543 func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) { 1544 m := testModule(t, "apply-destroy-mod-var-provider-config") 1545 p := testProvider("aws") 1546 p.ApplyFn = testApplyFn 1547 p.DiffFn = testDiffFn 1548 state := &State{ 1549 Modules: []*ModuleState{ 1550 &ModuleState{ 1551 Path: []string{"root", "child"}, 1552 Resources: map[string]*ResourceState{ 1553 "aws_instance.foo": &ResourceState{ 1554 Type: "aws_instance", 1555 Primary: &InstanceState{ 1556 ID: "foo", 1557 }, 1558 }, 1559 }, 1560 }, 1561 }, 1562 } 1563 ctx := testContext2(t, &ContextOpts{ 1564 Module: m, 1565 Providers: map[string]ResourceProviderFactory{ 1566 "aws": testProviderFuncFixed(p), 1567 }, 1568 State: state, 1569 Destroy: true, 1570 }) 1571 1572 if _, err := ctx.Plan(); err != nil { 1573 t.Fatalf("err: %s", err) 1574 } 1575 1576 _, err := ctx.Apply() 1577 if err != nil { 1578 t.Fatalf("err: %s", err) 1579 } 1580 } 1581 1582 // https://github.com/hashicorp/terraform/issues/2892 1583 func TestContext2Apply_destroyCrossProviders(t *testing.T) { 1584 m := testModule(t, "apply-destroy-cross-providers") 1585 1586 p_aws := testProvider("aws") 1587 p_aws.ApplyFn = testApplyFn 1588 p_aws.DiffFn = testDiffFn 1589 1590 p_tf := testProvider("terraform") 1591 p_tf.ApplyFn = testApplyFn 1592 p_tf.DiffFn = testDiffFn 1593 1594 providers := map[string]ResourceProviderFactory{ 1595 "aws": testProviderFuncFixed(p_aws), 1596 "terraform": testProviderFuncFixed(p_tf), 1597 } 1598 1599 // Bug only appears from time to time, 1600 // so we run this test multiple times 1601 // to check for the race-condition 1602 for i := 0; i <= 10; i++ { 1603 ctx := getContextForApply_destroyCrossProviders( 1604 t, m, providers) 1605 1606 if p, err := ctx.Plan(); err != nil { 1607 t.Fatalf("err: %s", err) 1608 } else { 1609 t.Logf(p.String()) 1610 } 1611 1612 if _, err := ctx.Apply(); err != nil { 1613 t.Fatalf("err: %s", err) 1614 } 1615 } 1616 } 1617 1618 func getContextForApply_destroyCrossProviders( 1619 t *testing.T, 1620 m *module.Tree, 1621 providers map[string]ResourceProviderFactory) *Context { 1622 state := &State{ 1623 Modules: []*ModuleState{ 1624 &ModuleState{ 1625 Path: rootModulePath, 1626 Resources: map[string]*ResourceState{ 1627 "terraform_remote_state.shared": &ResourceState{ 1628 Type: "terraform_remote_state", 1629 Primary: &InstanceState{ 1630 ID: "remote-2652591293", 1631 Attributes: map[string]string{ 1632 "output.env_name": "test", 1633 }, 1634 }, 1635 }, 1636 }, 1637 }, 1638 &ModuleState{ 1639 Path: []string{"root", "child"}, 1640 Resources: map[string]*ResourceState{ 1641 "aws_vpc.bar": &ResourceState{ 1642 Type: "aws_vpc", 1643 Primary: &InstanceState{ 1644 ID: "vpc-aaabbb12", 1645 Attributes: map[string]string{ 1646 "value": "test", 1647 }, 1648 }, 1649 }, 1650 }, 1651 }, 1652 }, 1653 } 1654 ctx := testContext2(t, &ContextOpts{ 1655 Module: m, 1656 Providers: providers, 1657 State: state, 1658 Destroy: true, 1659 }) 1660 1661 return ctx 1662 } 1663 1664 func TestContext2Apply_minimal(t *testing.T) { 1665 m := testModule(t, "apply-minimal") 1666 p := testProvider("aws") 1667 p.ApplyFn = testApplyFn 1668 p.DiffFn = testDiffFn 1669 ctx := testContext2(t, &ContextOpts{ 1670 Module: m, 1671 Providers: map[string]ResourceProviderFactory{ 1672 "aws": testProviderFuncFixed(p), 1673 }, 1674 }) 1675 1676 if _, err := ctx.Plan(); err != nil { 1677 t.Fatalf("err: %s", err) 1678 } 1679 1680 state, err := ctx.Apply() 1681 if err != nil { 1682 t.Fatalf("err: %s", err) 1683 } 1684 1685 actual := strings.TrimSpace(state.String()) 1686 expected := strings.TrimSpace(testTerraformApplyMinimalStr) 1687 if actual != expected { 1688 t.Fatalf("bad: \n%s", actual) 1689 } 1690 } 1691 1692 func TestContext2Apply_badDiff(t *testing.T) { 1693 m := testModule(t, "apply-good") 1694 p := testProvider("aws") 1695 p.ApplyFn = testApplyFn 1696 p.DiffFn = testDiffFn 1697 ctx := testContext2(t, &ContextOpts{ 1698 Module: m, 1699 Providers: map[string]ResourceProviderFactory{ 1700 "aws": testProviderFuncFixed(p), 1701 }, 1702 }) 1703 1704 if _, err := ctx.Plan(); err != nil { 1705 t.Fatalf("err: %s", err) 1706 } 1707 1708 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1709 return &InstanceDiff{ 1710 Attributes: map[string]*ResourceAttrDiff{ 1711 "newp": nil, 1712 }, 1713 }, nil 1714 } 1715 1716 if _, err := ctx.Apply(); err == nil { 1717 t.Fatal("should error") 1718 } 1719 } 1720 1721 func TestContext2Apply_cancel(t *testing.T) { 1722 stopped := false 1723 1724 m := testModule(t, "apply-cancel") 1725 p := testProvider("aws") 1726 ctx := testContext2(t, &ContextOpts{ 1727 Module: m, 1728 Providers: map[string]ResourceProviderFactory{ 1729 "aws": testProviderFuncFixed(p), 1730 }, 1731 }) 1732 1733 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 1734 if !stopped { 1735 stopped = true 1736 go ctx.Stop() 1737 1738 for { 1739 if ctx.sh.Stopped() { 1740 break 1741 } 1742 } 1743 } 1744 1745 return &InstanceState{ 1746 ID: "foo", 1747 Attributes: map[string]string{ 1748 "num": "2", 1749 }, 1750 }, nil 1751 } 1752 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1753 return &InstanceDiff{ 1754 Attributes: map[string]*ResourceAttrDiff{ 1755 "num": &ResourceAttrDiff{ 1756 New: "bar", 1757 }, 1758 }, 1759 }, nil 1760 } 1761 1762 if _, err := ctx.Plan(); err != nil { 1763 t.Fatalf("err: %s", err) 1764 } 1765 1766 // Start the Apply in a goroutine 1767 var applyErr error 1768 stateCh := make(chan *State) 1769 go func() { 1770 state, err := ctx.Apply() 1771 if err != nil { 1772 applyErr = err 1773 } 1774 1775 stateCh <- state 1776 }() 1777 1778 state := <-stateCh 1779 if applyErr != nil { 1780 t.Fatalf("err: %s", applyErr) 1781 } 1782 1783 mod := state.RootModule() 1784 if len(mod.Resources) != 1 { 1785 t.Fatalf("bad: %s", state.String()) 1786 } 1787 1788 actual := strings.TrimSpace(state.String()) 1789 expected := strings.TrimSpace(testTerraformApplyCancelStr) 1790 if actual != expected { 1791 t.Fatalf("bad: \n%s", actual) 1792 } 1793 1794 if !p.StopCalled { 1795 t.Fatal("stop should be called") 1796 } 1797 } 1798 1799 func TestContext2Apply_cancelBlock(t *testing.T) { 1800 m := testModule(t, "apply-cancel-block") 1801 p := testProvider("aws") 1802 ctx := testContext2(t, &ContextOpts{ 1803 Module: m, 1804 Providers: map[string]ResourceProviderFactory{ 1805 "aws": testProviderFuncFixed(p), 1806 }, 1807 }) 1808 1809 applyCh := make(chan struct{}) 1810 p.DiffFn = testDiffFn 1811 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 1812 close(applyCh) 1813 1814 for !ctx.sh.Stopped() { 1815 // Wait for stop to be called 1816 } 1817 1818 // Sleep 1819 time.Sleep(100 * time.Millisecond) 1820 1821 return &InstanceState{ 1822 ID: "foo", 1823 }, nil 1824 } 1825 1826 if _, err := ctx.Plan(); err != nil { 1827 t.Fatalf("err: %s", err) 1828 } 1829 1830 // Start the Apply in a goroutine 1831 var applyErr error 1832 stateCh := make(chan *State) 1833 go func() { 1834 state, err := ctx.Apply() 1835 if err != nil { 1836 applyErr = err 1837 } 1838 1839 stateCh <- state 1840 }() 1841 1842 stopDone := make(chan struct{}) 1843 go func() { 1844 defer close(stopDone) 1845 <-applyCh 1846 ctx.Stop() 1847 }() 1848 1849 // Make sure that stop blocks 1850 select { 1851 case <-stopDone: 1852 t.Fatal("stop should block") 1853 case <-time.After(10 * time.Millisecond): 1854 } 1855 1856 // Wait for stop 1857 select { 1858 case <-stopDone: 1859 case <-time.After(500 * time.Millisecond): 1860 t.Fatal("stop should be done") 1861 } 1862 1863 // Wait for apply to complete 1864 state := <-stateCh 1865 if applyErr != nil { 1866 t.Fatalf("err: %s", applyErr) 1867 } 1868 1869 checkStateString(t, state, ` 1870 aws_instance.foo: 1871 ID = foo 1872 `) 1873 } 1874 1875 func TestContext2Apply_cancelProvisioner(t *testing.T) { 1876 m := testModule(t, "apply-cancel-provisioner") 1877 p := testProvider("aws") 1878 p.ApplyFn = testApplyFn 1879 p.DiffFn = testDiffFn 1880 pr := testProvisioner() 1881 ctx := testContext2(t, &ContextOpts{ 1882 Module: m, 1883 Providers: map[string]ResourceProviderFactory{ 1884 "aws": testProviderFuncFixed(p), 1885 }, 1886 Provisioners: map[string]ResourceProvisionerFactory{ 1887 "shell": testProvisionerFuncFixed(pr), 1888 }, 1889 }) 1890 1891 prStopped := make(chan struct{}) 1892 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1893 // Start the stop process 1894 go ctx.Stop() 1895 1896 <-prStopped 1897 return nil 1898 } 1899 pr.StopFn = func() error { 1900 close(prStopped) 1901 return nil 1902 } 1903 1904 if _, err := ctx.Plan(); err != nil { 1905 t.Fatalf("err: %s", err) 1906 } 1907 1908 // Start the Apply in a goroutine 1909 var applyErr error 1910 stateCh := make(chan *State) 1911 go func() { 1912 state, err := ctx.Apply() 1913 if err != nil { 1914 applyErr = err 1915 } 1916 1917 stateCh <- state 1918 }() 1919 1920 // Wait for completion 1921 state := <-stateCh 1922 if applyErr != nil { 1923 t.Fatalf("err: %s", applyErr) 1924 } 1925 1926 checkStateString(t, state, ` 1927 aws_instance.foo: (tainted) 1928 ID = foo 1929 num = 2 1930 type = aws_instance 1931 `) 1932 1933 if !pr.StopCalled { 1934 t.Fatal("stop should be called") 1935 } 1936 } 1937 1938 func TestContext2Apply_compute(t *testing.T) { 1939 m := testModule(t, "apply-compute") 1940 p := testProvider("aws") 1941 p.ApplyFn = testApplyFn 1942 p.DiffFn = testDiffFn 1943 ctx := testContext2(t, &ContextOpts{ 1944 Module: m, 1945 Providers: map[string]ResourceProviderFactory{ 1946 "aws": testProviderFuncFixed(p), 1947 }, 1948 }) 1949 1950 if _, err := ctx.Plan(); err != nil { 1951 t.Fatalf("err: %s", err) 1952 } 1953 1954 ctx.variables = map[string]interface{}{"value": "1"} 1955 1956 state, err := ctx.Apply() 1957 if err != nil { 1958 t.Fatalf("err: %s", err) 1959 } 1960 1961 actual := strings.TrimSpace(state.String()) 1962 expected := strings.TrimSpace(testTerraformApplyComputeStr) 1963 if actual != expected { 1964 t.Fatalf("bad: \n%s", actual) 1965 } 1966 } 1967 1968 func TestContext2Apply_countDecrease(t *testing.T) { 1969 m := testModule(t, "apply-count-dec") 1970 p := testProvider("aws") 1971 p.DiffFn = testDiffFn 1972 s := &State{ 1973 Modules: []*ModuleState{ 1974 &ModuleState{ 1975 Path: rootModulePath, 1976 Resources: map[string]*ResourceState{ 1977 "aws_instance.foo.0": &ResourceState{ 1978 Type: "aws_instance", 1979 Primary: &InstanceState{ 1980 ID: "bar", 1981 Attributes: map[string]string{ 1982 "foo": "foo", 1983 "type": "aws_instance", 1984 }, 1985 }, 1986 }, 1987 "aws_instance.foo.1": &ResourceState{ 1988 Type: "aws_instance", 1989 Primary: &InstanceState{ 1990 ID: "bar", 1991 Attributes: map[string]string{ 1992 "foo": "foo", 1993 "type": "aws_instance", 1994 }, 1995 }, 1996 }, 1997 "aws_instance.foo.2": &ResourceState{ 1998 Type: "aws_instance", 1999 Primary: &InstanceState{ 2000 ID: "bar", 2001 Attributes: map[string]string{ 2002 "foo": "foo", 2003 "type": "aws_instance", 2004 }, 2005 }, 2006 }, 2007 }, 2008 }, 2009 }, 2010 } 2011 ctx := testContext2(t, &ContextOpts{ 2012 Module: m, 2013 Providers: map[string]ResourceProviderFactory{ 2014 "aws": testProviderFuncFixed(p), 2015 }, 2016 State: s, 2017 }) 2018 2019 if _, err := ctx.Plan(); err != nil { 2020 t.Fatalf("err: %s", err) 2021 } 2022 2023 state, err := ctx.Apply() 2024 if err != nil { 2025 t.Fatalf("err: %s", err) 2026 } 2027 2028 actual := strings.TrimSpace(state.String()) 2029 expected := strings.TrimSpace(testTerraformApplyCountDecStr) 2030 if actual != expected { 2031 t.Fatalf("bad: \n%s", actual) 2032 } 2033 } 2034 2035 func TestContext2Apply_countDecreaseToOneX(t *testing.T) { 2036 m := testModule(t, "apply-count-dec-one") 2037 p := testProvider("aws") 2038 p.ApplyFn = testApplyFn 2039 p.DiffFn = testDiffFn 2040 s := &State{ 2041 Modules: []*ModuleState{ 2042 &ModuleState{ 2043 Path: rootModulePath, 2044 Resources: map[string]*ResourceState{ 2045 "aws_instance.foo.0": &ResourceState{ 2046 Type: "aws_instance", 2047 Primary: &InstanceState{ 2048 ID: "bar", 2049 Attributes: map[string]string{ 2050 "foo": "foo", 2051 "type": "aws_instance", 2052 }, 2053 }, 2054 }, 2055 "aws_instance.foo.1": &ResourceState{ 2056 Type: "aws_instance", 2057 Primary: &InstanceState{ 2058 ID: "bar", 2059 }, 2060 }, 2061 "aws_instance.foo.2": &ResourceState{ 2062 Type: "aws_instance", 2063 Primary: &InstanceState{ 2064 ID: "bar", 2065 }, 2066 }, 2067 }, 2068 }, 2069 }, 2070 } 2071 ctx := testContext2(t, &ContextOpts{ 2072 Module: m, 2073 Providers: map[string]ResourceProviderFactory{ 2074 "aws": testProviderFuncFixed(p), 2075 }, 2076 State: s, 2077 }) 2078 2079 if _, err := ctx.Plan(); err != nil { 2080 t.Fatalf("err: %s", err) 2081 } 2082 2083 state, err := ctx.Apply() 2084 if err != nil { 2085 t.Fatalf("err: %s", err) 2086 } 2087 2088 actual := strings.TrimSpace(state.String()) 2089 expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) 2090 if actual != expected { 2091 t.Fatalf("bad: \n%s", actual) 2092 } 2093 } 2094 2095 // https://github.com/PeoplePerHour/terraform/pull/11 2096 // 2097 // This tests a case where both a "resource" and "resource.0" are in 2098 // the state file, which apparently is a reasonable backwards compatibility 2099 // concern found in the above 3rd party repo. 2100 func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { 2101 m := testModule(t, "apply-count-dec-one") 2102 p := testProvider("aws") 2103 p.ApplyFn = testApplyFn 2104 p.DiffFn = testDiffFn 2105 s := &State{ 2106 Modules: []*ModuleState{ 2107 &ModuleState{ 2108 Path: rootModulePath, 2109 Resources: map[string]*ResourceState{ 2110 "aws_instance.foo": &ResourceState{ 2111 Type: "aws_instance", 2112 Primary: &InstanceState{ 2113 ID: "bar", 2114 Attributes: map[string]string{ 2115 "foo": "foo", 2116 "type": "aws_instance", 2117 }, 2118 }, 2119 }, 2120 "aws_instance.foo.0": &ResourceState{ 2121 Type: "aws_instance", 2122 Primary: &InstanceState{ 2123 ID: "baz", 2124 Attributes: map[string]string{ 2125 "type": "aws_instance", 2126 }, 2127 }, 2128 }, 2129 }, 2130 }, 2131 }, 2132 } 2133 ctx := testContext2(t, &ContextOpts{ 2134 Module: m, 2135 Providers: map[string]ResourceProviderFactory{ 2136 "aws": testProviderFuncFixed(p), 2137 }, 2138 State: s, 2139 }) 2140 2141 if p, err := ctx.Plan(); err != nil { 2142 t.Fatalf("err: %s", err) 2143 } else { 2144 testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr) 2145 } 2146 2147 state, err := ctx.Apply() 2148 if err != nil { 2149 t.Fatalf("err: %s", err) 2150 } 2151 2152 actual := strings.TrimSpace(state.String()) 2153 expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) 2154 if actual != expected { 2155 t.Fatalf("bad: \n%s", actual) 2156 } 2157 } 2158 2159 func TestContext2Apply_countTainted(t *testing.T) { 2160 m := testModule(t, "apply-count-tainted") 2161 p := testProvider("aws") 2162 p.DiffFn = testDiffFn 2163 s := &State{ 2164 Modules: []*ModuleState{ 2165 &ModuleState{ 2166 Path: rootModulePath, 2167 Resources: map[string]*ResourceState{ 2168 "aws_instance.foo.0": &ResourceState{ 2169 Type: "aws_instance", 2170 Primary: &InstanceState{ 2171 ID: "bar", 2172 Attributes: map[string]string{ 2173 "foo": "foo", 2174 "type": "aws_instance", 2175 }, 2176 Tainted: true, 2177 }, 2178 }, 2179 }, 2180 }, 2181 }, 2182 } 2183 ctx := testContext2(t, &ContextOpts{ 2184 Module: m, 2185 Providers: map[string]ResourceProviderFactory{ 2186 "aws": testProviderFuncFixed(p), 2187 }, 2188 State: s, 2189 }) 2190 2191 if _, err := ctx.Plan(); err != nil { 2192 t.Fatalf("err: %s", err) 2193 } 2194 2195 state, err := ctx.Apply() 2196 if err != nil { 2197 t.Fatalf("err: %s", err) 2198 } 2199 2200 actual := strings.TrimSpace(state.String()) 2201 expected := strings.TrimSpace(testTerraformApplyCountTaintedStr) 2202 if actual != expected { 2203 t.Fatalf("bad: \n%s", actual) 2204 } 2205 } 2206 2207 func TestContext2Apply_countVariable(t *testing.T) { 2208 m := testModule(t, "apply-count-variable") 2209 p := testProvider("aws") 2210 p.ApplyFn = testApplyFn 2211 p.DiffFn = testDiffFn 2212 ctx := testContext2(t, &ContextOpts{ 2213 Module: m, 2214 Providers: map[string]ResourceProviderFactory{ 2215 "aws": testProviderFuncFixed(p), 2216 }, 2217 }) 2218 2219 if _, err := ctx.Plan(); err != nil { 2220 t.Fatalf("err: %s", err) 2221 } 2222 2223 state, err := ctx.Apply() 2224 if err != nil { 2225 t.Fatalf("err: %s", err) 2226 } 2227 2228 actual := strings.TrimSpace(state.String()) 2229 expected := strings.TrimSpace(testTerraformApplyCountVariableStr) 2230 if actual != expected { 2231 t.Fatalf("bad: \n%s", actual) 2232 } 2233 } 2234 2235 func TestContext2Apply_countVariableRef(t *testing.T) { 2236 m := testModule(t, "apply-count-variable-ref") 2237 p := testProvider("aws") 2238 p.ApplyFn = testApplyFn 2239 p.DiffFn = testDiffFn 2240 ctx := testContext2(t, &ContextOpts{ 2241 Module: m, 2242 Providers: map[string]ResourceProviderFactory{ 2243 "aws": testProviderFuncFixed(p), 2244 }, 2245 }) 2246 2247 if _, err := ctx.Plan(); err != nil { 2248 t.Fatalf("err: %s", err) 2249 } 2250 2251 state, err := ctx.Apply() 2252 if err != nil { 2253 t.Fatalf("err: %s", err) 2254 } 2255 2256 actual := strings.TrimSpace(state.String()) 2257 expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr) 2258 if actual != expected { 2259 t.Fatalf("bad: \n%s", actual) 2260 } 2261 } 2262 2263 func TestContext2Apply_mapVariableOverride(t *testing.T) { 2264 m := testModule(t, "apply-map-var-override") 2265 p := testProvider("aws") 2266 p.ApplyFn = testApplyFn 2267 p.DiffFn = testDiffFn 2268 ctx := testContext2(t, &ContextOpts{ 2269 Module: m, 2270 Providers: map[string]ResourceProviderFactory{ 2271 "aws": testProviderFuncFixed(p), 2272 }, 2273 Variables: map[string]interface{}{ 2274 "images": []map[string]interface{}{ 2275 map[string]interface{}{ 2276 "us-west-2": "overridden", 2277 }, 2278 }, 2279 }, 2280 }) 2281 2282 if _, err := ctx.Plan(); err != nil { 2283 t.Fatalf("err: %s", err) 2284 } 2285 2286 state, err := ctx.Apply() 2287 if err != nil { 2288 t.Fatalf("err: %s", err) 2289 } 2290 2291 actual := strings.TrimSpace(state.String()) 2292 expected := strings.TrimSpace(` 2293 aws_instance.bar: 2294 ID = foo 2295 ami = overridden 2296 type = aws_instance 2297 aws_instance.foo: 2298 ID = foo 2299 ami = image-1234 2300 type = aws_instance 2301 `) 2302 if actual != expected { 2303 t.Fatalf("got: \n%s\nexpected: \n%s", actual, expected) 2304 } 2305 } 2306 2307 func TestContext2Apply_moduleBasic(t *testing.T) { 2308 m := testModule(t, "apply-module") 2309 p := testProvider("aws") 2310 p.ApplyFn = testApplyFn 2311 p.DiffFn = testDiffFn 2312 ctx := testContext2(t, &ContextOpts{ 2313 Module: m, 2314 Providers: map[string]ResourceProviderFactory{ 2315 "aws": testProviderFuncFixed(p), 2316 }, 2317 }) 2318 2319 if _, err := ctx.Plan(); err != nil { 2320 t.Fatalf("err: %s", err) 2321 } 2322 2323 state, err := ctx.Apply() 2324 if err != nil { 2325 t.Fatalf("err: %s", err) 2326 } 2327 2328 actual := strings.TrimSpace(state.String()) 2329 expected := strings.TrimSpace(testTerraformApplyModuleStr) 2330 if actual != expected { 2331 t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual) 2332 } 2333 } 2334 2335 func TestContext2Apply_moduleDestroyOrder(t *testing.T) { 2336 m := testModule(t, "apply-module-destroy-order") 2337 p := testProvider("aws") 2338 p.DiffFn = testDiffFn 2339 2340 // Create a custom apply function to track the order they were destroyed 2341 var order []string 2342 var orderLock sync.Mutex 2343 p.ApplyFn = func( 2344 info *InstanceInfo, 2345 is *InstanceState, 2346 id *InstanceDiff) (*InstanceState, error) { 2347 orderLock.Lock() 2348 defer orderLock.Unlock() 2349 2350 order = append(order, is.ID) 2351 return nil, nil 2352 } 2353 2354 state := &State{ 2355 Modules: []*ModuleState{ 2356 &ModuleState{ 2357 Path: rootModulePath, 2358 Resources: map[string]*ResourceState{ 2359 "aws_instance.b": &ResourceState{ 2360 Type: "aws_instance", 2361 Primary: &InstanceState{ 2362 ID: "b", 2363 }, 2364 }, 2365 }, 2366 }, 2367 2368 &ModuleState{ 2369 Path: []string{"root", "child"}, 2370 Resources: map[string]*ResourceState{ 2371 "aws_instance.a": &ResourceState{ 2372 Type: "aws_instance", 2373 Primary: &InstanceState{ 2374 ID: "a", 2375 }, 2376 }, 2377 }, 2378 Outputs: map[string]*OutputState{ 2379 "a_output": &OutputState{ 2380 Type: "string", 2381 Sensitive: false, 2382 Value: "a", 2383 }, 2384 }, 2385 }, 2386 }, 2387 } 2388 2389 ctx := testContext2(t, &ContextOpts{ 2390 Module: m, 2391 Providers: map[string]ResourceProviderFactory{ 2392 "aws": testProviderFuncFixed(p), 2393 }, 2394 State: state, 2395 Destroy: true, 2396 }) 2397 2398 if _, err := ctx.Plan(); err != nil { 2399 t.Fatalf("err: %s", err) 2400 } 2401 2402 state, err := ctx.Apply() 2403 if err != nil { 2404 t.Fatalf("err: %s", err) 2405 } 2406 2407 expected := []string{"b", "a"} 2408 if !reflect.DeepEqual(order, expected) { 2409 t.Fatalf("bad: %#v", order) 2410 } 2411 2412 { 2413 actual := strings.TrimSpace(state.String()) 2414 expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr) 2415 if actual != expected { 2416 t.Fatalf("bad: \n%s", actual) 2417 } 2418 } 2419 } 2420 2421 func TestContext2Apply_moduleInheritAlias(t *testing.T) { 2422 m := testModule(t, "apply-module-provider-inherit-alias") 2423 p := testProvider("aws") 2424 p.ApplyFn = testApplyFn 2425 p.DiffFn = testDiffFn 2426 2427 p.ConfigureFn = func(c *ResourceConfig) error { 2428 if _, ok := c.Get("child"); !ok { 2429 return nil 2430 } 2431 2432 if _, ok := c.Get("root"); ok { 2433 return fmt.Errorf("child should not get root") 2434 } 2435 2436 return nil 2437 } 2438 2439 ctx := testContext2(t, &ContextOpts{ 2440 Module: m, 2441 Providers: map[string]ResourceProviderFactory{ 2442 "aws": testProviderFuncFixed(p), 2443 }, 2444 }) 2445 2446 if _, err := ctx.Plan(); err != nil { 2447 t.Fatalf("err: %s", err) 2448 } 2449 2450 state, err := ctx.Apply() 2451 if err != nil { 2452 t.Fatalf("err: %s", err) 2453 } 2454 2455 checkStateString(t, state, ` 2456 <no state> 2457 module.child: 2458 aws_instance.foo: 2459 ID = foo 2460 provider = aws.eu 2461 `) 2462 } 2463 2464 func TestContext2Apply_moduleOrphanInheritAlias(t *testing.T) { 2465 m := testModule(t, "apply-module-provider-inherit-alias-orphan") 2466 p := testProvider("aws") 2467 p.ApplyFn = testApplyFn 2468 p.DiffFn = testDiffFn 2469 2470 called := false 2471 p.ConfigureFn = func(c *ResourceConfig) error { 2472 called = true 2473 2474 if _, ok := c.Get("child"); !ok { 2475 return nil 2476 } 2477 2478 if _, ok := c.Get("root"); ok { 2479 return fmt.Errorf("child should not get root") 2480 } 2481 2482 return nil 2483 } 2484 2485 // Create a state with an orphan module 2486 state := &State{ 2487 Modules: []*ModuleState{ 2488 &ModuleState{ 2489 Path: []string{"root", "child"}, 2490 Resources: map[string]*ResourceState{ 2491 "aws_instance.bar": &ResourceState{ 2492 Type: "aws_instance", 2493 Primary: &InstanceState{ 2494 ID: "bar", 2495 }, 2496 Provider: "aws.eu", 2497 }, 2498 }, 2499 }, 2500 }, 2501 } 2502 2503 ctx := testContext2(t, &ContextOpts{ 2504 Module: m, 2505 State: state, 2506 Providers: map[string]ResourceProviderFactory{ 2507 "aws": testProviderFuncFixed(p), 2508 }, 2509 }) 2510 2511 if _, err := ctx.Plan(); err != nil { 2512 t.Fatalf("err: %s", err) 2513 } 2514 2515 state, err := ctx.Apply() 2516 if err != nil { 2517 t.Fatalf("err: %s", err) 2518 } 2519 2520 if !called { 2521 t.Fatal("must call configure") 2522 } 2523 2524 checkStateString(t, state, ` 2525 module.child: 2526 <no state> 2527 `) 2528 } 2529 2530 func TestContext2Apply_moduleOrphanProvider(t *testing.T) { 2531 m := testModule(t, "apply-module-orphan-provider-inherit") 2532 p := testProvider("aws") 2533 p.ApplyFn = testApplyFn 2534 p.DiffFn = testDiffFn 2535 2536 p.ConfigureFn = func(c *ResourceConfig) error { 2537 if _, ok := c.Get("value"); !ok { 2538 return fmt.Errorf("value is not found") 2539 } 2540 2541 return nil 2542 } 2543 2544 // Create a state with an orphan module 2545 state := &State{ 2546 Modules: []*ModuleState{ 2547 &ModuleState{ 2548 Path: []string{"root", "child"}, 2549 Resources: map[string]*ResourceState{ 2550 "aws_instance.bar": &ResourceState{ 2551 Type: "aws_instance", 2552 Primary: &InstanceState{ 2553 ID: "bar", 2554 }, 2555 }, 2556 }, 2557 }, 2558 }, 2559 } 2560 2561 ctx := testContext2(t, &ContextOpts{ 2562 Module: m, 2563 State: state, 2564 Providers: map[string]ResourceProviderFactory{ 2565 "aws": testProviderFuncFixed(p), 2566 }, 2567 }) 2568 2569 if _, err := ctx.Plan(); err != nil { 2570 t.Fatalf("err: %s", err) 2571 } 2572 2573 if _, err := ctx.Apply(); err != nil { 2574 t.Fatalf("err: %s", err) 2575 } 2576 } 2577 2578 func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) { 2579 m := testModule(t, "apply-module-orphan-provider-inherit") 2580 p := testProvider("aws") 2581 p.ApplyFn = testApplyFn 2582 p.DiffFn = testDiffFn 2583 2584 p.ConfigureFn = func(c *ResourceConfig) error { 2585 if _, ok := c.Get("value"); !ok { 2586 return fmt.Errorf("value is not found") 2587 } 2588 2589 return nil 2590 } 2591 2592 // Create a state with an orphan module that is nested (grandchild) 2593 state := &State{ 2594 Modules: []*ModuleState{ 2595 &ModuleState{ 2596 Path: []string{"root", "parent", "child"}, 2597 Resources: map[string]*ResourceState{ 2598 "aws_instance.bar": &ResourceState{ 2599 Type: "aws_instance", 2600 Primary: &InstanceState{ 2601 ID: "bar", 2602 }, 2603 }, 2604 }, 2605 }, 2606 }, 2607 } 2608 2609 ctx := testContext2(t, &ContextOpts{ 2610 Module: m, 2611 State: state, 2612 Providers: map[string]ResourceProviderFactory{ 2613 "aws": testProviderFuncFixed(p), 2614 }, 2615 }) 2616 2617 if _, err := ctx.Plan(); err != nil { 2618 t.Fatalf("err: %s", err) 2619 } 2620 2621 if _, err := ctx.Apply(); err != nil { 2622 t.Fatalf("err: %s", err) 2623 } 2624 } 2625 2626 func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { 2627 m := testModule(t, "apply-module-grandchild-provider-inherit") 2628 p := testProvider("aws") 2629 p.ApplyFn = testApplyFn 2630 p.DiffFn = testDiffFn 2631 2632 var callLock sync.Mutex 2633 called := false 2634 p.ConfigureFn = func(c *ResourceConfig) error { 2635 if _, ok := c.Get("value"); !ok { 2636 return fmt.Errorf("value is not found") 2637 } 2638 callLock.Lock() 2639 called = true 2640 callLock.Unlock() 2641 2642 return nil 2643 } 2644 2645 ctx := testContext2(t, &ContextOpts{ 2646 Module: m, 2647 Providers: map[string]ResourceProviderFactory{ 2648 "aws": testProviderFuncFixed(p), 2649 }, 2650 }) 2651 2652 if _, err := ctx.Plan(); err != nil { 2653 t.Fatalf("err: %s", err) 2654 } 2655 2656 if _, err := ctx.Apply(); err != nil { 2657 t.Fatalf("err: %s", err) 2658 } 2659 2660 callLock.Lock() 2661 defer callLock.Unlock() 2662 if called != true { 2663 t.Fatalf("err: configure never called") 2664 } 2665 } 2666 2667 // This tests an issue where all the providers in a module but not 2668 // in the root weren't being added to the root properly. In this test 2669 // case: aws is explicitly added to root, but "test" should be added to. 2670 // With the bug, it wasn't. 2671 func TestContext2Apply_moduleOnlyProvider(t *testing.T) { 2672 m := testModule(t, "apply-module-only-provider") 2673 p := testProvider("aws") 2674 p.ApplyFn = testApplyFn 2675 p.DiffFn = testDiffFn 2676 pTest := testProvider("test") 2677 pTest.ApplyFn = testApplyFn 2678 pTest.DiffFn = testDiffFn 2679 2680 ctx := testContext2(t, &ContextOpts{ 2681 Module: m, 2682 Providers: map[string]ResourceProviderFactory{ 2683 "aws": testProviderFuncFixed(p), 2684 "test": testProviderFuncFixed(pTest), 2685 }, 2686 }) 2687 2688 if _, err := ctx.Plan(); err != nil { 2689 t.Fatalf("err: %s", err) 2690 } 2691 2692 state, err := ctx.Apply() 2693 if err != nil { 2694 t.Fatalf("err: %s", err) 2695 } 2696 2697 actual := strings.TrimSpace(state.String()) 2698 expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) 2699 if actual != expected { 2700 t.Fatalf("bad: \n%s", actual) 2701 } 2702 } 2703 2704 func TestContext2Apply_moduleProviderAlias(t *testing.T) { 2705 m := testModule(t, "apply-module-provider-alias") 2706 p := testProvider("aws") 2707 p.ApplyFn = testApplyFn 2708 p.DiffFn = testDiffFn 2709 ctx := testContext2(t, &ContextOpts{ 2710 Module: m, 2711 Providers: map[string]ResourceProviderFactory{ 2712 "aws": testProviderFuncFixed(p), 2713 }, 2714 }) 2715 2716 if _, err := ctx.Plan(); err != nil { 2717 t.Fatalf("err: %s", err) 2718 } 2719 2720 state, err := ctx.Apply() 2721 if err != nil { 2722 t.Fatalf("err: %s", err) 2723 } 2724 2725 actual := strings.TrimSpace(state.String()) 2726 expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) 2727 if actual != expected { 2728 t.Fatalf("bad: \n%s", actual) 2729 } 2730 } 2731 2732 func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { 2733 m := testModule(t, "apply-module-provider-alias") 2734 p := testProvider("aws") 2735 p.ApplyFn = testApplyFn 2736 p.DiffFn = testDiffFn 2737 ctx := testContext2(t, &ContextOpts{ 2738 Module: m, 2739 Providers: map[string]ResourceProviderFactory{ 2740 "aws": testProviderFuncFixed(p), 2741 }, 2742 Targets: []string{"no.thing"}, 2743 }) 2744 2745 if _, err := ctx.Plan(); err != nil { 2746 t.Fatalf("err: %s", err) 2747 } 2748 2749 state, err := ctx.Apply() 2750 if err != nil { 2751 t.Fatalf("err: %s", err) 2752 } 2753 2754 actual := strings.TrimSpace(state.String()) 2755 expected := strings.TrimSpace(` 2756 <no state> 2757 `) 2758 if actual != expected { 2759 t.Fatalf("bad: \n%s", actual) 2760 } 2761 } 2762 2763 func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { 2764 m := testModule(t, "apply-module-provider-close-nested") 2765 p := testProvider("aws") 2766 p.ApplyFn = testApplyFn 2767 p.DiffFn = testDiffFn 2768 ctx := testContext2(t, &ContextOpts{ 2769 Module: m, 2770 Providers: map[string]ResourceProviderFactory{ 2771 "aws": testProviderFuncFixed(p), 2772 }, 2773 State: &State{ 2774 Modules: []*ModuleState{ 2775 &ModuleState{ 2776 Path: []string{"root", "child", "subchild"}, 2777 Resources: map[string]*ResourceState{ 2778 "aws_instance.foo": &ResourceState{ 2779 Type: "aws_instance", 2780 Primary: &InstanceState{ 2781 ID: "bar", 2782 }, 2783 }, 2784 }, 2785 }, 2786 }, 2787 }, 2788 Destroy: true, 2789 }) 2790 2791 if _, err := ctx.Plan(); err != nil { 2792 t.Fatalf("err: %s", err) 2793 } 2794 2795 if _, err := ctx.Apply(); err != nil { 2796 t.Fatalf("err: %s", err) 2797 } 2798 } 2799 2800 // Tests that variables used as module vars that reference data that 2801 // already exists in the state and requires no diff works properly. This 2802 // fixes an issue faced where module variables were pruned because they were 2803 // accessing "non-existent" resources (they existed, just not in the graph 2804 // cause they weren't in the diff). 2805 func TestContext2Apply_moduleVarRefExisting(t *testing.T) { 2806 m := testModule(t, "apply-ref-existing") 2807 p := testProvider("aws") 2808 p.ApplyFn = testApplyFn 2809 p.DiffFn = testDiffFn 2810 2811 state := &State{ 2812 Modules: []*ModuleState{ 2813 &ModuleState{ 2814 Path: rootModulePath, 2815 Resources: map[string]*ResourceState{ 2816 "aws_instance.foo": &ResourceState{ 2817 Type: "aws_instance", 2818 Primary: &InstanceState{ 2819 ID: "foo", 2820 Attributes: map[string]string{ 2821 "foo": "bar", 2822 }, 2823 }, 2824 }, 2825 }, 2826 }, 2827 }, 2828 } 2829 2830 ctx := testContext2(t, &ContextOpts{ 2831 Module: m, 2832 Providers: map[string]ResourceProviderFactory{ 2833 "aws": testProviderFuncFixed(p), 2834 }, 2835 State: state, 2836 }) 2837 2838 if _, err := ctx.Plan(); err != nil { 2839 t.Fatalf("err: %s", err) 2840 } 2841 2842 state, err := ctx.Apply() 2843 if err != nil { 2844 t.Fatalf("err: %s", err) 2845 } 2846 2847 actual := strings.TrimSpace(state.String()) 2848 expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr) 2849 if actual != expected { 2850 t.Fatalf("bad: \n%s", actual) 2851 } 2852 } 2853 2854 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 2855 m := testModule(t, "apply-module-var-resource-count") 2856 p := testProvider("aws") 2857 p.ApplyFn = testApplyFn 2858 p.DiffFn = testDiffFn 2859 ctx := testContext2(t, &ContextOpts{ 2860 Module: m, 2861 Providers: map[string]ResourceProviderFactory{ 2862 "aws": testProviderFuncFixed(p), 2863 }, 2864 Variables: map[string]interface{}{ 2865 "count": "2", 2866 }, 2867 Destroy: true, 2868 }) 2869 2870 if _, err := ctx.Plan(); err != nil { 2871 t.Fatalf("err: %s", err) 2872 } 2873 2874 if _, err := ctx.Apply(); err != nil { 2875 t.Fatalf("err: %s", err) 2876 } 2877 2878 ctx = testContext2(t, &ContextOpts{ 2879 Module: m, 2880 Providers: map[string]ResourceProviderFactory{ 2881 "aws": testProviderFuncFixed(p), 2882 }, 2883 Variables: map[string]interface{}{ 2884 "count": "5", 2885 }, 2886 }) 2887 2888 if _, err := ctx.Plan(); err != nil { 2889 t.Fatalf("err: %s", err) 2890 } 2891 2892 if _, err := ctx.Apply(); err != nil { 2893 t.Fatalf("err: %s", err) 2894 } 2895 } 2896 2897 // GH-819 2898 func TestContext2Apply_moduleBool(t *testing.T) { 2899 m := testModule(t, "apply-module-bool") 2900 p := testProvider("aws") 2901 p.ApplyFn = testApplyFn 2902 p.DiffFn = testDiffFn 2903 ctx := testContext2(t, &ContextOpts{ 2904 Module: m, 2905 Providers: map[string]ResourceProviderFactory{ 2906 "aws": testProviderFuncFixed(p), 2907 }, 2908 }) 2909 2910 if _, err := ctx.Plan(); err != nil { 2911 t.Fatalf("err: %s", err) 2912 } 2913 2914 state, err := ctx.Apply() 2915 if err != nil { 2916 t.Fatalf("err: %s", err) 2917 } 2918 2919 actual := strings.TrimSpace(state.String()) 2920 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 2921 if actual != expected { 2922 t.Fatalf("bad: \n%s", actual) 2923 } 2924 } 2925 2926 // Tests that a module can be targeted and everything is properly created. 2927 // This adds to the plan test to also just verify that apply works. 2928 func TestContext2Apply_moduleTarget(t *testing.T) { 2929 m := testModule(t, "plan-targeted-cross-module") 2930 p := testProvider("aws") 2931 p.ApplyFn = testApplyFn 2932 p.DiffFn = testDiffFn 2933 ctx := testContext2(t, &ContextOpts{ 2934 Module: m, 2935 Providers: map[string]ResourceProviderFactory{ 2936 "aws": testProviderFuncFixed(p), 2937 }, 2938 Targets: []string{"module.B"}, 2939 }) 2940 2941 if _, err := ctx.Plan(); err != nil { 2942 t.Fatalf("err: %s", err) 2943 } 2944 2945 state, err := ctx.Apply() 2946 if err != nil { 2947 t.Fatalf("err: %s", err) 2948 } 2949 2950 checkStateString(t, state, ` 2951 <no state> 2952 module.A: 2953 aws_instance.foo: 2954 ID = foo 2955 foo = bar 2956 type = aws_instance 2957 2958 Outputs: 2959 2960 value = foo 2961 module.B: 2962 aws_instance.bar: 2963 ID = foo 2964 foo = foo 2965 type = aws_instance 2966 `) 2967 } 2968 2969 func TestContext2Apply_multiProvider(t *testing.T) { 2970 m := testModule(t, "apply-multi-provider") 2971 p := testProvider("aws") 2972 p.ApplyFn = testApplyFn 2973 p.DiffFn = testDiffFn 2974 2975 pDO := testProvider("do") 2976 pDO.ApplyFn = testApplyFn 2977 pDO.DiffFn = testDiffFn 2978 2979 ctx := testContext2(t, &ContextOpts{ 2980 Module: m, 2981 Providers: map[string]ResourceProviderFactory{ 2982 "aws": testProviderFuncFixed(p), 2983 "do": testProviderFuncFixed(pDO), 2984 }, 2985 }) 2986 2987 if _, err := ctx.Plan(); err != nil { 2988 t.Fatalf("err: %s", err) 2989 } 2990 2991 state, err := ctx.Apply() 2992 if err != nil { 2993 t.Fatalf("err: %s", err) 2994 } 2995 2996 mod := state.RootModule() 2997 if len(mod.Resources) < 2 { 2998 t.Fatalf("bad: %#v", mod.Resources) 2999 } 3000 3001 actual := strings.TrimSpace(state.String()) 3002 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 3003 if actual != expected { 3004 t.Fatalf("bad: \n%s", actual) 3005 } 3006 } 3007 3008 func TestContext2Apply_multiProviderDestroy(t *testing.T) { 3009 m := testModule(t, "apply-multi-provider-destroy") 3010 p := testProvider("aws") 3011 p.ApplyFn = testApplyFn 3012 p.DiffFn = testDiffFn 3013 3014 p2 := testProvider("do") 3015 p2.ApplyFn = testApplyFn 3016 p2.DiffFn = testDiffFn 3017 3018 var state *State 3019 3020 // First, create the instances 3021 { 3022 ctx := testContext2(t, &ContextOpts{ 3023 Module: m, 3024 Providers: map[string]ResourceProviderFactory{ 3025 "aws": testProviderFuncFixed(p), 3026 "vault": testProviderFuncFixed(p2), 3027 }, 3028 }) 3029 3030 if _, err := ctx.Plan(); err != nil { 3031 t.Fatalf("err: %s", err) 3032 } 3033 3034 s, err := ctx.Apply() 3035 if err != nil { 3036 t.Fatalf("err: %s", err) 3037 } 3038 3039 state = s 3040 } 3041 3042 // Destroy them 3043 { 3044 // Verify that aws_instance.bar is destroyed first 3045 var checked bool 3046 var called int32 3047 var lock sync.Mutex 3048 applyFn := func( 3049 info *InstanceInfo, 3050 is *InstanceState, 3051 id *InstanceDiff) (*InstanceState, error) { 3052 lock.Lock() 3053 defer lock.Unlock() 3054 3055 if info.HumanId() == "aws_instance.bar" { 3056 checked = true 3057 3058 // Sleep to allow parallel execution 3059 time.Sleep(50 * time.Millisecond) 3060 3061 // Verify that called is 0 (dep not called) 3062 if atomic.LoadInt32(&called) != 0 { 3063 return nil, fmt.Errorf("nothing else should be called") 3064 } 3065 } 3066 3067 atomic.AddInt32(&called, 1) 3068 return testApplyFn(info, is, id) 3069 } 3070 3071 // Set the apply functions 3072 p.ApplyFn = applyFn 3073 p2.ApplyFn = applyFn 3074 3075 ctx := testContext2(t, &ContextOpts{ 3076 Destroy: true, 3077 State: state, 3078 Module: m, 3079 Providers: map[string]ResourceProviderFactory{ 3080 "aws": testProviderFuncFixed(p), 3081 "vault": testProviderFuncFixed(p2), 3082 }, 3083 }) 3084 3085 if _, err := ctx.Plan(); err != nil { 3086 t.Fatalf("err: %s", err) 3087 } 3088 3089 s, err := ctx.Apply() 3090 if err != nil { 3091 t.Fatalf("err: %s", err) 3092 } 3093 3094 if !checked { 3095 t.Fatal("should be checked") 3096 } 3097 3098 state = s 3099 } 3100 3101 checkStateString(t, state, `<no state>`) 3102 } 3103 3104 // This is like the multiProviderDestroy test except it tests that 3105 // dependent resources within a child module that inherit provider 3106 // configuration are still destroyed first. 3107 func TestContext2Apply_multiProviderDestroyChild(t *testing.T) { 3108 m := testModule(t, "apply-multi-provider-destroy-child") 3109 p := testProvider("aws") 3110 p.ApplyFn = testApplyFn 3111 p.DiffFn = testDiffFn 3112 3113 p2 := testProvider("do") 3114 p2.ApplyFn = testApplyFn 3115 p2.DiffFn = testDiffFn 3116 3117 var state *State 3118 3119 // First, create the instances 3120 { 3121 ctx := testContext2(t, &ContextOpts{ 3122 Module: m, 3123 Providers: map[string]ResourceProviderFactory{ 3124 "aws": testProviderFuncFixed(p), 3125 "vault": testProviderFuncFixed(p2), 3126 }, 3127 }) 3128 3129 if _, err := ctx.Plan(); err != nil { 3130 t.Fatalf("err: %s", err) 3131 } 3132 3133 s, err := ctx.Apply() 3134 if err != nil { 3135 t.Fatalf("err: %s", err) 3136 } 3137 3138 state = s 3139 } 3140 3141 // Destroy them 3142 { 3143 // Verify that aws_instance.bar is destroyed first 3144 var checked bool 3145 var called int32 3146 var lock sync.Mutex 3147 applyFn := func( 3148 info *InstanceInfo, 3149 is *InstanceState, 3150 id *InstanceDiff) (*InstanceState, error) { 3151 lock.Lock() 3152 defer lock.Unlock() 3153 3154 if info.HumanId() == "module.child.aws_instance.bar" { 3155 checked = true 3156 3157 // Sleep to allow parallel execution 3158 time.Sleep(50 * time.Millisecond) 3159 3160 // Verify that called is 0 (dep not called) 3161 if atomic.LoadInt32(&called) != 0 { 3162 return nil, fmt.Errorf("nothing else should be called") 3163 } 3164 } 3165 3166 atomic.AddInt32(&called, 1) 3167 return testApplyFn(info, is, id) 3168 } 3169 3170 // Set the apply functions 3171 p.ApplyFn = applyFn 3172 p2.ApplyFn = applyFn 3173 3174 ctx := testContext2(t, &ContextOpts{ 3175 Destroy: true, 3176 State: state, 3177 Module: m, 3178 Providers: map[string]ResourceProviderFactory{ 3179 "aws": testProviderFuncFixed(p), 3180 "vault": testProviderFuncFixed(p2), 3181 }, 3182 }) 3183 3184 if _, err := ctx.Plan(); err != nil { 3185 t.Fatalf("err: %s", err) 3186 } 3187 3188 s, err := ctx.Apply() 3189 if err != nil { 3190 t.Fatalf("err: %s", err) 3191 } 3192 3193 if !checked { 3194 t.Fatal("should be checked") 3195 } 3196 3197 state = s 3198 } 3199 3200 checkStateString(t, state, ` 3201 <no state> 3202 module.child: 3203 <no state> 3204 `) 3205 } 3206 3207 func TestContext2Apply_multiVar(t *testing.T) { 3208 m := testModule(t, "apply-multi-var") 3209 p := testProvider("aws") 3210 p.ApplyFn = testApplyFn 3211 p.DiffFn = testDiffFn 3212 3213 // First, apply with a count of 3 3214 ctx := testContext2(t, &ContextOpts{ 3215 Module: m, 3216 Providers: map[string]ResourceProviderFactory{ 3217 "aws": testProviderFuncFixed(p), 3218 }, 3219 Variables: map[string]interface{}{ 3220 "count": "3", 3221 }, 3222 }) 3223 3224 if _, err := ctx.Plan(); err != nil { 3225 t.Fatalf("err: %s", err) 3226 } 3227 3228 state, err := ctx.Apply() 3229 if err != nil { 3230 t.Fatalf("err: %s", err) 3231 } 3232 3233 actual := state.RootModule().Outputs["output"] 3234 expected := "bar0,bar1,bar2" 3235 if actual == nil || actual.Value != expected { 3236 t.Fatalf("bad: \n%s", actual) 3237 } 3238 3239 t.Logf("Initial state: %s", state.String()) 3240 3241 // Apply again, reduce the count to 1 3242 { 3243 ctx := testContext2(t, &ContextOpts{ 3244 Module: m, 3245 State: state, 3246 Providers: map[string]ResourceProviderFactory{ 3247 "aws": testProviderFuncFixed(p), 3248 }, 3249 Variables: map[string]interface{}{ 3250 "count": "1", 3251 }, 3252 }) 3253 3254 if _, err := ctx.Plan(); err != nil { 3255 t.Fatalf("err: %s", err) 3256 } 3257 3258 state, err := ctx.Apply() 3259 if err != nil { 3260 t.Fatalf("err: %s", err) 3261 } 3262 3263 t.Logf("End state: %s", state.String()) 3264 3265 actual := state.RootModule().Outputs["output"] 3266 if actual == nil { 3267 t.Fatal("missing output") 3268 } 3269 3270 expected := "bar0" 3271 if actual.Value != expected { 3272 t.Fatalf("bad: \n%s", actual) 3273 } 3274 } 3275 } 3276 3277 // Test that multi-var (splat) access is ordered by count, not by 3278 // value. 3279 func TestContext2Apply_multiVarOrder(t *testing.T) { 3280 m := testModule(t, "apply-multi-var-order") 3281 p := testProvider("aws") 3282 p.ApplyFn = testApplyFn 3283 p.DiffFn = testDiffFn 3284 3285 // First, apply with a count of 3 3286 ctx := testContext2(t, &ContextOpts{ 3287 Module: m, 3288 Providers: map[string]ResourceProviderFactory{ 3289 "aws": testProviderFuncFixed(p), 3290 }, 3291 }) 3292 3293 if _, err := ctx.Plan(); err != nil { 3294 t.Fatalf("err: %s", err) 3295 } 3296 3297 state, err := ctx.Apply() 3298 if err != nil { 3299 t.Fatalf("err: %s", err) 3300 } 3301 3302 t.Logf("State: %s", state.String()) 3303 3304 actual := state.RootModule().Outputs["should-be-11"] 3305 expected := "index-11" 3306 if actual == nil || actual.Value != expected { 3307 t.Fatalf("bad: \n%s", actual) 3308 } 3309 } 3310 3311 // Test that multi-var (splat) access is ordered by count, not by 3312 // value, through interpolations. 3313 func TestContext2Apply_multiVarOrderInterp(t *testing.T) { 3314 m := testModule(t, "apply-multi-var-order-interp") 3315 p := testProvider("aws") 3316 p.ApplyFn = testApplyFn 3317 p.DiffFn = testDiffFn 3318 3319 // First, apply with a count of 3 3320 ctx := testContext2(t, &ContextOpts{ 3321 Module: m, 3322 Providers: map[string]ResourceProviderFactory{ 3323 "aws": testProviderFuncFixed(p), 3324 }, 3325 }) 3326 3327 if _, err := ctx.Plan(); err != nil { 3328 t.Fatalf("err: %s", err) 3329 } 3330 3331 state, err := ctx.Apply() 3332 if err != nil { 3333 t.Fatalf("err: %s", err) 3334 } 3335 3336 t.Logf("State: %s", state.String()) 3337 3338 actual := state.RootModule().Outputs["should-be-11"] 3339 expected := "baz-index-11" 3340 if actual == nil || actual.Value != expected { 3341 t.Fatalf("bad: \n%s", actual) 3342 } 3343 } 3344 3345 // Based on GH-10440 where a graph edge wasn't properly being created 3346 // between a modified resource and a count instance being destroyed. 3347 func TestContext2Apply_multiVarCountDec(t *testing.T) { 3348 var s *State 3349 3350 // First create resources. Nothing sneaky here. 3351 { 3352 m := testModule(t, "apply-multi-var-count-dec") 3353 p := testProvider("aws") 3354 p.ApplyFn = testApplyFn 3355 p.DiffFn = testDiffFn 3356 ctx := testContext2(t, &ContextOpts{ 3357 Module: m, 3358 Providers: map[string]ResourceProviderFactory{ 3359 "aws": testProviderFuncFixed(p), 3360 }, 3361 Variables: map[string]interface{}{ 3362 "count": "2", 3363 }, 3364 }) 3365 3366 if _, err := ctx.Plan(); err != nil { 3367 t.Fatalf("err: %s", err) 3368 } 3369 3370 state, err := ctx.Apply() 3371 if err != nil { 3372 t.Fatalf("err: %s", err) 3373 } 3374 3375 t.Logf("Step 1 state: %s", state) 3376 3377 s = state 3378 } 3379 3380 // Decrease the count by 1 and verify that everything happens in the 3381 // right order. 3382 { 3383 m := testModule(t, "apply-multi-var-count-dec") 3384 p := testProvider("aws") 3385 p.ApplyFn = testApplyFn 3386 p.DiffFn = testDiffFn 3387 3388 // Verify that aws_instance.bar is modified first and nothing 3389 // else happens at the same time. 3390 var checked bool 3391 var called int32 3392 var lock sync.Mutex 3393 p.ApplyFn = func( 3394 info *InstanceInfo, 3395 is *InstanceState, 3396 id *InstanceDiff) (*InstanceState, error) { 3397 lock.Lock() 3398 defer lock.Unlock() 3399 3400 if info.HumanId() == "aws_instance.bar" { 3401 checked = true 3402 3403 // Sleep to allow parallel execution 3404 time.Sleep(50 * time.Millisecond) 3405 3406 // Verify that called is 0 (dep not called) 3407 if atomic.LoadInt32(&called) != 1 { 3408 return nil, fmt.Errorf("nothing else should be called") 3409 } 3410 } 3411 3412 atomic.AddInt32(&called, 1) 3413 return testApplyFn(info, is, id) 3414 } 3415 3416 ctx := testContext2(t, &ContextOpts{ 3417 State: s, 3418 Module: m, 3419 Providers: map[string]ResourceProviderFactory{ 3420 "aws": testProviderFuncFixed(p), 3421 }, 3422 Variables: map[string]interface{}{ 3423 "count": "1", 3424 }, 3425 }) 3426 3427 if _, err := ctx.Plan(); err != nil { 3428 t.Fatalf("err: %s", err) 3429 } 3430 3431 state, err := ctx.Apply() 3432 if err != nil { 3433 t.Fatalf("err: %s", err) 3434 } 3435 3436 if !checked { 3437 t.Fatal("apply never called") 3438 } 3439 3440 t.Logf("Step 2 state: %s", state) 3441 3442 s = state 3443 } 3444 } 3445 3446 func TestContext2Apply_nilDiff(t *testing.T) { 3447 m := testModule(t, "apply-good") 3448 p := testProvider("aws") 3449 p.ApplyFn = testApplyFn 3450 p.DiffFn = testDiffFn 3451 ctx := testContext2(t, &ContextOpts{ 3452 Module: m, 3453 Providers: map[string]ResourceProviderFactory{ 3454 "aws": testProviderFuncFixed(p), 3455 }, 3456 }) 3457 3458 if _, err := ctx.Plan(); err != nil { 3459 t.Fatalf("err: %s", err) 3460 } 3461 3462 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3463 return nil, nil 3464 } 3465 3466 if _, err := ctx.Apply(); err == nil { 3467 t.Fatal("should error") 3468 } 3469 } 3470 3471 func TestContext2Apply_outputDependsOn(t *testing.T) { 3472 m := testModule(t, "apply-output-depends-on") 3473 p := testProvider("aws") 3474 p.DiffFn = testDiffFn 3475 3476 { 3477 // Create a custom apply function that sleeps a bit (to allow parallel 3478 // graph execution) and then returns an error to force a partial state 3479 // return. We then verify the output is NOT there. 3480 p.ApplyFn = func( 3481 info *InstanceInfo, 3482 is *InstanceState, 3483 id *InstanceDiff) (*InstanceState, error) { 3484 3485 // Sleep to allow parallel execution 3486 time.Sleep(50 * time.Millisecond) 3487 3488 // Return error to force partial state 3489 return nil, fmt.Errorf("abcd") 3490 } 3491 3492 ctx := testContext2(t, &ContextOpts{ 3493 Module: m, 3494 Providers: map[string]ResourceProviderFactory{ 3495 "aws": testProviderFuncFixed(p), 3496 }, 3497 }) 3498 3499 if _, err := ctx.Plan(); err != nil { 3500 t.Fatalf("err: %s", err) 3501 } 3502 3503 state, err := ctx.Apply() 3504 if err == nil || !strings.Contains(err.Error(), "abcd") { 3505 t.Fatalf("err: %s", err) 3506 } 3507 3508 checkStateString(t, state, `<no state>`) 3509 } 3510 3511 { 3512 // Create the standard apply function and verify we get the output 3513 p.ApplyFn = testApplyFn 3514 3515 ctx := testContext2(t, &ContextOpts{ 3516 Module: m, 3517 Providers: map[string]ResourceProviderFactory{ 3518 "aws": testProviderFuncFixed(p), 3519 }, 3520 }) 3521 3522 if _, err := ctx.Plan(); err != nil { 3523 t.Fatalf("err: %s", err) 3524 } 3525 3526 state, err := ctx.Apply() 3527 if err != nil { 3528 t.Fatalf("err: %s", err) 3529 } 3530 3531 checkStateString(t, state, ` 3532 aws_instance.foo: 3533 ID = foo 3534 3535 Outputs: 3536 3537 value = result 3538 `) 3539 } 3540 } 3541 3542 func TestContext2Apply_outputOrphan(t *testing.T) { 3543 m := testModule(t, "apply-output-orphan") 3544 p := testProvider("aws") 3545 p.ApplyFn = testApplyFn 3546 p.DiffFn = testDiffFn 3547 3548 state := &State{ 3549 Modules: []*ModuleState{ 3550 &ModuleState{ 3551 Path: rootModulePath, 3552 Outputs: map[string]*OutputState{ 3553 "foo": &OutputState{ 3554 Type: "string", 3555 Sensitive: false, 3556 Value: "bar", 3557 }, 3558 "bar": &OutputState{ 3559 Type: "string", 3560 Sensitive: false, 3561 Value: "baz", 3562 }, 3563 }, 3564 }, 3565 }, 3566 } 3567 3568 ctx := testContext2(t, &ContextOpts{ 3569 Module: m, 3570 Providers: map[string]ResourceProviderFactory{ 3571 "aws": testProviderFuncFixed(p), 3572 }, 3573 State: state, 3574 }) 3575 3576 if _, err := ctx.Plan(); err != nil { 3577 t.Fatalf("err: %s", err) 3578 } 3579 3580 state, err := ctx.Apply() 3581 if err != nil { 3582 t.Fatalf("err: %s", err) 3583 } 3584 3585 actual := strings.TrimSpace(state.String()) 3586 expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) 3587 if actual != expected { 3588 t.Fatalf("bad: \n%s", actual) 3589 } 3590 } 3591 3592 func TestContext2Apply_outputOrphanModule(t *testing.T) { 3593 m := testModule(t, "apply-output-orphan-module") 3594 p := testProvider("aws") 3595 p.ApplyFn = testApplyFn 3596 p.DiffFn = testDiffFn 3597 3598 state := &State{ 3599 Modules: []*ModuleState{ 3600 &ModuleState{ 3601 Path: []string{"root", "child"}, 3602 Outputs: map[string]*OutputState{ 3603 "foo": &OutputState{ 3604 Type: "string", 3605 Value: "bar", 3606 }, 3607 "bar": &OutputState{ 3608 Type: "string", 3609 Value: "baz", 3610 }, 3611 }, 3612 }, 3613 }, 3614 } 3615 3616 ctx := testContext2(t, &ContextOpts{ 3617 Module: m, 3618 Providers: map[string]ResourceProviderFactory{ 3619 "aws": testProviderFuncFixed(p), 3620 }, 3621 State: state, 3622 }) 3623 3624 if _, err := ctx.Plan(); err != nil { 3625 t.Fatalf("err: %s", err) 3626 } 3627 3628 state, err := ctx.Apply() 3629 if err != nil { 3630 t.Fatalf("err: %s", err) 3631 } 3632 3633 actual := strings.TrimSpace(state.String()) 3634 expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr) 3635 if actual != expected { 3636 t.Fatalf("bad: \n%s", actual) 3637 } 3638 } 3639 3640 func TestContext2Apply_providerComputedVar(t *testing.T) { 3641 m := testModule(t, "apply-provider-computed") 3642 p := testProvider("aws") 3643 p.ApplyFn = testApplyFn 3644 p.DiffFn = testDiffFn 3645 3646 pTest := testProvider("test") 3647 pTest.ApplyFn = testApplyFn 3648 pTest.DiffFn = testDiffFn 3649 3650 ctx := testContext2(t, &ContextOpts{ 3651 Module: m, 3652 Providers: map[string]ResourceProviderFactory{ 3653 "aws": testProviderFuncFixed(p), 3654 "test": testProviderFuncFixed(pTest), 3655 }, 3656 }) 3657 3658 p.ConfigureFn = func(c *ResourceConfig) error { 3659 if c.IsComputed("value") { 3660 return fmt.Errorf("value is computed") 3661 } 3662 3663 v, ok := c.Get("value") 3664 if !ok { 3665 return fmt.Errorf("value is not found") 3666 } 3667 if v != "yes" { 3668 return fmt.Errorf("value is not 'yes': %v", v) 3669 } 3670 3671 return nil 3672 } 3673 3674 if _, err := ctx.Plan(); err != nil { 3675 t.Fatalf("err: %s", err) 3676 } 3677 3678 if _, err := ctx.Apply(); err != nil { 3679 t.Fatalf("err: %s", err) 3680 } 3681 } 3682 3683 func TestContext2Apply_providerConfigureDisabled(t *testing.T) { 3684 m := testModule(t, "apply-provider-configure-disabled") 3685 p := testProvider("aws") 3686 p.ApplyFn = testApplyFn 3687 p.DiffFn = testDiffFn 3688 3689 called := false 3690 p.ConfigureFn = func(c *ResourceConfig) error { 3691 called = true 3692 3693 if _, ok := c.Get("value"); !ok { 3694 return fmt.Errorf("value is not found") 3695 } 3696 3697 return nil 3698 } 3699 3700 ctx := testContext2(t, &ContextOpts{ 3701 Module: m, 3702 Providers: map[string]ResourceProviderFactory{ 3703 "aws": testProviderFuncFixed(p), 3704 }, 3705 }) 3706 3707 if _, err := ctx.Plan(); err != nil { 3708 t.Fatalf("err: %s", err) 3709 } 3710 3711 if _, err := ctx.Apply(); err != nil { 3712 t.Fatalf("err: %s", err) 3713 } 3714 3715 if !called { 3716 t.Fatal("configure never called") 3717 } 3718 } 3719 3720 func TestContext2Apply_provisionerModule(t *testing.T) { 3721 m := testModule(t, "apply-provisioner-module") 3722 p := testProvider("aws") 3723 pr := testProvisioner() 3724 p.ApplyFn = testApplyFn 3725 p.DiffFn = testDiffFn 3726 ctx := testContext2(t, &ContextOpts{ 3727 Module: m, 3728 Providers: map[string]ResourceProviderFactory{ 3729 "aws": testProviderFuncFixed(p), 3730 }, 3731 Provisioners: map[string]ResourceProvisionerFactory{ 3732 "shell": testProvisionerFuncFixed(pr), 3733 }, 3734 }) 3735 3736 if _, err := ctx.Plan(); err != nil { 3737 t.Fatalf("err: %s", err) 3738 } 3739 3740 state, err := ctx.Apply() 3741 if err != nil { 3742 t.Fatalf("err: %s", err) 3743 } 3744 3745 actual := strings.TrimSpace(state.String()) 3746 expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr) 3747 if actual != expected { 3748 t.Fatalf("bad: \n%s", actual) 3749 } 3750 3751 // Verify apply was invoked 3752 if !pr.ApplyCalled { 3753 t.Fatalf("provisioner not invoked") 3754 } 3755 } 3756 3757 func TestContext2Apply_Provisioner_compute(t *testing.T) { 3758 m := testModule(t, "apply-provisioner-compute") 3759 p := testProvider("aws") 3760 pr := testProvisioner() 3761 p.ApplyFn = testApplyFn 3762 p.DiffFn = testDiffFn 3763 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3764 val, ok := c.Config["foo"] 3765 if !ok || val != "computed_dynamical" { 3766 t.Fatalf("bad value for foo: %v %#v", val, c) 3767 } 3768 3769 return nil 3770 } 3771 ctx := testContext2(t, &ContextOpts{ 3772 Module: m, 3773 Providers: map[string]ResourceProviderFactory{ 3774 "aws": testProviderFuncFixed(p), 3775 }, 3776 Provisioners: map[string]ResourceProvisionerFactory{ 3777 "shell": testProvisionerFuncFixed(pr), 3778 }, 3779 Variables: map[string]interface{}{ 3780 "value": "1", 3781 }, 3782 }) 3783 3784 if _, err := ctx.Plan(); err != nil { 3785 t.Fatalf("err: %s", err) 3786 } 3787 3788 state, err := ctx.Apply() 3789 if err != nil { 3790 t.Fatalf("err: %s", err) 3791 } 3792 3793 actual := strings.TrimSpace(state.String()) 3794 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 3795 if actual != expected { 3796 t.Fatalf("bad: \n%s", actual) 3797 } 3798 3799 // Verify apply was invoked 3800 if !pr.ApplyCalled { 3801 t.Fatalf("provisioner not invoked") 3802 } 3803 } 3804 3805 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 3806 m := testModule(t, "apply-provisioner-fail-create") 3807 p := testProvider("aws") 3808 pr := testProvisioner() 3809 p.DiffFn = testDiffFn 3810 3811 p.ApplyFn = func( 3812 info *InstanceInfo, 3813 is *InstanceState, 3814 id *InstanceDiff) (*InstanceState, error) { 3815 is.ID = "foo" 3816 return is, fmt.Errorf("error") 3817 } 3818 3819 ctx := testContext2(t, &ContextOpts{ 3820 Module: m, 3821 Providers: map[string]ResourceProviderFactory{ 3822 "aws": testProviderFuncFixed(p), 3823 }, 3824 Provisioners: map[string]ResourceProvisionerFactory{ 3825 "shell": testProvisionerFuncFixed(pr), 3826 }, 3827 }) 3828 3829 if _, err := ctx.Plan(); err != nil { 3830 t.Fatalf("err: %s", err) 3831 } 3832 3833 state, err := ctx.Apply() 3834 if err == nil { 3835 t.Fatal("should error") 3836 } 3837 3838 actual := strings.TrimSpace(state.String()) 3839 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 3840 if actual != expected { 3841 t.Fatalf("bad: \n%s", actual) 3842 } 3843 } 3844 3845 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 3846 m := testModule(t, "apply-provisioner-fail-create") 3847 p := testProvider("aws") 3848 pr := testProvisioner() 3849 p.DiffFn = testDiffFn 3850 3851 p.ApplyFn = func( 3852 info *InstanceInfo, 3853 is *InstanceState, 3854 id *InstanceDiff) (*InstanceState, error) { 3855 return nil, fmt.Errorf("error") 3856 } 3857 3858 ctx := testContext2(t, &ContextOpts{ 3859 Module: m, 3860 Providers: map[string]ResourceProviderFactory{ 3861 "aws": testProviderFuncFixed(p), 3862 }, 3863 Provisioners: map[string]ResourceProvisionerFactory{ 3864 "shell": testProvisionerFuncFixed(pr), 3865 }, 3866 }) 3867 3868 if _, err := ctx.Plan(); err != nil { 3869 t.Fatalf("err: %s", err) 3870 } 3871 3872 state, err := ctx.Apply() 3873 if err == nil { 3874 t.Fatal("should error") 3875 } 3876 3877 actual := strings.TrimSpace(state.String()) 3878 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 3879 if actual != expected { 3880 t.Fatalf("bad: \n%s", actual) 3881 } 3882 } 3883 3884 func TestContext2Apply_provisionerFail(t *testing.T) { 3885 m := testModule(t, "apply-provisioner-fail") 3886 p := testProvider("aws") 3887 pr := testProvisioner() 3888 p.ApplyFn = testApplyFn 3889 p.DiffFn = testDiffFn 3890 3891 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 3892 return fmt.Errorf("EXPLOSION") 3893 } 3894 3895 ctx := testContext2(t, &ContextOpts{ 3896 Module: m, 3897 Providers: map[string]ResourceProviderFactory{ 3898 "aws": testProviderFuncFixed(p), 3899 }, 3900 Provisioners: map[string]ResourceProvisionerFactory{ 3901 "shell": testProvisionerFuncFixed(pr), 3902 }, 3903 Variables: map[string]interface{}{ 3904 "value": "1", 3905 }, 3906 }) 3907 3908 if _, err := ctx.Plan(); err != nil { 3909 t.Fatalf("err: %s", err) 3910 } 3911 3912 state, err := ctx.Apply() 3913 if err == nil { 3914 t.Fatal("should error") 3915 } 3916 3917 actual := strings.TrimSpace(state.String()) 3918 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 3919 if actual != expected { 3920 t.Fatalf("bad: \n%s", actual) 3921 } 3922 } 3923 3924 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 3925 m := testModule(t, "apply-provisioner-fail-create-before") 3926 p := testProvider("aws") 3927 pr := testProvisioner() 3928 p.ApplyFn = testApplyFn 3929 p.DiffFn = testDiffFn 3930 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 3931 return fmt.Errorf("EXPLOSION") 3932 } 3933 3934 state := &State{ 3935 Modules: []*ModuleState{ 3936 &ModuleState{ 3937 Path: rootModulePath, 3938 Resources: map[string]*ResourceState{ 3939 "aws_instance.bar": &ResourceState{ 3940 Type: "aws_instance", 3941 Primary: &InstanceState{ 3942 ID: "bar", 3943 Attributes: map[string]string{ 3944 "require_new": "abc", 3945 }, 3946 }, 3947 }, 3948 }, 3949 }, 3950 }, 3951 } 3952 ctx := testContext2(t, &ContextOpts{ 3953 Module: m, 3954 Providers: map[string]ResourceProviderFactory{ 3955 "aws": testProviderFuncFixed(p), 3956 }, 3957 Provisioners: map[string]ResourceProvisionerFactory{ 3958 "shell": testProvisionerFuncFixed(pr), 3959 }, 3960 State: state, 3961 }) 3962 3963 if _, err := ctx.Plan(); err != nil { 3964 t.Fatalf("err: %s", err) 3965 } 3966 3967 state, err := ctx.Apply() 3968 if err == nil { 3969 t.Fatal("should error") 3970 } 3971 3972 actual := strings.TrimSpace(state.String()) 3973 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 3974 if actual != expected { 3975 t.Fatalf("bad: \n%s", actual) 3976 } 3977 } 3978 3979 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 3980 m := testModule(t, "apply-error-create-before") 3981 p := testProvider("aws") 3982 state := &State{ 3983 Modules: []*ModuleState{ 3984 &ModuleState{ 3985 Path: rootModulePath, 3986 Resources: map[string]*ResourceState{ 3987 "aws_instance.bar": &ResourceState{ 3988 Type: "aws_instance", 3989 Primary: &InstanceState{ 3990 ID: "bar", 3991 Attributes: map[string]string{ 3992 "require_new": "abc", 3993 }, 3994 }, 3995 }, 3996 }, 3997 }, 3998 }, 3999 } 4000 ctx := testContext2(t, &ContextOpts{ 4001 Module: m, 4002 Providers: map[string]ResourceProviderFactory{ 4003 "aws": testProviderFuncFixed(p), 4004 }, 4005 State: state, 4006 }) 4007 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 4008 return nil, fmt.Errorf("error") 4009 } 4010 p.DiffFn = testDiffFn 4011 4012 if _, err := ctx.Plan(); err != nil { 4013 t.Fatalf("err: %s", err) 4014 } 4015 4016 state, err := ctx.Apply() 4017 if err == nil { 4018 t.Fatal("should have error") 4019 } 4020 4021 actual := strings.TrimSpace(state.String()) 4022 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 4023 if actual != expected { 4024 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 4025 } 4026 } 4027 4028 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 4029 m := testModule(t, "apply-error-create-before") 4030 p := testProvider("aws") 4031 state := &State{ 4032 Modules: []*ModuleState{ 4033 &ModuleState{ 4034 Path: rootModulePath, 4035 Resources: map[string]*ResourceState{ 4036 "aws_instance.bar": &ResourceState{ 4037 Type: "aws_instance", 4038 Primary: &InstanceState{ 4039 ID: "bar", 4040 Attributes: map[string]string{ 4041 "require_new": "abc", 4042 }, 4043 }, 4044 }, 4045 }, 4046 }, 4047 }, 4048 } 4049 ctx := testContext2(t, &ContextOpts{ 4050 Module: m, 4051 Providers: map[string]ResourceProviderFactory{ 4052 "aws": testProviderFuncFixed(p), 4053 }, 4054 State: state, 4055 }) 4056 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 4057 // Fail the destroy! 4058 if id.Destroy { 4059 return is, fmt.Errorf("error") 4060 } 4061 4062 // Create should work 4063 is = &InstanceState{ 4064 ID: "foo", 4065 } 4066 return is, nil 4067 } 4068 p.DiffFn = testDiffFn 4069 4070 if _, err := ctx.Plan(); err != nil { 4071 t.Fatalf("err: %s", err) 4072 } 4073 4074 state, err := ctx.Apply() 4075 if err == nil { 4076 t.Fatal("should have error") 4077 } 4078 4079 actual := strings.TrimSpace(state.String()) 4080 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 4081 if actual != expected { 4082 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 4083 } 4084 } 4085 4086 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 4087 m := testModule(t, "apply-multi-depose-create-before-destroy") 4088 p := testProvider("aws") 4089 p.DiffFn = testDiffFn 4090 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 4091 state := &State{ 4092 Modules: []*ModuleState{ 4093 &ModuleState{ 4094 Path: rootModulePath, 4095 Resources: map[string]*ResourceState{ 4096 "aws_instance.web": &ResourceState{ 4097 Type: "aws_instance", 4098 Primary: &InstanceState{ID: "foo"}, 4099 }, 4100 }, 4101 }, 4102 }, 4103 } 4104 4105 ctx := testContext2(t, &ContextOpts{ 4106 Module: m, 4107 Providers: ps, 4108 State: state, 4109 }) 4110 createdInstanceId := "bar" 4111 // Create works 4112 createFunc := func(is *InstanceState) (*InstanceState, error) { 4113 return &InstanceState{ID: createdInstanceId}, nil 4114 } 4115 // Destroy starts broken 4116 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 4117 return is, fmt.Errorf("destroy failed") 4118 } 4119 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 4120 if id.Destroy { 4121 return destroyFunc(is) 4122 } else { 4123 return createFunc(is) 4124 } 4125 } 4126 4127 if _, err := ctx.Plan(); err != nil { 4128 t.Fatalf("err: %s", err) 4129 } 4130 4131 // Destroy is broken, so even though CBD successfully replaces the instance, 4132 // we'll have to save the Deposed instance to destroy later 4133 state, err := ctx.Apply() 4134 if err == nil { 4135 t.Fatal("should have error") 4136 } 4137 4138 checkStateString(t, state, ` 4139 aws_instance.web: (1 deposed) 4140 ID = bar 4141 Deposed ID 1 = foo 4142 `) 4143 4144 createdInstanceId = "baz" 4145 ctx = testContext2(t, &ContextOpts{ 4146 Module: m, 4147 Providers: ps, 4148 State: state, 4149 }) 4150 4151 if _, err := ctx.Plan(); err != nil { 4152 t.Fatalf("err: %s", err) 4153 } 4154 4155 // We're replacing the primary instance once again. Destroy is _still_ 4156 // broken, so the Deposed list gets longer 4157 state, err = ctx.Apply() 4158 if err == nil { 4159 t.Fatal("should have error") 4160 } 4161 4162 checkStateString(t, state, ` 4163 aws_instance.web: (2 deposed) 4164 ID = baz 4165 Deposed ID 1 = foo 4166 Deposed ID 2 = bar 4167 `) 4168 4169 // Destroy partially fixed! 4170 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 4171 if is.ID == "foo" || is.ID == "baz" { 4172 return nil, nil 4173 } else { 4174 return is, fmt.Errorf("destroy partially failed") 4175 } 4176 } 4177 4178 createdInstanceId = "qux" 4179 if _, err := ctx.Plan(); err != nil { 4180 t.Fatalf("err: %s", err) 4181 } 4182 state, err = ctx.Apply() 4183 // Expect error because 1/2 of Deposed destroys failed 4184 if err == nil { 4185 t.Fatal("should have error") 4186 } 4187 4188 // foo and baz are now gone, bar sticks around 4189 checkStateString(t, state, ` 4190 aws_instance.web: (1 deposed) 4191 ID = qux 4192 Deposed ID 1 = bar 4193 `) 4194 4195 // Destroy working fully! 4196 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 4197 return nil, nil 4198 } 4199 4200 createdInstanceId = "quux" 4201 if _, err := ctx.Plan(); err != nil { 4202 t.Fatalf("err: %s", err) 4203 } 4204 state, err = ctx.Apply() 4205 if err != nil { 4206 t.Fatal("should not have error:", err) 4207 } 4208 4209 // And finally the state is clean 4210 checkStateString(t, state, ` 4211 aws_instance.web: 4212 ID = quux 4213 `) 4214 } 4215 4216 // Verify that a normal provisioner with on_failure "continue" set won't 4217 // taint the resource and continues executing. 4218 func TestContext2Apply_provisionerFailContinue(t *testing.T) { 4219 m := testModule(t, "apply-provisioner-fail-continue") 4220 p := testProvider("aws") 4221 pr := testProvisioner() 4222 p.ApplyFn = testApplyFn 4223 p.DiffFn = testDiffFn 4224 4225 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4226 return fmt.Errorf("provisioner error") 4227 } 4228 4229 ctx := testContext2(t, &ContextOpts{ 4230 Module: m, 4231 Providers: map[string]ResourceProviderFactory{ 4232 "aws": testProviderFuncFixed(p), 4233 }, 4234 Provisioners: map[string]ResourceProvisionerFactory{ 4235 "shell": testProvisionerFuncFixed(pr), 4236 }, 4237 }) 4238 4239 if _, err := ctx.Plan(); err != nil { 4240 t.Fatalf("err: %s", err) 4241 } 4242 4243 state, err := ctx.Apply() 4244 if err != nil { 4245 t.Fatalf("err: %s", err) 4246 } 4247 4248 checkStateString(t, state, ` 4249 aws_instance.foo: 4250 ID = foo 4251 foo = bar 4252 type = aws_instance 4253 `) 4254 4255 // Verify apply was invoked 4256 if !pr.ApplyCalled { 4257 t.Fatalf("provisioner not invoked") 4258 } 4259 } 4260 4261 // Verify that a normal provisioner with on_failure "continue" records 4262 // the error with the hook. 4263 func TestContext2Apply_provisionerFailContinueHook(t *testing.T) { 4264 h := new(MockHook) 4265 m := testModule(t, "apply-provisioner-fail-continue") 4266 p := testProvider("aws") 4267 pr := testProvisioner() 4268 p.ApplyFn = testApplyFn 4269 p.DiffFn = testDiffFn 4270 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4271 return fmt.Errorf("provisioner error") 4272 } 4273 4274 ctx := testContext2(t, &ContextOpts{ 4275 Module: m, 4276 Hooks: []Hook{h}, 4277 Providers: map[string]ResourceProviderFactory{ 4278 "aws": testProviderFuncFixed(p), 4279 }, 4280 Provisioners: map[string]ResourceProvisionerFactory{ 4281 "shell": testProvisionerFuncFixed(pr), 4282 }, 4283 }) 4284 4285 if _, err := ctx.Plan(); err != nil { 4286 t.Fatalf("err: %s", err) 4287 } 4288 4289 if _, err := ctx.Apply(); err != nil { 4290 t.Fatalf("err: %s", err) 4291 } 4292 4293 if !h.PostProvisionCalled { 4294 t.Fatal("PostProvision not called") 4295 } 4296 if h.PostProvisionErrorArg == nil { 4297 t.Fatal("should have error") 4298 } 4299 } 4300 4301 func TestContext2Apply_provisionerDestroy(t *testing.T) { 4302 m := testModule(t, "apply-provisioner-destroy") 4303 p := testProvider("aws") 4304 pr := testProvisioner() 4305 p.ApplyFn = testApplyFn 4306 p.DiffFn = testDiffFn 4307 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4308 val, ok := c.Config["foo"] 4309 if !ok || val != "destroy" { 4310 t.Fatalf("bad value for foo: %v %#v", val, c) 4311 } 4312 4313 return nil 4314 } 4315 4316 state := &State{ 4317 Modules: []*ModuleState{ 4318 &ModuleState{ 4319 Path: rootModulePath, 4320 Resources: map[string]*ResourceState{ 4321 "aws_instance.foo": &ResourceState{ 4322 Type: "aws_instance", 4323 Primary: &InstanceState{ 4324 ID: "bar", 4325 }, 4326 }, 4327 }, 4328 }, 4329 }, 4330 } 4331 4332 ctx := testContext2(t, &ContextOpts{ 4333 Module: m, 4334 State: state, 4335 Destroy: true, 4336 Providers: map[string]ResourceProviderFactory{ 4337 "aws": testProviderFuncFixed(p), 4338 }, 4339 Provisioners: map[string]ResourceProvisionerFactory{ 4340 "shell": testProvisionerFuncFixed(pr), 4341 }, 4342 }) 4343 4344 if _, err := ctx.Plan(); err != nil { 4345 t.Fatalf("err: %s", err) 4346 } 4347 4348 state, err := ctx.Apply() 4349 if err != nil { 4350 t.Fatalf("err: %s", err) 4351 } 4352 4353 checkStateString(t, state, `<no state>`) 4354 4355 // Verify apply was invoked 4356 if !pr.ApplyCalled { 4357 t.Fatalf("provisioner not invoked") 4358 } 4359 } 4360 4361 // Verify that on destroy provisioner failure, nothing happens to the instance 4362 func TestContext2Apply_provisionerDestroyFail(t *testing.T) { 4363 m := testModule(t, "apply-provisioner-destroy") 4364 p := testProvider("aws") 4365 pr := testProvisioner() 4366 p.ApplyFn = testApplyFn 4367 p.DiffFn = testDiffFn 4368 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4369 return fmt.Errorf("provisioner error") 4370 } 4371 4372 state := &State{ 4373 Modules: []*ModuleState{ 4374 &ModuleState{ 4375 Path: rootModulePath, 4376 Resources: map[string]*ResourceState{ 4377 "aws_instance.foo": &ResourceState{ 4378 Type: "aws_instance", 4379 Primary: &InstanceState{ 4380 ID: "bar", 4381 }, 4382 }, 4383 }, 4384 }, 4385 }, 4386 } 4387 4388 ctx := testContext2(t, &ContextOpts{ 4389 Module: m, 4390 State: state, 4391 Destroy: true, 4392 Providers: map[string]ResourceProviderFactory{ 4393 "aws": testProviderFuncFixed(p), 4394 }, 4395 Provisioners: map[string]ResourceProvisionerFactory{ 4396 "shell": testProvisionerFuncFixed(pr), 4397 }, 4398 }) 4399 4400 if _, err := ctx.Plan(); err != nil { 4401 t.Fatalf("err: %s", err) 4402 } 4403 4404 state, err := ctx.Apply() 4405 if err == nil { 4406 t.Fatal("should error") 4407 } 4408 4409 checkStateString(t, state, ` 4410 aws_instance.foo: 4411 ID = bar 4412 `) 4413 4414 // Verify apply was invoked 4415 if !pr.ApplyCalled { 4416 t.Fatalf("provisioner not invoked") 4417 } 4418 } 4419 4420 // Verify that on destroy provisioner failure with "continue" that 4421 // we continue to the next provisioner. 4422 func TestContext2Apply_provisionerDestroyFailContinue(t *testing.T) { 4423 m := testModule(t, "apply-provisioner-destroy-continue") 4424 p := testProvider("aws") 4425 pr := testProvisioner() 4426 p.ApplyFn = testApplyFn 4427 p.DiffFn = testDiffFn 4428 4429 var calls []string 4430 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4431 val, ok := c.Config["foo"] 4432 if !ok { 4433 t.Fatalf("bad value for foo: %v %#v", val, c) 4434 } 4435 4436 calls = append(calls, val.(string)) 4437 return fmt.Errorf("provisioner error") 4438 } 4439 4440 state := &State{ 4441 Modules: []*ModuleState{ 4442 &ModuleState{ 4443 Path: rootModulePath, 4444 Resources: map[string]*ResourceState{ 4445 "aws_instance.foo": &ResourceState{ 4446 Type: "aws_instance", 4447 Primary: &InstanceState{ 4448 ID: "bar", 4449 }, 4450 }, 4451 }, 4452 }, 4453 }, 4454 } 4455 4456 ctx := testContext2(t, &ContextOpts{ 4457 Module: m, 4458 State: state, 4459 Destroy: true, 4460 Providers: map[string]ResourceProviderFactory{ 4461 "aws": testProviderFuncFixed(p), 4462 }, 4463 Provisioners: map[string]ResourceProvisionerFactory{ 4464 "shell": testProvisionerFuncFixed(pr), 4465 }, 4466 }) 4467 4468 if _, err := ctx.Plan(); err != nil { 4469 t.Fatalf("err: %s", err) 4470 } 4471 4472 state, err := ctx.Apply() 4473 if err != nil { 4474 t.Fatalf("err: %s", err) 4475 } 4476 4477 checkStateString(t, state, `<no state>`) 4478 4479 // Verify apply was invoked 4480 if !pr.ApplyCalled { 4481 t.Fatalf("provisioner not invoked") 4482 } 4483 4484 expected := []string{"one", "two"} 4485 if !reflect.DeepEqual(calls, expected) { 4486 t.Fatalf("bad: %#v", calls) 4487 } 4488 } 4489 4490 // Verify that on destroy provisioner failure with "continue" that 4491 // we continue to the next provisioner. But if the next provisioner defines 4492 // to fail, then we fail after running it. 4493 func TestContext2Apply_provisionerDestroyFailContinueFail(t *testing.T) { 4494 m := testModule(t, "apply-provisioner-destroy-fail") 4495 p := testProvider("aws") 4496 pr := testProvisioner() 4497 p.ApplyFn = testApplyFn 4498 p.DiffFn = testDiffFn 4499 4500 var calls []string 4501 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4502 val, ok := c.Config["foo"] 4503 if !ok { 4504 t.Fatalf("bad value for foo: %v %#v", val, c) 4505 } 4506 4507 calls = append(calls, val.(string)) 4508 return fmt.Errorf("provisioner error") 4509 } 4510 4511 state := &State{ 4512 Modules: []*ModuleState{ 4513 &ModuleState{ 4514 Path: rootModulePath, 4515 Resources: map[string]*ResourceState{ 4516 "aws_instance.foo": &ResourceState{ 4517 Type: "aws_instance", 4518 Primary: &InstanceState{ 4519 ID: "bar", 4520 }, 4521 }, 4522 }, 4523 }, 4524 }, 4525 } 4526 4527 ctx := testContext2(t, &ContextOpts{ 4528 Module: m, 4529 State: state, 4530 Destroy: true, 4531 Providers: map[string]ResourceProviderFactory{ 4532 "aws": testProviderFuncFixed(p), 4533 }, 4534 Provisioners: map[string]ResourceProvisionerFactory{ 4535 "shell": testProvisionerFuncFixed(pr), 4536 }, 4537 }) 4538 4539 if _, err := ctx.Plan(); err != nil { 4540 t.Fatalf("err: %s", err) 4541 } 4542 4543 state, err := ctx.Apply() 4544 if err == nil { 4545 t.Fatal("should error") 4546 } 4547 4548 checkStateString(t, state, ` 4549 aws_instance.foo: 4550 ID = bar 4551 `) 4552 4553 // Verify apply was invoked 4554 if !pr.ApplyCalled { 4555 t.Fatalf("provisioner not invoked") 4556 } 4557 4558 expected := []string{"one", "two"} 4559 if !reflect.DeepEqual(calls, expected) { 4560 t.Fatalf("bad: %#v", calls) 4561 } 4562 } 4563 4564 // Verify destroy provisioners are not run for tainted instances. 4565 func TestContext2Apply_provisionerDestroyTainted(t *testing.T) { 4566 m := testModule(t, "apply-provisioner-destroy") 4567 p := testProvider("aws") 4568 pr := testProvisioner() 4569 p.ApplyFn = testApplyFn 4570 p.DiffFn = testDiffFn 4571 4572 destroyCalled := false 4573 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4574 expected := "create" 4575 if rs.ID == "bar" { 4576 destroyCalled = true 4577 return nil 4578 } 4579 4580 val, ok := c.Config["foo"] 4581 if !ok || val != expected { 4582 t.Fatalf("bad value for foo: %v %#v", val, c) 4583 } 4584 4585 return nil 4586 } 4587 4588 state := &State{ 4589 Modules: []*ModuleState{ 4590 &ModuleState{ 4591 Path: rootModulePath, 4592 Resources: map[string]*ResourceState{ 4593 "aws_instance.foo": &ResourceState{ 4594 Type: "aws_instance", 4595 Primary: &InstanceState{ 4596 ID: "bar", 4597 Tainted: true, 4598 }, 4599 }, 4600 }, 4601 }, 4602 }, 4603 } 4604 4605 ctx := testContext2(t, &ContextOpts{ 4606 Module: m, 4607 State: state, 4608 Providers: map[string]ResourceProviderFactory{ 4609 "aws": testProviderFuncFixed(p), 4610 }, 4611 Provisioners: map[string]ResourceProvisionerFactory{ 4612 "shell": testProvisionerFuncFixed(pr), 4613 }, 4614 }) 4615 4616 if _, err := ctx.Plan(); err != nil { 4617 t.Fatalf("err: %s", err) 4618 } 4619 4620 state, err := ctx.Apply() 4621 if err != nil { 4622 t.Fatalf("err: %s", err) 4623 } 4624 4625 checkStateString(t, state, ` 4626 aws_instance.foo: 4627 ID = foo 4628 foo = bar 4629 type = aws_instance 4630 `) 4631 4632 // Verify apply was invoked 4633 if !pr.ApplyCalled { 4634 t.Fatalf("provisioner not invoked") 4635 } 4636 4637 if destroyCalled { 4638 t.Fatal("destroy should not be called") 4639 } 4640 } 4641 4642 func TestContext2Apply_provisionerDestroyModule(t *testing.T) { 4643 m := testModule(t, "apply-provisioner-destroy-module") 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 val, ok := c.Config["foo"] 4650 if !ok || val != "value" { 4651 t.Fatalf("bad value for foo: %v %#v", val, c) 4652 } 4653 4654 return nil 4655 } 4656 4657 state := &State{ 4658 Modules: []*ModuleState{ 4659 &ModuleState{ 4660 Path: []string{"root", "child"}, 4661 Resources: map[string]*ResourceState{ 4662 "aws_instance.foo": &ResourceState{ 4663 Type: "aws_instance", 4664 Primary: &InstanceState{ 4665 ID: "bar", 4666 }, 4667 }, 4668 }, 4669 }, 4670 }, 4671 } 4672 4673 ctx := testContext2(t, &ContextOpts{ 4674 Module: m, 4675 State: state, 4676 Destroy: true, 4677 Providers: map[string]ResourceProviderFactory{ 4678 "aws": testProviderFuncFixed(p), 4679 }, 4680 Provisioners: map[string]ResourceProvisionerFactory{ 4681 "shell": testProvisionerFuncFixed(pr), 4682 }, 4683 }) 4684 4685 if _, err := ctx.Plan(); err != nil { 4686 t.Fatalf("err: %s", err) 4687 } 4688 4689 state, err := ctx.Apply() 4690 if err != nil { 4691 t.Fatalf("err: %s", err) 4692 } 4693 4694 checkStateString(t, state, ` 4695 module.child: 4696 <no state>`) 4697 4698 // Verify apply was invoked 4699 if !pr.ApplyCalled { 4700 t.Fatalf("provisioner not invoked") 4701 } 4702 } 4703 4704 func TestContext2Apply_provisionerDestroyRef(t *testing.T) { 4705 m := testModule(t, "apply-provisioner-destroy-ref") 4706 p := testProvider("aws") 4707 pr := testProvisioner() 4708 p.ApplyFn = testApplyFn 4709 p.DiffFn = testDiffFn 4710 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4711 val, ok := c.Config["foo"] 4712 if !ok || val != "hello" { 4713 return fmt.Errorf("bad value for foo: %v %#v", val, c) 4714 } 4715 4716 return nil 4717 } 4718 4719 state := &State{ 4720 Modules: []*ModuleState{ 4721 &ModuleState{ 4722 Path: rootModulePath, 4723 Resources: map[string]*ResourceState{ 4724 "aws_instance.bar": &ResourceState{ 4725 Type: "aws_instance", 4726 Primary: &InstanceState{ 4727 ID: "bar", 4728 Attributes: map[string]string{ 4729 "key": "hello", 4730 }, 4731 }, 4732 }, 4733 4734 "aws_instance.foo": &ResourceState{ 4735 Type: "aws_instance", 4736 Primary: &InstanceState{ 4737 ID: "bar", 4738 }, 4739 }, 4740 }, 4741 }, 4742 }, 4743 } 4744 4745 ctx := testContext2(t, &ContextOpts{ 4746 Module: m, 4747 State: state, 4748 Destroy: true, 4749 Providers: map[string]ResourceProviderFactory{ 4750 "aws": testProviderFuncFixed(p), 4751 }, 4752 Provisioners: map[string]ResourceProvisionerFactory{ 4753 "shell": testProvisionerFuncFixed(pr), 4754 }, 4755 }) 4756 4757 if _, err := ctx.Plan(); err != nil { 4758 t.Fatalf("err: %s", err) 4759 } 4760 4761 state, err := ctx.Apply() 4762 if err != nil { 4763 t.Fatalf("err: %s", err) 4764 } 4765 4766 checkStateString(t, state, `<no state>`) 4767 4768 // Verify apply was invoked 4769 if !pr.ApplyCalled { 4770 t.Fatalf("provisioner not invoked") 4771 } 4772 } 4773 4774 // Test that a destroy provisioner referencing an invalid key errors. 4775 func TestContext2Apply_provisionerDestroyRefInvalid(t *testing.T) { 4776 m := testModule(t, "apply-provisioner-destroy-ref") 4777 p := testProvider("aws") 4778 pr := testProvisioner() 4779 p.ApplyFn = testApplyFn 4780 p.DiffFn = testDiffFn 4781 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4782 return nil 4783 } 4784 4785 state := &State{ 4786 Modules: []*ModuleState{ 4787 &ModuleState{ 4788 Path: rootModulePath, 4789 Resources: map[string]*ResourceState{ 4790 "aws_instance.bar": &ResourceState{ 4791 Type: "aws_instance", 4792 Primary: &InstanceState{ 4793 ID: "bar", 4794 }, 4795 }, 4796 4797 "aws_instance.foo": &ResourceState{ 4798 Type: "aws_instance", 4799 Primary: &InstanceState{ 4800 ID: "bar", 4801 }, 4802 }, 4803 }, 4804 }, 4805 }, 4806 } 4807 4808 ctx := testContext2(t, &ContextOpts{ 4809 Module: m, 4810 State: state, 4811 Destroy: true, 4812 Providers: map[string]ResourceProviderFactory{ 4813 "aws": testProviderFuncFixed(p), 4814 }, 4815 Provisioners: map[string]ResourceProvisionerFactory{ 4816 "shell": testProvisionerFuncFixed(pr), 4817 }, 4818 }) 4819 4820 if _, err := ctx.Plan(); err != nil { 4821 t.Fatalf("err: %s", err) 4822 } 4823 4824 if _, err := ctx.Apply(); err == nil { 4825 t.Fatal("expected error") 4826 } 4827 } 4828 4829 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 4830 m := testModule(t, "apply-provisioner-resource-ref") 4831 p := testProvider("aws") 4832 pr := testProvisioner() 4833 p.ApplyFn = testApplyFn 4834 p.DiffFn = testDiffFn 4835 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4836 val, ok := c.Config["foo"] 4837 if !ok || val != "2" { 4838 t.Fatalf("bad value for foo: %v %#v", val, c) 4839 } 4840 4841 return nil 4842 } 4843 4844 ctx := testContext2(t, &ContextOpts{ 4845 Module: m, 4846 Providers: map[string]ResourceProviderFactory{ 4847 "aws": testProviderFuncFixed(p), 4848 }, 4849 Provisioners: map[string]ResourceProvisionerFactory{ 4850 "shell": testProvisionerFuncFixed(pr), 4851 }, 4852 }) 4853 4854 if _, err := ctx.Plan(); err != nil { 4855 t.Fatalf("err: %s", err) 4856 } 4857 4858 state, err := ctx.Apply() 4859 if err != nil { 4860 t.Fatalf("err: %s", err) 4861 } 4862 4863 actual := strings.TrimSpace(state.String()) 4864 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 4865 if actual != expected { 4866 t.Fatalf("bad: \n%s", actual) 4867 } 4868 4869 // Verify apply was invoked 4870 if !pr.ApplyCalled { 4871 t.Fatalf("provisioner not invoked") 4872 } 4873 } 4874 4875 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 4876 m := testModule(t, "apply-provisioner-self-ref") 4877 p := testProvider("aws") 4878 pr := testProvisioner() 4879 p.ApplyFn = testApplyFn 4880 p.DiffFn = testDiffFn 4881 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4882 val, ok := c.Config["command"] 4883 if !ok || val != "bar" { 4884 t.Fatalf("bad value for command: %v %#v", val, c) 4885 } 4886 4887 return nil 4888 } 4889 4890 ctx := testContext2(t, &ContextOpts{ 4891 Module: m, 4892 Providers: map[string]ResourceProviderFactory{ 4893 "aws": testProviderFuncFixed(p), 4894 }, 4895 Provisioners: map[string]ResourceProvisionerFactory{ 4896 "shell": testProvisionerFuncFixed(pr), 4897 }, 4898 }) 4899 4900 if _, err := ctx.Plan(); err != nil { 4901 t.Fatalf("err: %s", err) 4902 } 4903 4904 state, err := ctx.Apply() 4905 if err != nil { 4906 t.Fatalf("err: %s", err) 4907 } 4908 4909 actual := strings.TrimSpace(state.String()) 4910 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 4911 if actual != expected { 4912 t.Fatalf("bad: \n%s", actual) 4913 } 4914 4915 // Verify apply was invoked 4916 if !pr.ApplyCalled { 4917 t.Fatalf("provisioner not invoked") 4918 } 4919 } 4920 4921 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 4922 var lock sync.Mutex 4923 commands := make([]string, 0, 5) 4924 4925 m := testModule(t, "apply-provisioner-multi-self-ref") 4926 p := testProvider("aws") 4927 pr := testProvisioner() 4928 p.ApplyFn = testApplyFn 4929 p.DiffFn = testDiffFn 4930 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4931 lock.Lock() 4932 defer lock.Unlock() 4933 4934 val, ok := c.Config["command"] 4935 if !ok { 4936 t.Fatalf("bad value for command: %v %#v", val, c) 4937 } 4938 4939 commands = append(commands, val.(string)) 4940 return nil 4941 } 4942 4943 ctx := testContext2(t, &ContextOpts{ 4944 Module: m, 4945 Providers: map[string]ResourceProviderFactory{ 4946 "aws": testProviderFuncFixed(p), 4947 }, 4948 Provisioners: map[string]ResourceProvisionerFactory{ 4949 "shell": testProvisionerFuncFixed(pr), 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(testTerraformApplyProvisionerMultiSelfRefStr) 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 // Verify our result 4974 sort.Strings(commands) 4975 expectedCommands := []string{"number 0", "number 1", "number 2"} 4976 if !reflect.DeepEqual(commands, expectedCommands) { 4977 t.Fatalf("bad: %#v", commands) 4978 } 4979 } 4980 4981 func TestContext2Apply_provisionerMultiSelfRefSingle(t *testing.T) { 4982 var lock sync.Mutex 4983 order := make([]string, 0, 5) 4984 4985 m := testModule(t, "apply-provisioner-multi-self-ref-single") 4986 p := testProvider("aws") 4987 pr := testProvisioner() 4988 p.ApplyFn = testApplyFn 4989 p.DiffFn = testDiffFn 4990 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4991 lock.Lock() 4992 defer lock.Unlock() 4993 4994 val, ok := c.Config["order"] 4995 if !ok { 4996 t.Fatalf("bad value for order: %v %#v", val, c) 4997 } 4998 4999 order = append(order, val.(string)) 5000 return nil 5001 } 5002 5003 ctx := testContext2(t, &ContextOpts{ 5004 Module: m, 5005 Providers: map[string]ResourceProviderFactory{ 5006 "aws": testProviderFuncFixed(p), 5007 }, 5008 Provisioners: map[string]ResourceProvisionerFactory{ 5009 "shell": testProvisionerFuncFixed(pr), 5010 }, 5011 }) 5012 5013 if _, err := ctx.Plan(); err != nil { 5014 t.Fatalf("err: %s", err) 5015 } 5016 5017 state, err := ctx.Apply() 5018 if err != nil { 5019 t.Fatalf("err: %s", err) 5020 } 5021 5022 actual := strings.TrimSpace(state.String()) 5023 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefSingleStr) 5024 if actual != expected { 5025 t.Fatalf("bad: \n%s", actual) 5026 } 5027 5028 // Verify apply was invoked 5029 if !pr.ApplyCalled { 5030 t.Fatalf("provisioner not invoked") 5031 } 5032 5033 // Verify our result 5034 sort.Strings(order) 5035 expectedOrder := []string{"0", "1", "2"} 5036 if !reflect.DeepEqual(order, expectedOrder) { 5037 t.Fatalf("bad: %#v", order) 5038 } 5039 } 5040 5041 func TestContext2Apply_provisionerMultiSelfRefCount(t *testing.T) { 5042 var lock sync.Mutex 5043 commands := make([]string, 0, 5) 5044 5045 m := testModule(t, "apply-provisioner-multi-self-ref-count") 5046 p := testProvider("aws") 5047 pr := testProvisioner() 5048 p.ApplyFn = testApplyFn 5049 p.DiffFn = testDiffFn 5050 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5051 lock.Lock() 5052 defer lock.Unlock() 5053 5054 val, ok := c.Config["command"] 5055 if !ok { 5056 t.Fatalf("bad value for command: %v %#v", val, c) 5057 } 5058 5059 commands = append(commands, val.(string)) 5060 return nil 5061 } 5062 5063 ctx := testContext2(t, &ContextOpts{ 5064 Module: m, 5065 Providers: map[string]ResourceProviderFactory{ 5066 "aws": testProviderFuncFixed(p), 5067 }, 5068 Provisioners: map[string]ResourceProvisionerFactory{ 5069 "shell": testProvisionerFuncFixed(pr), 5070 }, 5071 }) 5072 5073 if _, err := ctx.Plan(); err != nil { 5074 t.Fatalf("err: %s", err) 5075 } 5076 5077 if _, err := ctx.Apply(); err != nil { 5078 t.Fatalf("err: %s", err) 5079 } 5080 5081 // Verify apply was invoked 5082 if !pr.ApplyCalled { 5083 t.Fatalf("provisioner not invoked") 5084 } 5085 5086 // Verify our result 5087 sort.Strings(commands) 5088 expectedCommands := []string{"3", "3", "3"} 5089 if !reflect.DeepEqual(commands, expectedCommands) { 5090 t.Fatalf("bad: %#v", commands) 5091 } 5092 } 5093 5094 func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) { 5095 m := testModule(t, "apply-provisioner-explicit-self-ref") 5096 p := testProvider("aws") 5097 pr := testProvisioner() 5098 p.ApplyFn = testApplyFn 5099 p.DiffFn = testDiffFn 5100 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5101 val, ok := c.Config["command"] 5102 if !ok || val != "bar" { 5103 t.Fatalf("bad value for command: %v %#v", val, c) 5104 } 5105 5106 return nil 5107 } 5108 5109 var state *State 5110 { 5111 ctx := testContext2(t, &ContextOpts{ 5112 Module: m, 5113 Providers: map[string]ResourceProviderFactory{ 5114 "aws": testProviderFuncFixed(p), 5115 }, 5116 Provisioners: map[string]ResourceProvisionerFactory{ 5117 "shell": testProvisionerFuncFixed(pr), 5118 }, 5119 }) 5120 5121 _, err := ctx.Plan() 5122 if err != nil { 5123 t.Fatalf("err: %s", err) 5124 } 5125 5126 state, err = ctx.Apply() 5127 if err != nil { 5128 t.Fatalf("err: %s", err) 5129 } 5130 5131 // Verify apply was invoked 5132 if !pr.ApplyCalled { 5133 t.Fatalf("provisioner not invoked") 5134 } 5135 } 5136 5137 { 5138 ctx := testContext2(t, &ContextOpts{ 5139 Module: m, 5140 Destroy: true, 5141 State: state, 5142 Providers: map[string]ResourceProviderFactory{ 5143 "aws": testProviderFuncFixed(p), 5144 }, 5145 Provisioners: map[string]ResourceProvisionerFactory{ 5146 "shell": testProvisionerFuncFixed(pr), 5147 }, 5148 }) 5149 5150 _, err := ctx.Plan() 5151 if err != nil { 5152 t.Fatalf("err: %s", err) 5153 } 5154 5155 state, err = ctx.Apply() 5156 if err != nil { 5157 t.Fatalf("err: %s", err) 5158 } 5159 5160 checkStateString(t, state, `<no state>`) 5161 } 5162 } 5163 5164 // Provisioner should NOT run on a diff, only create 5165 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 5166 m := testModule(t, "apply-provisioner-diff") 5167 p := testProvider("aws") 5168 pr := testProvisioner() 5169 p.ApplyFn = testApplyFn 5170 p.DiffFn = testDiffFn 5171 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5172 return nil 5173 } 5174 ctx := testContext2(t, &ContextOpts{ 5175 Module: m, 5176 Providers: map[string]ResourceProviderFactory{ 5177 "aws": testProviderFuncFixed(p), 5178 }, 5179 Provisioners: map[string]ResourceProvisionerFactory{ 5180 "shell": testProvisionerFuncFixed(pr), 5181 }, 5182 }) 5183 5184 if _, err := ctx.Plan(); err != nil { 5185 t.Fatalf("err: %s", err) 5186 } 5187 5188 state, err := ctx.Apply() 5189 if err != nil { 5190 t.Fatalf("err: %s", err) 5191 } 5192 5193 actual := strings.TrimSpace(state.String()) 5194 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 5195 if actual != expected { 5196 t.Fatalf("bad: \n%s", actual) 5197 } 5198 5199 // Verify apply was invoked 5200 if !pr.ApplyCalled { 5201 t.Fatalf("provisioner not invoked") 5202 } 5203 pr.ApplyCalled = false 5204 5205 // Change the state to force a diff 5206 mod := state.RootModule() 5207 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 5208 5209 // Re-create context with state 5210 ctx = testContext2(t, &ContextOpts{ 5211 Module: m, 5212 Providers: map[string]ResourceProviderFactory{ 5213 "aws": testProviderFuncFixed(p), 5214 }, 5215 Provisioners: map[string]ResourceProvisionerFactory{ 5216 "shell": testProvisionerFuncFixed(pr), 5217 }, 5218 State: state, 5219 }) 5220 5221 if _, err := ctx.Plan(); err != nil { 5222 t.Fatalf("err: %s", err) 5223 } 5224 5225 state2, err := ctx.Apply() 5226 if err != nil { 5227 t.Fatalf("err: %s", err) 5228 } 5229 5230 actual = strings.TrimSpace(state2.String()) 5231 if actual != expected { 5232 t.Fatalf("bad: \n%s", actual) 5233 } 5234 5235 // Verify apply was NOT invoked 5236 if pr.ApplyCalled { 5237 t.Fatalf("provisioner invoked") 5238 } 5239 } 5240 5241 func TestContext2Apply_outputDiffVars(t *testing.T) { 5242 m := testModule(t, "apply-good") 5243 p := testProvider("aws") 5244 s := &State{ 5245 Modules: []*ModuleState{ 5246 &ModuleState{ 5247 Path: rootModulePath, 5248 Resources: map[string]*ResourceState{ 5249 "aws_instance.baz": &ResourceState{ 5250 Type: "aws_instance", 5251 Primary: &InstanceState{ 5252 ID: "bar", 5253 }, 5254 }, 5255 }, 5256 }, 5257 }, 5258 } 5259 ctx := testContext2(t, &ContextOpts{ 5260 Module: m, 5261 Providers: map[string]ResourceProviderFactory{ 5262 "aws": testProviderFuncFixed(p), 5263 }, 5264 State: s, 5265 }) 5266 5267 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5268 for k, ad := range d.Attributes { 5269 if ad.NewComputed { 5270 return nil, fmt.Errorf("%s: computed", k) 5271 } 5272 } 5273 5274 result := s.MergeDiff(d) 5275 result.ID = "foo" 5276 return result, nil 5277 } 5278 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 5279 return &InstanceDiff{ 5280 Attributes: map[string]*ResourceAttrDiff{ 5281 "foo": &ResourceAttrDiff{ 5282 NewComputed: true, 5283 Type: DiffAttrOutput, 5284 }, 5285 "bar": &ResourceAttrDiff{ 5286 New: "baz", 5287 }, 5288 }, 5289 }, nil 5290 } 5291 5292 if _, err := ctx.Plan(); err != nil { 5293 t.Fatalf("err: %s", err) 5294 } 5295 if _, err := ctx.Apply(); err != nil { 5296 t.Fatalf("err: %s", err) 5297 } 5298 } 5299 5300 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 5301 m := testModule(t, "apply-provisioner-conninfo") 5302 p := testProvider("aws") 5303 pr := testProvisioner() 5304 5305 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5306 if s.Ephemeral.ConnInfo == nil { 5307 t.Fatalf("ConnInfo not initialized") 5308 } 5309 5310 result, _ := testApplyFn(info, s, d) 5311 result.Ephemeral.ConnInfo = map[string]string{ 5312 "type": "ssh", 5313 "host": "127.0.0.1", 5314 "port": "22", 5315 } 5316 return result, nil 5317 } 5318 p.DiffFn = testDiffFn 5319 5320 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 5321 conn := rs.Ephemeral.ConnInfo 5322 if conn["type"] != "telnet" { 5323 t.Fatalf("Bad: %#v", conn) 5324 } 5325 if conn["host"] != "127.0.0.1" { 5326 t.Fatalf("Bad: %#v", conn) 5327 } 5328 if conn["port"] != "2222" { 5329 t.Fatalf("Bad: %#v", conn) 5330 } 5331 if conn["user"] != "superuser" { 5332 t.Fatalf("Bad: %#v", conn) 5333 } 5334 if conn["pass"] != "test" { 5335 t.Fatalf("Bad: %#v", conn) 5336 } 5337 5338 return nil 5339 } 5340 5341 ctx := testContext2(t, &ContextOpts{ 5342 Module: m, 5343 Providers: map[string]ResourceProviderFactory{ 5344 "aws": testProviderFuncFixed(p), 5345 }, 5346 Provisioners: map[string]ResourceProvisionerFactory{ 5347 "shell": testProvisionerFuncFixed(pr), 5348 }, 5349 Variables: map[string]interface{}{ 5350 "value": "1", 5351 "pass": "test", 5352 }, 5353 }) 5354 5355 if _, err := ctx.Plan(); err != nil { 5356 t.Fatalf("err: %s", err) 5357 } 5358 5359 state, err := ctx.Apply() 5360 if err != nil { 5361 t.Fatalf("err: %s", err) 5362 } 5363 5364 actual := strings.TrimSpace(state.String()) 5365 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 5366 if actual != expected { 5367 t.Fatalf("bad: \n%s", actual) 5368 } 5369 5370 // Verify apply was invoked 5371 if !pr.ApplyCalled { 5372 t.Fatalf("provisioner not invoked") 5373 } 5374 } 5375 5376 func TestContext2Apply_destroyX(t *testing.T) { 5377 m := testModule(t, "apply-destroy") 5378 h := new(HookRecordApplyOrder) 5379 p := testProvider("aws") 5380 p.ApplyFn = testApplyFn 5381 p.DiffFn = testDiffFn 5382 ctx := testContext2(t, &ContextOpts{ 5383 Module: m, 5384 Hooks: []Hook{h}, 5385 Providers: map[string]ResourceProviderFactory{ 5386 "aws": testProviderFuncFixed(p), 5387 }, 5388 }) 5389 5390 // First plan and apply a create operation 5391 if _, err := ctx.Plan(); err != nil { 5392 t.Fatalf("err: %s", err) 5393 } 5394 5395 state, err := ctx.Apply() 5396 if err != nil { 5397 t.Fatalf("err: %s", err) 5398 } 5399 5400 // Next, plan and apply a destroy operation 5401 h.Active = true 5402 ctx = testContext2(t, &ContextOpts{ 5403 Destroy: true, 5404 State: state, 5405 Module: m, 5406 Hooks: []Hook{h}, 5407 Providers: map[string]ResourceProviderFactory{ 5408 "aws": testProviderFuncFixed(p), 5409 }, 5410 }) 5411 5412 if _, err := ctx.Plan(); err != nil { 5413 t.Fatalf("err: %s", err) 5414 } 5415 5416 state, err = ctx.Apply() 5417 if err != nil { 5418 t.Fatalf("err: %s", err) 5419 } 5420 5421 // Test that things were destroyed 5422 actual := strings.TrimSpace(state.String()) 5423 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 5424 if actual != expected { 5425 t.Fatalf("bad: \n%s", actual) 5426 } 5427 5428 // Test that things were destroyed _in the right order_ 5429 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 5430 actual2 := h.IDs 5431 if !reflect.DeepEqual(actual2, expected2) { 5432 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 5433 } 5434 } 5435 5436 func TestContext2Apply_destroyOrder(t *testing.T) { 5437 m := testModule(t, "apply-destroy") 5438 h := new(HookRecordApplyOrder) 5439 p := testProvider("aws") 5440 p.ApplyFn = testApplyFn 5441 p.DiffFn = testDiffFn 5442 ctx := testContext2(t, &ContextOpts{ 5443 Module: m, 5444 Hooks: []Hook{h}, 5445 Providers: map[string]ResourceProviderFactory{ 5446 "aws": testProviderFuncFixed(p), 5447 }, 5448 }) 5449 5450 // First plan and apply a create operation 5451 if _, err := ctx.Plan(); err != nil { 5452 t.Fatalf("err: %s", err) 5453 } 5454 5455 state, err := ctx.Apply() 5456 if err != nil { 5457 t.Fatalf("err: %s", err) 5458 } 5459 5460 t.Logf("State 1: %s", state) 5461 5462 // Next, plan and apply config-less to force a destroy with "apply" 5463 h.Active = true 5464 ctx = testContext2(t, &ContextOpts{ 5465 State: state, 5466 Module: module.NewEmptyTree(), 5467 Hooks: []Hook{h}, 5468 Providers: map[string]ResourceProviderFactory{ 5469 "aws": testProviderFuncFixed(p), 5470 }, 5471 }) 5472 5473 if _, err := ctx.Plan(); err != nil { 5474 t.Fatalf("err: %s", err) 5475 } 5476 5477 state, err = ctx.Apply() 5478 if err != nil { 5479 t.Fatalf("err: %s", err) 5480 } 5481 5482 // Test that things were destroyed 5483 actual := strings.TrimSpace(state.String()) 5484 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 5485 if actual != expected { 5486 t.Fatalf("bad: \n%s", actual) 5487 } 5488 5489 // Test that things were destroyed _in the right order_ 5490 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 5491 actual2 := h.IDs 5492 if !reflect.DeepEqual(actual2, expected2) { 5493 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 5494 } 5495 } 5496 5497 // https://github.com/hashicorp/terraform/issues/2767 5498 func TestContext2Apply_destroyModulePrefix(t *testing.T) { 5499 m := testModule(t, "apply-destroy-module-resource-prefix") 5500 h := new(MockHook) 5501 p := testProvider("aws") 5502 p.ApplyFn = testApplyFn 5503 p.DiffFn = testDiffFn 5504 ctx := testContext2(t, &ContextOpts{ 5505 Module: m, 5506 Hooks: []Hook{h}, 5507 Providers: map[string]ResourceProviderFactory{ 5508 "aws": testProviderFuncFixed(p), 5509 }, 5510 }) 5511 5512 // First plan and apply a create operation 5513 if _, err := ctx.Plan(); err != nil { 5514 t.Fatalf("err: %s", err) 5515 } 5516 5517 state, err := ctx.Apply() 5518 if err != nil { 5519 t.Fatalf("err: %s", err) 5520 } 5521 5522 // Verify that we got the apply info correct 5523 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 5524 t.Fatalf("bad: %s", v) 5525 } 5526 5527 // Next, plan and apply a destroy operation and reset the hook 5528 h = new(MockHook) 5529 ctx = testContext2(t, &ContextOpts{ 5530 Destroy: true, 5531 State: state, 5532 Module: m, 5533 Hooks: []Hook{h}, 5534 Providers: map[string]ResourceProviderFactory{ 5535 "aws": testProviderFuncFixed(p), 5536 }, 5537 }) 5538 5539 if _, err := ctx.Plan(); err != nil { 5540 t.Fatalf("err: %s", err) 5541 } 5542 5543 state, err = ctx.Apply() 5544 if err != nil { 5545 t.Fatalf("err: %s", err) 5546 } 5547 5548 // Test that things were destroyed 5549 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 5550 t.Fatalf("bad: %s", v) 5551 } 5552 } 5553 5554 func TestContext2Apply_destroyNestedModule(t *testing.T) { 5555 m := testModule(t, "apply-destroy-nested-module") 5556 p := testProvider("aws") 5557 p.ApplyFn = testApplyFn 5558 p.DiffFn = testDiffFn 5559 5560 s := &State{ 5561 Modules: []*ModuleState{ 5562 &ModuleState{ 5563 Path: []string{"root", "child", "subchild"}, 5564 Resources: map[string]*ResourceState{ 5565 "aws_instance.bar": &ResourceState{ 5566 Type: "aws_instance", 5567 Primary: &InstanceState{ 5568 ID: "bar", 5569 }, 5570 }, 5571 }, 5572 }, 5573 }, 5574 } 5575 5576 ctx := testContext2(t, &ContextOpts{ 5577 Module: m, 5578 Providers: map[string]ResourceProviderFactory{ 5579 "aws": testProviderFuncFixed(p), 5580 }, 5581 State: s, 5582 }) 5583 5584 // First plan and apply a create operation 5585 if _, err := ctx.Plan(); err != nil { 5586 t.Fatalf("err: %s", err) 5587 } 5588 5589 state, err := ctx.Apply() 5590 if err != nil { 5591 t.Fatalf("err: %s", err) 5592 } 5593 5594 // Test that things were destroyed 5595 actual := strings.TrimSpace(state.String()) 5596 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 5597 if actual != expected { 5598 t.Fatalf("bad: \n%s", actual) 5599 } 5600 } 5601 5602 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 5603 m := testModule(t, "apply-destroy-deeply-nested-module") 5604 p := testProvider("aws") 5605 p.ApplyFn = testApplyFn 5606 p.DiffFn = testDiffFn 5607 5608 s := &State{ 5609 Modules: []*ModuleState{ 5610 &ModuleState{ 5611 Path: []string{"root", "child", "subchild", "subsubchild"}, 5612 Resources: map[string]*ResourceState{ 5613 "aws_instance.bar": &ResourceState{ 5614 Type: "aws_instance", 5615 Primary: &InstanceState{ 5616 ID: "bar", 5617 }, 5618 }, 5619 }, 5620 }, 5621 }, 5622 } 5623 5624 ctx := testContext2(t, &ContextOpts{ 5625 Module: m, 5626 Providers: map[string]ResourceProviderFactory{ 5627 "aws": testProviderFuncFixed(p), 5628 }, 5629 State: s, 5630 }) 5631 5632 // First plan and apply a create operation 5633 if _, err := ctx.Plan(); err != nil { 5634 t.Fatalf("err: %s", err) 5635 } 5636 5637 state, err := ctx.Apply() 5638 if err != nil { 5639 t.Fatalf("err: %s", err) 5640 } 5641 5642 // Test that things were destroyed 5643 actual := strings.TrimSpace(state.String()) 5644 expected := strings.TrimSpace(` 5645 module.child.subchild.subsubchild: 5646 <no state> 5647 `) 5648 if actual != expected { 5649 t.Fatalf("bad: \n%s", actual) 5650 } 5651 } 5652 5653 // https://github.com/hashicorp/terraform/issues/5440 5654 func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { 5655 m := testModule(t, "apply-destroy-module-with-attrs") 5656 p := testProvider("aws") 5657 p.ApplyFn = testApplyFn 5658 p.DiffFn = testDiffFn 5659 5660 var state *State 5661 var err error 5662 { 5663 ctx := testContext2(t, &ContextOpts{ 5664 Module: m, 5665 Providers: map[string]ResourceProviderFactory{ 5666 "aws": testProviderFuncFixed(p), 5667 }, 5668 }) 5669 5670 // First plan and apply a create operation 5671 if p, err := ctx.Plan(); err != nil { 5672 t.Fatalf("plan err: %s", err) 5673 } else { 5674 t.Logf("Step 1 plan: %s", p) 5675 } 5676 5677 state, err = ctx.Apply() 5678 if err != nil { 5679 t.Fatalf("apply err: %s", err) 5680 } 5681 5682 t.Logf("Step 1 state: %s", state) 5683 } 5684 5685 h := new(HookRecordApplyOrder) 5686 h.Active = true 5687 5688 { 5689 ctx := testContext2(t, &ContextOpts{ 5690 Destroy: true, 5691 Module: m, 5692 State: state, 5693 Hooks: []Hook{h}, 5694 Providers: map[string]ResourceProviderFactory{ 5695 "aws": testProviderFuncFixed(p), 5696 }, 5697 Variables: map[string]interface{}{ 5698 "key_name": "foobarkey", 5699 }, 5700 }) 5701 5702 // First plan and apply a create operation 5703 plan, err := ctx.Plan() 5704 if err != nil { 5705 t.Fatalf("destroy plan err: %s", err) 5706 } 5707 5708 t.Logf("Step 2 plan: %s", plan) 5709 5710 var buf bytes.Buffer 5711 if err := WritePlan(plan, &buf); err != nil { 5712 t.Fatalf("plan write err: %s", err) 5713 } 5714 5715 planFromFile, err := ReadPlan(&buf) 5716 if err != nil { 5717 t.Fatalf("plan read err: %s", err) 5718 } 5719 5720 ctx, err = planFromFile.Context(&ContextOpts{ 5721 Providers: map[string]ResourceProviderFactory{ 5722 "aws": testProviderFuncFixed(p), 5723 }, 5724 }) 5725 if err != nil { 5726 t.Fatalf("err: %s", err) 5727 } 5728 5729 state, err = ctx.Apply() 5730 if err != nil { 5731 t.Fatalf("destroy apply err: %s", err) 5732 } 5733 5734 t.Logf("Step 2 state: %s", state) 5735 } 5736 5737 //Test that things were destroyed 5738 actual := strings.TrimSpace(state.String()) 5739 expected := strings.TrimSpace(` 5740 <no state> 5741 module.child: 5742 <no state> 5743 `) 5744 if actual != expected { 5745 t.Fatalf("expected:\n\n%s\n\nactual:\n\n%s", expected, actual) 5746 } 5747 } 5748 5749 func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { 5750 m := testModule(t, "apply-destroy-mod-var-and-count") 5751 p := testProvider("aws") 5752 p.ApplyFn = testApplyFn 5753 p.DiffFn = testDiffFn 5754 5755 var state *State 5756 var err error 5757 { 5758 ctx := testContext2(t, &ContextOpts{ 5759 Module: m, 5760 Providers: map[string]ResourceProviderFactory{ 5761 "aws": testProviderFuncFixed(p), 5762 }, 5763 }) 5764 5765 // First plan and apply a create operation 5766 if _, err := ctx.Plan(); err != nil { 5767 t.Fatalf("plan err: %s", err) 5768 } 5769 5770 state, err = ctx.Apply() 5771 if err != nil { 5772 t.Fatalf("apply err: %s", err) 5773 } 5774 } 5775 5776 h := new(HookRecordApplyOrder) 5777 h.Active = true 5778 5779 { 5780 ctx := testContext2(t, &ContextOpts{ 5781 Destroy: true, 5782 Module: m, 5783 State: state, 5784 Hooks: []Hook{h}, 5785 Providers: map[string]ResourceProviderFactory{ 5786 "aws": testProviderFuncFixed(p), 5787 }, 5788 }) 5789 5790 // First plan and apply a create operation 5791 plan, err := ctx.Plan() 5792 if err != nil { 5793 t.Fatalf("destroy plan err: %s", err) 5794 } 5795 5796 var buf bytes.Buffer 5797 if err := WritePlan(plan, &buf); err != nil { 5798 t.Fatalf("plan write err: %s", err) 5799 } 5800 5801 planFromFile, err := ReadPlan(&buf) 5802 if err != nil { 5803 t.Fatalf("plan read err: %s", err) 5804 } 5805 5806 ctx, err = planFromFile.Context(&ContextOpts{ 5807 Providers: map[string]ResourceProviderFactory{ 5808 "aws": testProviderFuncFixed(p), 5809 }, 5810 }) 5811 if err != nil { 5812 t.Fatalf("err: %s", err) 5813 } 5814 5815 state, err = ctx.Apply() 5816 if err != nil { 5817 t.Fatalf("destroy apply err: %s", err) 5818 } 5819 } 5820 5821 //Test that things were destroyed 5822 actual := strings.TrimSpace(state.String()) 5823 expected := strings.TrimSpace(` 5824 <no state> 5825 module.child: 5826 <no state> 5827 `) 5828 if actual != expected { 5829 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5830 } 5831 } 5832 5833 func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) { 5834 m := testModule(t, "apply-destroy-mod-var-and-count") 5835 p := testProvider("aws") 5836 p.ApplyFn = testApplyFn 5837 p.DiffFn = testDiffFn 5838 5839 var state *State 5840 var err error 5841 { 5842 ctx := testContext2(t, &ContextOpts{ 5843 Module: m, 5844 Providers: map[string]ResourceProviderFactory{ 5845 "aws": testProviderFuncFixed(p), 5846 }, 5847 }) 5848 5849 // First plan and apply a create operation 5850 if _, err := ctx.Plan(); err != nil { 5851 t.Fatalf("plan err: %s", err) 5852 } 5853 5854 state, err = ctx.Apply() 5855 if err != nil { 5856 t.Fatalf("apply err: %s", err) 5857 } 5858 } 5859 5860 { 5861 ctx := testContext2(t, &ContextOpts{ 5862 Destroy: true, 5863 Module: m, 5864 State: state, 5865 Providers: map[string]ResourceProviderFactory{ 5866 "aws": testProviderFuncFixed(p), 5867 }, 5868 Targets: []string{"module.child"}, 5869 }) 5870 5871 _, err := ctx.Plan() 5872 if err != nil { 5873 t.Fatalf("plan err: %s", err) 5874 } 5875 5876 // Destroy, targeting the module explicitly 5877 state, err = ctx.Apply() 5878 if err != nil { 5879 t.Fatalf("destroy apply err: %s", err) 5880 } 5881 } 5882 5883 //Test that things were destroyed 5884 actual := strings.TrimSpace(state.String()) 5885 expected := strings.TrimSpace(` 5886 <no state> 5887 module.child: 5888 <no state> 5889 `) 5890 if actual != expected { 5891 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5892 } 5893 } 5894 5895 func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { 5896 m := testModule(t, "apply-destroy-mod-var-and-count-nested") 5897 p := testProvider("aws") 5898 p.ApplyFn = testApplyFn 5899 p.DiffFn = testDiffFn 5900 5901 var state *State 5902 var err error 5903 { 5904 ctx := testContext2(t, &ContextOpts{ 5905 Module: m, 5906 Providers: map[string]ResourceProviderFactory{ 5907 "aws": testProviderFuncFixed(p), 5908 }, 5909 }) 5910 5911 // First plan and apply a create operation 5912 if _, err := ctx.Plan(); err != nil { 5913 t.Fatalf("plan err: %s", err) 5914 } 5915 5916 state, err = ctx.Apply() 5917 if err != nil { 5918 t.Fatalf("apply err: %s", err) 5919 } 5920 } 5921 5922 h := new(HookRecordApplyOrder) 5923 h.Active = true 5924 5925 { 5926 ctx := testContext2(t, &ContextOpts{ 5927 Destroy: true, 5928 Module: m, 5929 State: state, 5930 Hooks: []Hook{h}, 5931 Providers: map[string]ResourceProviderFactory{ 5932 "aws": testProviderFuncFixed(p), 5933 }, 5934 }) 5935 5936 // First plan and apply a create operation 5937 plan, err := ctx.Plan() 5938 if err != nil { 5939 t.Fatalf("destroy plan err: %s", err) 5940 } 5941 5942 var buf bytes.Buffer 5943 if err := WritePlan(plan, &buf); err != nil { 5944 t.Fatalf("plan write err: %s", err) 5945 } 5946 5947 planFromFile, err := ReadPlan(&buf) 5948 if err != nil { 5949 t.Fatalf("plan read err: %s", err) 5950 } 5951 5952 ctx, err = planFromFile.Context(&ContextOpts{ 5953 Providers: map[string]ResourceProviderFactory{ 5954 "aws": testProviderFuncFixed(p), 5955 }, 5956 }) 5957 if err != nil { 5958 t.Fatalf("err: %s", err) 5959 } 5960 5961 state, err = ctx.Apply() 5962 if err != nil { 5963 t.Fatalf("destroy apply err: %s", err) 5964 } 5965 } 5966 5967 //Test that things were destroyed 5968 actual := strings.TrimSpace(state.String()) 5969 expected := strings.TrimSpace(` 5970 <no state> 5971 module.child: 5972 <no state> 5973 module.child.child2: 5974 <no state> 5975 `) 5976 if actual != expected { 5977 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 5978 } 5979 } 5980 5981 func TestContext2Apply_destroyOutputs(t *testing.T) { 5982 m := testModule(t, "apply-destroy-outputs") 5983 h := new(HookRecordApplyOrder) 5984 p := testProvider("aws") 5985 p.ApplyFn = testApplyFn 5986 p.DiffFn = testDiffFn 5987 ctx := testContext2(t, &ContextOpts{ 5988 Module: m, 5989 Hooks: []Hook{h}, 5990 Providers: map[string]ResourceProviderFactory{ 5991 "aws": testProviderFuncFixed(p), 5992 }, 5993 }) 5994 5995 // First plan and apply a create operation 5996 if _, err := ctx.Plan(); err != nil { 5997 t.Fatalf("err: %s", err) 5998 } 5999 6000 state, err := ctx.Apply() 6001 6002 if err != nil { 6003 t.Fatalf("err: %s", err) 6004 } 6005 6006 // Next, plan and apply a destroy operation 6007 h.Active = true 6008 ctx = testContext2(t, &ContextOpts{ 6009 Destroy: true, 6010 State: state, 6011 Module: m, 6012 Hooks: []Hook{h}, 6013 Providers: map[string]ResourceProviderFactory{ 6014 "aws": testProviderFuncFixed(p), 6015 }, 6016 }) 6017 6018 if _, err := ctx.Plan(); err != nil { 6019 t.Fatalf("err: %s", err) 6020 } 6021 6022 state, err = ctx.Apply() 6023 if err != nil { 6024 t.Fatalf("err: %s", err) 6025 } 6026 6027 mod := state.RootModule() 6028 if len(mod.Resources) > 0 { 6029 t.Fatalf("bad: %#v", mod) 6030 } 6031 } 6032 6033 func TestContext2Apply_destroyOrphan(t *testing.T) { 6034 m := testModule(t, "apply-error") 6035 p := testProvider("aws") 6036 s := &State{ 6037 Modules: []*ModuleState{ 6038 &ModuleState{ 6039 Path: rootModulePath, 6040 Resources: map[string]*ResourceState{ 6041 "aws_instance.baz": &ResourceState{ 6042 Type: "aws_instance", 6043 Primary: &InstanceState{ 6044 ID: "bar", 6045 }, 6046 }, 6047 }, 6048 }, 6049 }, 6050 } 6051 ctx := testContext2(t, &ContextOpts{ 6052 Module: m, 6053 Providers: map[string]ResourceProviderFactory{ 6054 "aws": testProviderFuncFixed(p), 6055 }, 6056 State: s, 6057 }) 6058 6059 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6060 if d.Destroy { 6061 return nil, nil 6062 } 6063 6064 result := s.MergeDiff(d) 6065 result.ID = "foo" 6066 return result, nil 6067 } 6068 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 6069 return &InstanceDiff{ 6070 Attributes: map[string]*ResourceAttrDiff{ 6071 "num": &ResourceAttrDiff{ 6072 New: "bar", 6073 }, 6074 }, 6075 }, nil 6076 } 6077 6078 if _, err := ctx.Plan(); err != nil { 6079 t.Fatalf("err: %s", err) 6080 } 6081 6082 state, err := ctx.Apply() 6083 if err != nil { 6084 t.Fatalf("err: %s", err) 6085 } 6086 6087 mod := state.RootModule() 6088 if _, ok := mod.Resources["aws_instance.baz"]; ok { 6089 t.Fatalf("bad: %#v", mod.Resources) 6090 } 6091 } 6092 6093 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 6094 m := testModule(t, "apply-destroy-provisioner") 6095 p := testProvider("aws") 6096 pr := testProvisioner() 6097 p.ApplyFn = testApplyFn 6098 p.DiffFn = testDiffFn 6099 6100 called := false 6101 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 6102 called = true 6103 return nil 6104 } 6105 6106 s := &State{ 6107 Modules: []*ModuleState{ 6108 &ModuleState{ 6109 Path: rootModulePath, 6110 Resources: map[string]*ResourceState{ 6111 "aws_instance.foo": &ResourceState{ 6112 Type: "aws_instance", 6113 Primary: &InstanceState{ 6114 ID: "bar", 6115 Attributes: map[string]string{ 6116 "id": "bar", 6117 }, 6118 Tainted: true, 6119 }, 6120 }, 6121 }, 6122 }, 6123 }, 6124 } 6125 6126 ctx := testContext2(t, &ContextOpts{ 6127 Module: m, 6128 Providers: map[string]ResourceProviderFactory{ 6129 "aws": testProviderFuncFixed(p), 6130 }, 6131 Provisioners: map[string]ResourceProvisionerFactory{ 6132 "shell": testProvisionerFuncFixed(pr), 6133 }, 6134 State: s, 6135 Destroy: true, 6136 }) 6137 6138 if _, err := ctx.Plan(); err != nil { 6139 t.Fatalf("err: %s", err) 6140 } 6141 6142 state, err := ctx.Apply() 6143 if err != nil { 6144 t.Fatalf("err: %s", err) 6145 } 6146 6147 if called { 6148 t.Fatal("provisioner should not be called") 6149 } 6150 6151 actual := strings.TrimSpace(state.String()) 6152 expected := strings.TrimSpace("<no state>") 6153 if actual != expected { 6154 t.Fatalf("bad: \n%s", actual) 6155 } 6156 } 6157 6158 func TestContext2Apply_error(t *testing.T) { 6159 errored := false 6160 6161 m := testModule(t, "apply-error") 6162 p := testProvider("aws") 6163 ctx := testContext2(t, &ContextOpts{ 6164 Module: m, 6165 Providers: map[string]ResourceProviderFactory{ 6166 "aws": testProviderFuncFixed(p), 6167 }, 6168 }) 6169 6170 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 6171 if errored { 6172 state := &InstanceState{ 6173 ID: "bar", 6174 } 6175 return state, fmt.Errorf("error") 6176 } 6177 errored = true 6178 6179 return &InstanceState{ 6180 ID: "foo", 6181 Attributes: map[string]string{ 6182 "num": "2", 6183 }, 6184 }, nil 6185 } 6186 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 6187 return &InstanceDiff{ 6188 Attributes: map[string]*ResourceAttrDiff{ 6189 "num": &ResourceAttrDiff{ 6190 New: "bar", 6191 }, 6192 }, 6193 }, nil 6194 } 6195 6196 if _, err := ctx.Plan(); err != nil { 6197 t.Fatalf("err: %s", err) 6198 } 6199 6200 state, err := ctx.Apply() 6201 if err == nil { 6202 t.Fatal("should have error") 6203 } 6204 6205 actual := strings.TrimSpace(state.String()) 6206 expected := strings.TrimSpace(testTerraformApplyErrorStr) 6207 if actual != expected { 6208 t.Fatalf("bad: \n%s", actual) 6209 } 6210 } 6211 6212 func TestContext2Apply_errorPartial(t *testing.T) { 6213 errored := false 6214 6215 m := testModule(t, "apply-error") 6216 p := testProvider("aws") 6217 s := &State{ 6218 Modules: []*ModuleState{ 6219 &ModuleState{ 6220 Path: rootModulePath, 6221 Resources: map[string]*ResourceState{ 6222 "aws_instance.bar": &ResourceState{ 6223 Type: "aws_instance", 6224 Primary: &InstanceState{ 6225 ID: "bar", 6226 }, 6227 }, 6228 }, 6229 }, 6230 }, 6231 } 6232 ctx := testContext2(t, &ContextOpts{ 6233 Module: m, 6234 Providers: map[string]ResourceProviderFactory{ 6235 "aws": testProviderFuncFixed(p), 6236 }, 6237 State: s, 6238 }) 6239 6240 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6241 if errored { 6242 return s, fmt.Errorf("error") 6243 } 6244 errored = true 6245 6246 return &InstanceState{ 6247 ID: "foo", 6248 Attributes: map[string]string{ 6249 "num": "2", 6250 }, 6251 }, nil 6252 } 6253 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 6254 return &InstanceDiff{ 6255 Attributes: map[string]*ResourceAttrDiff{ 6256 "num": &ResourceAttrDiff{ 6257 New: "bar", 6258 }, 6259 }, 6260 }, nil 6261 } 6262 6263 if _, err := ctx.Plan(); err != nil { 6264 t.Fatalf("err: %s", err) 6265 } 6266 6267 state, err := ctx.Apply() 6268 if err == nil { 6269 t.Fatal("should have error") 6270 } 6271 6272 mod := state.RootModule() 6273 if len(mod.Resources) != 2 { 6274 t.Fatalf("bad: %#v", mod.Resources) 6275 } 6276 6277 actual := strings.TrimSpace(state.String()) 6278 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 6279 if actual != expected { 6280 t.Fatalf("bad: \n%s", actual) 6281 } 6282 } 6283 6284 func TestContext2Apply_hook(t *testing.T) { 6285 m := testModule(t, "apply-good") 6286 h := new(MockHook) 6287 p := testProvider("aws") 6288 p.ApplyFn = testApplyFn 6289 p.DiffFn = testDiffFn 6290 ctx := testContext2(t, &ContextOpts{ 6291 Module: m, 6292 Hooks: []Hook{h}, 6293 Providers: map[string]ResourceProviderFactory{ 6294 "aws": testProviderFuncFixed(p), 6295 }, 6296 }) 6297 6298 if _, err := ctx.Plan(); err != nil { 6299 t.Fatalf("err: %s", err) 6300 } 6301 6302 if _, err := ctx.Apply(); err != nil { 6303 t.Fatalf("err: %s", err) 6304 } 6305 6306 if !h.PreApplyCalled { 6307 t.Fatal("should be called") 6308 } 6309 if !h.PostApplyCalled { 6310 t.Fatal("should be called") 6311 } 6312 if !h.PostStateUpdateCalled { 6313 t.Fatalf("should call post state update") 6314 } 6315 } 6316 6317 func TestContext2Apply_hookOrphan(t *testing.T) { 6318 m := testModule(t, "apply-blank") 6319 h := new(MockHook) 6320 p := testProvider("aws") 6321 p.ApplyFn = testApplyFn 6322 p.DiffFn = testDiffFn 6323 6324 state := &State{ 6325 Modules: []*ModuleState{ 6326 &ModuleState{ 6327 Path: rootModulePath, 6328 Resources: map[string]*ResourceState{ 6329 "aws_instance.bar": &ResourceState{ 6330 Type: "aws_instance", 6331 Primary: &InstanceState{ 6332 ID: "bar", 6333 }, 6334 }, 6335 }, 6336 }, 6337 }, 6338 } 6339 6340 ctx := testContext2(t, &ContextOpts{ 6341 Module: m, 6342 State: state, 6343 Hooks: []Hook{h}, 6344 Providers: map[string]ResourceProviderFactory{ 6345 "aws": testProviderFuncFixed(p), 6346 }, 6347 }) 6348 6349 if _, err := ctx.Plan(); err != nil { 6350 t.Fatalf("err: %s", err) 6351 } 6352 6353 if _, err := ctx.Apply(); err != nil { 6354 t.Fatalf("err: %s", err) 6355 } 6356 6357 if !h.PreApplyCalled { 6358 t.Fatal("should be called") 6359 } 6360 if !h.PostApplyCalled { 6361 t.Fatal("should be called") 6362 } 6363 if !h.PostStateUpdateCalled { 6364 t.Fatalf("should call post state update") 6365 } 6366 } 6367 6368 func TestContext2Apply_idAttr(t *testing.T) { 6369 m := testModule(t, "apply-idattr") 6370 p := testProvider("aws") 6371 ctx := testContext2(t, &ContextOpts{ 6372 Module: m, 6373 Providers: map[string]ResourceProviderFactory{ 6374 "aws": testProviderFuncFixed(p), 6375 }, 6376 }) 6377 6378 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6379 result := s.MergeDiff(d) 6380 result.ID = "foo" 6381 result.Attributes = map[string]string{ 6382 "id": "bar", 6383 } 6384 6385 return result, nil 6386 } 6387 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 6388 return &InstanceDiff{ 6389 Attributes: map[string]*ResourceAttrDiff{ 6390 "num": &ResourceAttrDiff{ 6391 New: "bar", 6392 }, 6393 }, 6394 }, nil 6395 } 6396 6397 if _, err := ctx.Plan(); err != nil { 6398 t.Fatalf("err: %s", err) 6399 } 6400 6401 state, err := ctx.Apply() 6402 if err != nil { 6403 t.Fatalf("err: %s", err) 6404 } 6405 6406 mod := state.RootModule() 6407 rs, ok := mod.Resources["aws_instance.foo"] 6408 if !ok { 6409 t.Fatal("not in state") 6410 } 6411 if rs.Primary.ID != "foo" { 6412 t.Fatalf("bad: %#v", rs.Primary.ID) 6413 } 6414 if rs.Primary.Attributes["id"] != "foo" { 6415 t.Fatalf("bad: %#v", rs.Primary.Attributes) 6416 } 6417 } 6418 6419 func TestContext2Apply_outputBasic(t *testing.T) { 6420 m := testModule(t, "apply-output") 6421 p := testProvider("aws") 6422 p.ApplyFn = testApplyFn 6423 p.DiffFn = testDiffFn 6424 ctx := testContext2(t, &ContextOpts{ 6425 Module: m, 6426 Providers: map[string]ResourceProviderFactory{ 6427 "aws": testProviderFuncFixed(p), 6428 }, 6429 }) 6430 6431 if _, err := ctx.Plan(); err != nil { 6432 t.Fatalf("err: %s", err) 6433 } 6434 6435 state, err := ctx.Apply() 6436 if err != nil { 6437 t.Fatalf("err: %s", err) 6438 } 6439 6440 actual := strings.TrimSpace(state.String()) 6441 expected := strings.TrimSpace(testTerraformApplyOutputStr) 6442 if actual != expected { 6443 t.Fatalf("bad: \n%s", actual) 6444 } 6445 } 6446 6447 func TestContext2Apply_outputInvalid(t *testing.T) { 6448 m := testModule(t, "apply-output-invalid") 6449 p := testProvider("aws") 6450 p.ApplyFn = testApplyFn 6451 p.DiffFn = testDiffFn 6452 ctx := testContext2(t, &ContextOpts{ 6453 Module: m, 6454 Providers: map[string]ResourceProviderFactory{ 6455 "aws": testProviderFuncFixed(p), 6456 }, 6457 }) 6458 6459 _, err := ctx.Plan() 6460 if err == nil { 6461 t.Fatalf("err: %s", err) 6462 } 6463 if !strings.Contains(err.Error(), "is not a valid type") { 6464 t.Fatalf("err: %s", err) 6465 } 6466 } 6467 6468 func TestContext2Apply_outputAdd(t *testing.T) { 6469 m1 := testModule(t, "apply-output-add-before") 6470 p1 := testProvider("aws") 6471 p1.ApplyFn = testApplyFn 6472 p1.DiffFn = testDiffFn 6473 ctx1 := testContext2(t, &ContextOpts{ 6474 Module: m1, 6475 Providers: map[string]ResourceProviderFactory{ 6476 "aws": testProviderFuncFixed(p1), 6477 }, 6478 }) 6479 6480 if _, err := ctx1.Plan(); err != nil { 6481 t.Fatalf("err: %s", err) 6482 } 6483 6484 state1, err := ctx1.Apply() 6485 if err != nil { 6486 t.Fatalf("err: %s", err) 6487 } 6488 6489 m2 := testModule(t, "apply-output-add-after") 6490 p2 := testProvider("aws") 6491 p2.ApplyFn = testApplyFn 6492 p2.DiffFn = testDiffFn 6493 ctx2 := testContext2(t, &ContextOpts{ 6494 Module: m2, 6495 Providers: map[string]ResourceProviderFactory{ 6496 "aws": testProviderFuncFixed(p2), 6497 }, 6498 State: state1, 6499 }) 6500 6501 if _, err := ctx2.Plan(); err != nil { 6502 t.Fatalf("err: %s", err) 6503 } 6504 6505 state2, err := ctx2.Apply() 6506 if err != nil { 6507 t.Fatalf("err: %s", err) 6508 } 6509 6510 actual := strings.TrimSpace(state2.String()) 6511 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 6512 if actual != expected { 6513 t.Fatalf("bad: \n%s", actual) 6514 } 6515 } 6516 6517 func TestContext2Apply_outputList(t *testing.T) { 6518 m := testModule(t, "apply-output-list") 6519 p := testProvider("aws") 6520 p.ApplyFn = testApplyFn 6521 p.DiffFn = testDiffFn 6522 ctx := testContext2(t, &ContextOpts{ 6523 Module: m, 6524 Providers: map[string]ResourceProviderFactory{ 6525 "aws": testProviderFuncFixed(p), 6526 }, 6527 }) 6528 6529 if _, err := ctx.Plan(); err != nil { 6530 t.Fatalf("err: %s", err) 6531 } 6532 6533 state, err := ctx.Apply() 6534 if err != nil { 6535 t.Fatalf("err: %s", err) 6536 } 6537 6538 actual := strings.TrimSpace(state.String()) 6539 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 6540 if actual != expected { 6541 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 6542 } 6543 } 6544 6545 func TestContext2Apply_outputMulti(t *testing.T) { 6546 m := testModule(t, "apply-output-multi") 6547 p := testProvider("aws") 6548 p.ApplyFn = testApplyFn 6549 p.DiffFn = testDiffFn 6550 ctx := testContext2(t, &ContextOpts{ 6551 Module: m, 6552 Providers: map[string]ResourceProviderFactory{ 6553 "aws": testProviderFuncFixed(p), 6554 }, 6555 }) 6556 6557 if _, err := ctx.Plan(); err != nil { 6558 t.Fatalf("err: %s", err) 6559 } 6560 6561 state, err := ctx.Apply() 6562 if err != nil { 6563 t.Fatalf("err: %s", err) 6564 } 6565 6566 actual := strings.TrimSpace(state.String()) 6567 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 6568 if actual != expected { 6569 t.Fatalf("bad: \n%s", actual) 6570 } 6571 } 6572 6573 func TestContext2Apply_outputMultiIndex(t *testing.T) { 6574 m := testModule(t, "apply-output-multi-index") 6575 p := testProvider("aws") 6576 p.ApplyFn = testApplyFn 6577 p.DiffFn = testDiffFn 6578 ctx := testContext2(t, &ContextOpts{ 6579 Module: m, 6580 Providers: map[string]ResourceProviderFactory{ 6581 "aws": testProviderFuncFixed(p), 6582 }, 6583 }) 6584 6585 if _, err := ctx.Plan(); err != nil { 6586 t.Fatalf("err: %s", err) 6587 } 6588 6589 state, err := ctx.Apply() 6590 if err != nil { 6591 t.Fatalf("err: %s", err) 6592 } 6593 6594 actual := strings.TrimSpace(state.String()) 6595 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 6596 if actual != expected { 6597 t.Fatalf("bad: \n%s", actual) 6598 } 6599 } 6600 6601 func TestContext2Apply_taintX(t *testing.T) { 6602 m := testModule(t, "apply-taint") 6603 p := testProvider("aws") 6604 6605 // destroyCount tests against regression of 6606 // https://github.com/hashicorp/terraform/issues/1056 6607 var destroyCount = int32(0) 6608 var once sync.Once 6609 simulateProviderDelay := func() { 6610 time.Sleep(10 * time.Millisecond) 6611 } 6612 6613 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 6614 once.Do(simulateProviderDelay) 6615 if d.Destroy { 6616 atomic.AddInt32(&destroyCount, 1) 6617 } 6618 return testApplyFn(info, s, d) 6619 } 6620 p.DiffFn = testDiffFn 6621 s := &State{ 6622 Modules: []*ModuleState{ 6623 &ModuleState{ 6624 Path: rootModulePath, 6625 Resources: map[string]*ResourceState{ 6626 "aws_instance.bar": &ResourceState{ 6627 Type: "aws_instance", 6628 Primary: &InstanceState{ 6629 ID: "baz", 6630 Attributes: map[string]string{ 6631 "num": "2", 6632 "type": "aws_instance", 6633 }, 6634 Tainted: true, 6635 }, 6636 }, 6637 }, 6638 }, 6639 }, 6640 } 6641 ctx := testContext2(t, &ContextOpts{ 6642 Module: m, 6643 Providers: map[string]ResourceProviderFactory{ 6644 "aws": testProviderFuncFixed(p), 6645 }, 6646 State: s, 6647 }) 6648 6649 if p, err := ctx.Plan(); err != nil { 6650 t.Fatalf("err: %s", err) 6651 } else { 6652 t.Logf("plan: %s", p) 6653 } 6654 6655 state, err := ctx.Apply() 6656 if err != nil { 6657 t.Fatalf("err: %s", err) 6658 } 6659 6660 actual := strings.TrimSpace(state.String()) 6661 expected := strings.TrimSpace(testTerraformApplyTaintStr) 6662 if actual != expected { 6663 t.Fatalf("bad:\n%s", actual) 6664 } 6665 6666 if destroyCount != 1 { 6667 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 6668 } 6669 } 6670 6671 func TestContext2Apply_taintDep(t *testing.T) { 6672 m := testModule(t, "apply-taint-dep") 6673 p := testProvider("aws") 6674 p.ApplyFn = testApplyFn 6675 p.DiffFn = testDiffFn 6676 s := &State{ 6677 Modules: []*ModuleState{ 6678 &ModuleState{ 6679 Path: rootModulePath, 6680 Resources: map[string]*ResourceState{ 6681 "aws_instance.foo": &ResourceState{ 6682 Type: "aws_instance", 6683 Primary: &InstanceState{ 6684 ID: "baz", 6685 Attributes: map[string]string{ 6686 "num": "2", 6687 "type": "aws_instance", 6688 }, 6689 Tainted: true, 6690 }, 6691 }, 6692 "aws_instance.bar": &ResourceState{ 6693 Type: "aws_instance", 6694 Primary: &InstanceState{ 6695 ID: "bar", 6696 Attributes: map[string]string{ 6697 "foo": "baz", 6698 "num": "2", 6699 "type": "aws_instance", 6700 }, 6701 }, 6702 }, 6703 }, 6704 }, 6705 }, 6706 } 6707 ctx := testContext2(t, &ContextOpts{ 6708 Module: m, 6709 Providers: map[string]ResourceProviderFactory{ 6710 "aws": testProviderFuncFixed(p), 6711 }, 6712 State: s, 6713 }) 6714 6715 if p, err := ctx.Plan(); err != nil { 6716 t.Fatalf("err: %s", err) 6717 } else { 6718 t.Logf("plan: %s", p) 6719 } 6720 6721 state, err := ctx.Apply() 6722 if err != nil { 6723 t.Fatalf("err: %s", err) 6724 } 6725 6726 actual := strings.TrimSpace(state.String()) 6727 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 6728 if actual != expected { 6729 t.Fatalf("bad:\n%s", actual) 6730 } 6731 } 6732 6733 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 6734 m := testModule(t, "apply-taint-dep-requires-new") 6735 p := testProvider("aws") 6736 p.ApplyFn = testApplyFn 6737 p.DiffFn = testDiffFn 6738 s := &State{ 6739 Modules: []*ModuleState{ 6740 &ModuleState{ 6741 Path: rootModulePath, 6742 Resources: map[string]*ResourceState{ 6743 "aws_instance.foo": &ResourceState{ 6744 Type: "aws_instance", 6745 Primary: &InstanceState{ 6746 ID: "baz", 6747 Attributes: map[string]string{ 6748 "num": "2", 6749 "type": "aws_instance", 6750 }, 6751 Tainted: true, 6752 }, 6753 }, 6754 "aws_instance.bar": &ResourceState{ 6755 Type: "aws_instance", 6756 Primary: &InstanceState{ 6757 ID: "bar", 6758 Attributes: map[string]string{ 6759 "foo": "baz", 6760 "num": "2", 6761 "type": "aws_instance", 6762 }, 6763 }, 6764 }, 6765 }, 6766 }, 6767 }, 6768 } 6769 ctx := testContext2(t, &ContextOpts{ 6770 Module: m, 6771 Providers: map[string]ResourceProviderFactory{ 6772 "aws": testProviderFuncFixed(p), 6773 }, 6774 State: s, 6775 }) 6776 6777 if p, err := ctx.Plan(); err != nil { 6778 t.Fatalf("err: %s", err) 6779 } else { 6780 t.Logf("plan: %s", p) 6781 } 6782 6783 state, err := ctx.Apply() 6784 if err != nil { 6785 t.Fatalf("err: %s", err) 6786 } 6787 6788 actual := strings.TrimSpace(state.String()) 6789 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 6790 if actual != expected { 6791 t.Fatalf("bad:\n%s", actual) 6792 } 6793 } 6794 6795 func TestContext2Apply_targeted(t *testing.T) { 6796 m := testModule(t, "apply-targeted") 6797 p := testProvider("aws") 6798 p.ApplyFn = testApplyFn 6799 p.DiffFn = testDiffFn 6800 ctx := testContext2(t, &ContextOpts{ 6801 Module: m, 6802 Providers: map[string]ResourceProviderFactory{ 6803 "aws": testProviderFuncFixed(p), 6804 }, 6805 Targets: []string{"aws_instance.foo"}, 6806 }) 6807 6808 if _, err := ctx.Plan(); err != nil { 6809 t.Fatalf("err: %s", err) 6810 } 6811 6812 state, err := ctx.Apply() 6813 if err != nil { 6814 t.Fatalf("err: %s", err) 6815 } 6816 6817 mod := state.RootModule() 6818 if len(mod.Resources) != 1 { 6819 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 6820 } 6821 6822 checkStateString(t, state, ` 6823 aws_instance.foo: 6824 ID = foo 6825 num = 2 6826 type = aws_instance 6827 `) 6828 } 6829 6830 func TestContext2Apply_targetedCount(t *testing.T) { 6831 m := testModule(t, "apply-targeted-count") 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 Targets: []string{"aws_instance.foo"}, 6841 }) 6842 6843 if _, err := ctx.Plan(); err != nil { 6844 t.Fatalf("err: %s", err) 6845 } 6846 6847 state, err := ctx.Apply() 6848 if err != nil { 6849 t.Fatalf("err: %s", err) 6850 } 6851 6852 checkStateString(t, state, ` 6853 aws_instance.foo.0: 6854 ID = foo 6855 aws_instance.foo.1: 6856 ID = foo 6857 aws_instance.foo.2: 6858 ID = foo 6859 `) 6860 } 6861 6862 func TestContext2Apply_targetedCountIndex(t *testing.T) { 6863 m := testModule(t, "apply-targeted-count") 6864 p := testProvider("aws") 6865 p.ApplyFn = testApplyFn 6866 p.DiffFn = testDiffFn 6867 ctx := testContext2(t, &ContextOpts{ 6868 Module: m, 6869 Providers: map[string]ResourceProviderFactory{ 6870 "aws": testProviderFuncFixed(p), 6871 }, 6872 Targets: []string{"aws_instance.foo[1]"}, 6873 }) 6874 6875 if _, err := ctx.Plan(); err != nil { 6876 t.Fatalf("err: %s", err) 6877 } 6878 6879 state, err := ctx.Apply() 6880 if err != nil { 6881 t.Fatalf("err: %s", err) 6882 } 6883 6884 checkStateString(t, state, ` 6885 aws_instance.foo.1: 6886 ID = foo 6887 `) 6888 } 6889 6890 func TestContext2Apply_targetedDestroy(t *testing.T) { 6891 m := testModule(t, "apply-targeted") 6892 p := testProvider("aws") 6893 p.ApplyFn = testApplyFn 6894 p.DiffFn = testDiffFn 6895 ctx := testContext2(t, &ContextOpts{ 6896 Module: m, 6897 Providers: map[string]ResourceProviderFactory{ 6898 "aws": testProviderFuncFixed(p), 6899 }, 6900 State: &State{ 6901 Modules: []*ModuleState{ 6902 &ModuleState{ 6903 Path: rootModulePath, 6904 Resources: map[string]*ResourceState{ 6905 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6906 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6907 }, 6908 }, 6909 }, 6910 }, 6911 Targets: []string{"aws_instance.foo"}, 6912 Destroy: true, 6913 }) 6914 6915 if _, err := ctx.Plan(); err != nil { 6916 t.Fatalf("err: %s", err) 6917 } 6918 6919 state, err := ctx.Apply() 6920 if err != nil { 6921 t.Fatalf("err: %s", err) 6922 } 6923 6924 mod := state.RootModule() 6925 if len(mod.Resources) != 1 { 6926 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 6927 } 6928 6929 checkStateString(t, state, ` 6930 aws_instance.bar: 6931 ID = i-abc123 6932 `) 6933 } 6934 6935 func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) { 6936 m := testModule(t, "apply-destroy-targeted-count") 6937 p := testProvider("aws") 6938 p.ApplyFn = testApplyFn 6939 p.DiffFn = testDiffFn 6940 ctx := testContext2(t, &ContextOpts{ 6941 Module: m, 6942 Providers: map[string]ResourceProviderFactory{ 6943 "aws": testProviderFuncFixed(p), 6944 }, 6945 State: &State{ 6946 Modules: []*ModuleState{ 6947 &ModuleState{ 6948 Path: rootModulePath, 6949 Resources: map[string]*ResourceState{ 6950 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6951 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6952 }, 6953 }, 6954 }, 6955 }, 6956 Targets: []string{"aws_instance.foo"}, 6957 Destroy: true, 6958 }) 6959 6960 if _, err := ctx.Plan(); err != nil { 6961 t.Fatalf("err: %s", err) 6962 } 6963 6964 state, err := ctx.Apply() 6965 if err != nil { 6966 t.Fatalf("err: %s", err) 6967 } 6968 6969 checkStateString(t, state, `<no state>`) 6970 } 6971 6972 // https://github.com/hashicorp/terraform/issues/4462 6973 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 6974 m := testModule(t, "apply-targeted-module") 6975 p := testProvider("aws") 6976 p.ApplyFn = testApplyFn 6977 p.DiffFn = testDiffFn 6978 ctx := testContext2(t, &ContextOpts{ 6979 Module: m, 6980 Providers: map[string]ResourceProviderFactory{ 6981 "aws": testProviderFuncFixed(p), 6982 }, 6983 State: &State{ 6984 Modules: []*ModuleState{ 6985 &ModuleState{ 6986 Path: rootModulePath, 6987 Resources: map[string]*ResourceState{ 6988 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6989 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6990 }, 6991 }, 6992 &ModuleState{ 6993 Path: []string{"root", "child"}, 6994 Resources: map[string]*ResourceState{ 6995 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 6996 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 6997 }, 6998 }, 6999 }, 7000 }, 7001 Targets: []string{"module.child.aws_instance.foo"}, 7002 Destroy: true, 7003 }) 7004 7005 if _, err := ctx.Plan(); err != nil { 7006 t.Fatalf("err: %s", err) 7007 } 7008 7009 state, err := ctx.Apply() 7010 if err != nil { 7011 t.Fatalf("err: %s", err) 7012 } 7013 7014 checkStateString(t, state, ` 7015 aws_instance.bar: 7016 ID = i-abc123 7017 aws_instance.foo: 7018 ID = i-bcd345 7019 7020 module.child: 7021 aws_instance.bar: 7022 ID = i-abc123 7023 `) 7024 } 7025 7026 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 7027 m := testModule(t, "apply-targeted-count") 7028 p := testProvider("aws") 7029 p.ApplyFn = testApplyFn 7030 p.DiffFn = testDiffFn 7031 ctx := testContext2(t, &ContextOpts{ 7032 Module: m, 7033 Providers: map[string]ResourceProviderFactory{ 7034 "aws": testProviderFuncFixed(p), 7035 }, 7036 State: &State{ 7037 Modules: []*ModuleState{ 7038 &ModuleState{ 7039 Path: rootModulePath, 7040 Resources: map[string]*ResourceState{ 7041 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 7042 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 7043 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 7044 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 7045 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 7046 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 7047 }, 7048 }, 7049 }, 7050 }, 7051 Targets: []string{ 7052 "aws_instance.foo[2]", 7053 "aws_instance.bar[1]", 7054 }, 7055 Destroy: true, 7056 }) 7057 7058 if _, err := ctx.Plan(); err != nil { 7059 t.Fatalf("err: %s", err) 7060 } 7061 7062 state, err := ctx.Apply() 7063 if err != nil { 7064 t.Fatalf("err: %s", err) 7065 } 7066 7067 checkStateString(t, state, ` 7068 aws_instance.bar.0: 7069 ID = i-abc123 7070 aws_instance.bar.2: 7071 ID = i-abc123 7072 aws_instance.foo.0: 7073 ID = i-bcd345 7074 aws_instance.foo.1: 7075 ID = i-bcd345 7076 `) 7077 } 7078 7079 func TestContext2Apply_targetedModule(t *testing.T) { 7080 m := testModule(t, "apply-targeted-module") 7081 p := testProvider("aws") 7082 p.ApplyFn = testApplyFn 7083 p.DiffFn = testDiffFn 7084 ctx := testContext2(t, &ContextOpts{ 7085 Module: m, 7086 Providers: map[string]ResourceProviderFactory{ 7087 "aws": testProviderFuncFixed(p), 7088 }, 7089 Targets: []string{"module.child"}, 7090 }) 7091 7092 if _, err := ctx.Plan(); err != nil { 7093 t.Fatalf("err: %s", err) 7094 } 7095 7096 state, err := ctx.Apply() 7097 if err != nil { 7098 t.Fatalf("err: %s", err) 7099 } 7100 7101 mod := state.ModuleByPath([]string{"root", "child"}) 7102 if mod == nil { 7103 t.Fatalf("no child module found in the state!\n\n%#v", state) 7104 } 7105 if len(mod.Resources) != 2 { 7106 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 7107 } 7108 7109 checkStateString(t, state, ` 7110 <no state> 7111 module.child: 7112 aws_instance.bar: 7113 ID = foo 7114 num = 2 7115 type = aws_instance 7116 aws_instance.foo: 7117 ID = foo 7118 num = 2 7119 type = aws_instance 7120 `) 7121 } 7122 7123 // GH-1858 7124 func TestContext2Apply_targetedModuleDep(t *testing.T) { 7125 m := testModule(t, "apply-targeted-module-dep") 7126 p := testProvider("aws") 7127 p.ApplyFn = testApplyFn 7128 p.DiffFn = testDiffFn 7129 ctx := testContext2(t, &ContextOpts{ 7130 Module: m, 7131 Providers: map[string]ResourceProviderFactory{ 7132 "aws": testProviderFuncFixed(p), 7133 }, 7134 Targets: []string{"aws_instance.foo"}, 7135 }) 7136 7137 if p, err := ctx.Plan(); err != nil { 7138 t.Fatalf("err: %s", err) 7139 } else { 7140 t.Logf("Diff: %s", p) 7141 } 7142 7143 state, err := ctx.Apply() 7144 if err != nil { 7145 t.Fatalf("err: %s", err) 7146 } 7147 7148 checkStateString(t, state, ` 7149 aws_instance.foo: 7150 ID = foo 7151 foo = foo 7152 type = aws_instance 7153 7154 Dependencies: 7155 module.child 7156 7157 module.child: 7158 aws_instance.mod: 7159 ID = foo 7160 7161 Outputs: 7162 7163 output = foo 7164 `) 7165 } 7166 7167 // GH-10911 untargeted outputs should not be in the graph, and therefore 7168 // not execute. 7169 func TestContext2Apply_targetedModuleUnrelatedOutputs(t *testing.T) { 7170 m := testModule(t, "apply-targeted-module-unrelated-outputs") 7171 p := testProvider("aws") 7172 p.ApplyFn = testApplyFn 7173 p.DiffFn = testDiffFn 7174 ctx := testContext2(t, &ContextOpts{ 7175 Module: m, 7176 Providers: map[string]ResourceProviderFactory{ 7177 "aws": testProviderFuncFixed(p), 7178 }, 7179 Targets: []string{"module.child2"}, 7180 }) 7181 7182 if _, err := ctx.Plan(); err != nil { 7183 t.Fatalf("err: %s", err) 7184 } 7185 7186 state, err := ctx.Apply() 7187 if err != nil { 7188 t.Fatalf("err: %s", err) 7189 } 7190 7191 checkStateString(t, state, ` 7192 <no state> 7193 module.child2: 7194 aws_instance.foo: 7195 ID = foo 7196 `) 7197 } 7198 7199 func TestContext2Apply_targetedModuleResource(t *testing.T) { 7200 m := testModule(t, "apply-targeted-module-resource") 7201 p := testProvider("aws") 7202 p.ApplyFn = testApplyFn 7203 p.DiffFn = testDiffFn 7204 ctx := testContext2(t, &ContextOpts{ 7205 Module: m, 7206 Providers: map[string]ResourceProviderFactory{ 7207 "aws": testProviderFuncFixed(p), 7208 }, 7209 Targets: []string{"module.child.aws_instance.foo"}, 7210 }) 7211 7212 if _, err := ctx.Plan(); err != nil { 7213 t.Fatalf("err: %s", err) 7214 } 7215 7216 state, err := ctx.Apply() 7217 if err != nil { 7218 t.Fatalf("err: %s", err) 7219 } 7220 7221 mod := state.ModuleByPath([]string{"root", "child"}) 7222 if mod == nil || len(mod.Resources) != 1 { 7223 t.Fatalf("expected 1 resource, got: %#v", mod) 7224 } 7225 7226 checkStateString(t, state, ` 7227 <no state> 7228 module.child: 7229 aws_instance.foo: 7230 ID = foo 7231 num = 2 7232 type = aws_instance 7233 `) 7234 } 7235 7236 func TestContext2Apply_unknownAttribute(t *testing.T) { 7237 m := testModule(t, "apply-unknown") 7238 p := testProvider("aws") 7239 p.ApplyFn = testApplyFn 7240 p.DiffFn = testDiffFn 7241 ctx := testContext2(t, &ContextOpts{ 7242 Module: m, 7243 Providers: map[string]ResourceProviderFactory{ 7244 "aws": testProviderFuncFixed(p), 7245 }, 7246 }) 7247 7248 if _, err := ctx.Plan(); err != nil { 7249 t.Fatalf("err: %s", err) 7250 } 7251 7252 state, err := ctx.Apply() 7253 if err == nil { 7254 t.Fatal("should error") 7255 } 7256 7257 actual := strings.TrimSpace(state.String()) 7258 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 7259 if actual != expected { 7260 t.Fatalf("bad: \n%s", actual) 7261 } 7262 } 7263 7264 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 7265 m := testModule(t, "apply-unknown-interpolate") 7266 p := testProvider("aws") 7267 p.ApplyFn = testApplyFn 7268 p.DiffFn = testDiffFn 7269 ctx := testContext2(t, &ContextOpts{ 7270 Module: m, 7271 Providers: map[string]ResourceProviderFactory{ 7272 "aws": testProviderFuncFixed(p), 7273 }, 7274 }) 7275 7276 if _, err := ctx.Plan(); err == nil { 7277 t.Fatal("should error") 7278 } 7279 } 7280 7281 func TestContext2Apply_vars(t *testing.T) { 7282 m := testModule(t, "apply-vars") 7283 p := testProvider("aws") 7284 p.ApplyFn = testApplyFn 7285 p.DiffFn = testDiffFn 7286 ctx := testContext2(t, &ContextOpts{ 7287 Module: m, 7288 Providers: map[string]ResourceProviderFactory{ 7289 "aws": testProviderFuncFixed(p), 7290 }, 7291 Variables: map[string]interface{}{ 7292 "foo": "us-west-2", 7293 "test_list": []interface{}{"Hello", "World"}, 7294 "test_map": map[string]interface{}{ 7295 "Hello": "World", 7296 "Foo": "Bar", 7297 "Baz": "Foo", 7298 }, 7299 "amis": []map[string]interface{}{ 7300 map[string]interface{}{ 7301 "us-east-1": "override", 7302 }, 7303 }, 7304 }, 7305 }) 7306 7307 w, e := ctx.Validate() 7308 if len(w) > 0 { 7309 t.Fatalf("bad: %#v", w) 7310 } 7311 if len(e) > 0 { 7312 t.Fatalf("bad: %s", e) 7313 } 7314 7315 if _, err := ctx.Plan(); err != nil { 7316 t.Fatalf("err: %s", err) 7317 } 7318 7319 state, err := ctx.Apply() 7320 if err != nil { 7321 t.Fatalf("err: %s", err) 7322 } 7323 7324 actual := strings.TrimSpace(state.String()) 7325 expected := strings.TrimSpace(testTerraformApplyVarsStr) 7326 if actual != expected { 7327 t.Fatalf("expected: %s\n got:\n%s", expected, actual) 7328 } 7329 } 7330 7331 func TestContext2Apply_varsEnv(t *testing.T) { 7332 // Set the env var 7333 defer tempEnv(t, "TF_VAR_ami", "baz")() 7334 defer tempEnv(t, "TF_VAR_list", `["Hello", "World"]`)() 7335 defer tempEnv(t, "TF_VAR_map", `{"Hello" = "World", "Foo" = "Bar", "Baz" = "Foo"}`)() 7336 7337 m := testModule(t, "apply-vars-env") 7338 p := testProvider("aws") 7339 p.ApplyFn = testApplyFn 7340 p.DiffFn = testDiffFn 7341 ctx := testContext2(t, &ContextOpts{ 7342 Module: m, 7343 Providers: map[string]ResourceProviderFactory{ 7344 "aws": testProviderFuncFixed(p), 7345 }, 7346 }) 7347 7348 w, e := ctx.Validate() 7349 if len(w) > 0 { 7350 t.Fatalf("bad: %#v", w) 7351 } 7352 if len(e) > 0 { 7353 t.Fatalf("bad: %s", e) 7354 } 7355 7356 if _, err := ctx.Plan(); err != nil { 7357 t.Fatalf("err: %s", err) 7358 } 7359 7360 state, err := ctx.Apply() 7361 if err != nil { 7362 t.Fatalf("err: %s", err) 7363 } 7364 7365 actual := strings.TrimSpace(state.String()) 7366 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 7367 if actual != expected { 7368 t.Fatalf("bad: \n%s", actual) 7369 } 7370 } 7371 7372 func TestContext2Apply_createBefore_depends(t *testing.T) { 7373 m := testModule(t, "apply-depends-create-before") 7374 h := new(HookRecordApplyOrder) 7375 p := testProvider("aws") 7376 p.ApplyFn = testApplyFn 7377 p.DiffFn = testDiffFn 7378 state := &State{ 7379 Modules: []*ModuleState{ 7380 &ModuleState{ 7381 Path: rootModulePath, 7382 Resources: map[string]*ResourceState{ 7383 "aws_instance.web": &ResourceState{ 7384 Type: "aws_instance", 7385 Primary: &InstanceState{ 7386 ID: "bar", 7387 Attributes: map[string]string{ 7388 "require_new": "ami-old", 7389 }, 7390 }, 7391 }, 7392 "aws_instance.lb": &ResourceState{ 7393 Type: "aws_instance", 7394 Primary: &InstanceState{ 7395 ID: "baz", 7396 Attributes: map[string]string{ 7397 "instance": "bar", 7398 }, 7399 }, 7400 }, 7401 }, 7402 }, 7403 }, 7404 } 7405 ctx := testContext2(t, &ContextOpts{ 7406 Module: m, 7407 Hooks: []Hook{h}, 7408 Providers: map[string]ResourceProviderFactory{ 7409 "aws": testProviderFuncFixed(p), 7410 }, 7411 State: state, 7412 }) 7413 7414 if p, err := ctx.Plan(); err != nil { 7415 t.Fatalf("err: %s", err) 7416 } else { 7417 t.Logf("plan: %s", p) 7418 } 7419 7420 h.Active = true 7421 state, err := ctx.Apply() 7422 if err != nil { 7423 t.Fatalf("err: %s", err) 7424 } 7425 7426 mod := state.RootModule() 7427 if len(mod.Resources) < 2 { 7428 t.Fatalf("bad: %#v", mod.Resources) 7429 } 7430 7431 actual := strings.TrimSpace(state.String()) 7432 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 7433 if actual != expected { 7434 t.Fatalf("bad: \n%s\n\n%s", actual, expected) 7435 } 7436 7437 // Test that things were managed _in the right order_ 7438 order := h.States 7439 diffs := h.Diffs 7440 if order[0].ID != "" || diffs[0].Destroy { 7441 t.Fatalf("should create new instance first: %#v", order) 7442 } 7443 7444 if order[1].ID != "baz" { 7445 t.Fatalf("update must happen after create: %#v", order) 7446 } 7447 7448 if order[2].ID != "bar" || !diffs[2].Destroy { 7449 t.Fatalf("destroy must happen after update: %#v", order) 7450 } 7451 } 7452 7453 func TestContext2Apply_singleDestroy(t *testing.T) { 7454 m := testModule(t, "apply-depends-create-before") 7455 h := new(HookRecordApplyOrder) 7456 p := testProvider("aws") 7457 7458 invokeCount := 0 7459 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 7460 invokeCount++ 7461 switch invokeCount { 7462 case 1: 7463 if d.Destroy { 7464 t.Fatalf("should not destroy") 7465 } 7466 if s.ID != "" { 7467 t.Fatalf("should not have ID") 7468 } 7469 case 2: 7470 if d.Destroy { 7471 t.Fatalf("should not destroy") 7472 } 7473 if s.ID != "baz" { 7474 t.Fatalf("should have id") 7475 } 7476 case 3: 7477 if !d.Destroy { 7478 t.Fatalf("should destroy") 7479 } 7480 if s.ID == "" { 7481 t.Fatalf("should have ID") 7482 } 7483 default: 7484 t.Fatalf("bad invoke count %d", invokeCount) 7485 } 7486 return testApplyFn(info, s, d) 7487 } 7488 p.DiffFn = testDiffFn 7489 state := &State{ 7490 Modules: []*ModuleState{ 7491 &ModuleState{ 7492 Path: rootModulePath, 7493 Resources: map[string]*ResourceState{ 7494 "aws_instance.web": &ResourceState{ 7495 Type: "aws_instance", 7496 Primary: &InstanceState{ 7497 ID: "bar", 7498 Attributes: map[string]string{ 7499 "require_new": "ami-old", 7500 }, 7501 }, 7502 }, 7503 "aws_instance.lb": &ResourceState{ 7504 Type: "aws_instance", 7505 Primary: &InstanceState{ 7506 ID: "baz", 7507 Attributes: map[string]string{ 7508 "instance": "bar", 7509 }, 7510 }, 7511 }, 7512 }, 7513 }, 7514 }, 7515 } 7516 ctx := testContext2(t, &ContextOpts{ 7517 Module: m, 7518 Hooks: []Hook{h}, 7519 Providers: map[string]ResourceProviderFactory{ 7520 "aws": testProviderFuncFixed(p), 7521 }, 7522 State: state, 7523 }) 7524 7525 if _, err := ctx.Plan(); err != nil { 7526 t.Fatalf("err: %s", err) 7527 } 7528 7529 h.Active = true 7530 state, err := ctx.Apply() 7531 if err != nil { 7532 t.Fatalf("err: %s", err) 7533 } 7534 7535 if invokeCount != 3 { 7536 t.Fatalf("bad: %d", invokeCount) 7537 } 7538 } 7539 7540 // GH-7824 7541 func TestContext2Apply_issue7824(t *testing.T) { 7542 p := testProvider("template") 7543 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 7544 Name: "template_file", 7545 }) 7546 7547 p.ApplyFn = testApplyFn 7548 p.DiffFn = testDiffFn 7549 7550 // Apply cleanly step 0 7551 ctx := testContext2(t, &ContextOpts{ 7552 Module: testModule(t, "issue-7824"), 7553 Providers: map[string]ResourceProviderFactory{ 7554 "template": testProviderFuncFixed(p), 7555 }, 7556 }) 7557 7558 plan, err := ctx.Plan() 7559 if err != nil { 7560 t.Fatalf("err: %s", err) 7561 } 7562 7563 // Write / Read plan to simulate running it through a Plan file 7564 var buf bytes.Buffer 7565 if err := WritePlan(plan, &buf); err != nil { 7566 t.Fatalf("err: %s", err) 7567 } 7568 7569 planFromFile, err := ReadPlan(&buf) 7570 if err != nil { 7571 t.Fatalf("err: %s", err) 7572 } 7573 7574 ctx, err = planFromFile.Context(&ContextOpts{ 7575 Providers: map[string]ResourceProviderFactory{ 7576 "template": testProviderFuncFixed(p), 7577 }, 7578 }) 7579 if err != nil { 7580 t.Fatalf("err: %s", err) 7581 } 7582 7583 _, err = ctx.Apply() 7584 if err != nil { 7585 t.Fatalf("err: %s", err) 7586 } 7587 } 7588 7589 // GH-5254 7590 func TestContext2Apply_issue5254(t *testing.T) { 7591 // Create a provider. We use "template" here just to match the repro 7592 // we got from the issue itself. 7593 p := testProvider("template") 7594 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 7595 Name: "template_file", 7596 }) 7597 7598 p.ApplyFn = testApplyFn 7599 p.DiffFn = testDiffFn 7600 7601 // Apply cleanly step 0 7602 ctx := testContext2(t, &ContextOpts{ 7603 Module: testModule(t, "issue-5254/step-0"), 7604 Providers: map[string]ResourceProviderFactory{ 7605 "template": testProviderFuncFixed(p), 7606 }, 7607 }) 7608 7609 plan, err := ctx.Plan() 7610 if err != nil { 7611 t.Fatalf("err: %s", err) 7612 } 7613 7614 state, err := ctx.Apply() 7615 if err != nil { 7616 t.Fatalf("err: %s", err) 7617 } 7618 7619 // Application success. Now make the modification and store a plan 7620 ctx = testContext2(t, &ContextOpts{ 7621 Module: testModule(t, "issue-5254/step-1"), 7622 State: state, 7623 Providers: map[string]ResourceProviderFactory{ 7624 "template": testProviderFuncFixed(p), 7625 }, 7626 }) 7627 7628 plan, err = ctx.Plan() 7629 if err != nil { 7630 t.Fatalf("err: %s", err) 7631 } 7632 7633 // Write / Read plan to simulate running it through a Plan file 7634 var buf bytes.Buffer 7635 if err := WritePlan(plan, &buf); err != nil { 7636 t.Fatalf("err: %s", err) 7637 } 7638 7639 planFromFile, err := ReadPlan(&buf) 7640 if err != nil { 7641 t.Fatalf("err: %s", err) 7642 } 7643 7644 ctx, err = planFromFile.Context(&ContextOpts{ 7645 Providers: map[string]ResourceProviderFactory{ 7646 "template": testProviderFuncFixed(p), 7647 }, 7648 }) 7649 if err != nil { 7650 t.Fatalf("err: %s", err) 7651 } 7652 7653 state, err = ctx.Apply() 7654 if err != nil { 7655 t.Fatalf("err: %s", err) 7656 } 7657 7658 actual := strings.TrimSpace(state.String()) 7659 expected := strings.TrimSpace(` 7660 template_file.child: 7661 ID = foo 7662 template = Hi 7663 type = template_file 7664 7665 Dependencies: 7666 template_file.parent.* 7667 template_file.parent: 7668 ID = foo 7669 template = Hi 7670 type = template_file 7671 `) 7672 if actual != expected { 7673 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 7674 } 7675 } 7676 7677 func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { 7678 p := testProvider("aws") 7679 p.DiffFn = testDiffFn 7680 p.ApplyFn = testApplyFn 7681 ctx := testContext2(t, &ContextOpts{ 7682 Module: testModule(t, "apply-tainted-targets"), 7683 Providers: map[string]ResourceProviderFactory{ 7684 "aws": testProviderFuncFixed(p), 7685 }, 7686 Targets: []string{"aws_instance.iambeingadded"}, 7687 State: &State{ 7688 Modules: []*ModuleState{ 7689 &ModuleState{ 7690 Path: rootModulePath, 7691 Resources: map[string]*ResourceState{ 7692 "aws_instance.ifailedprovisioners": &ResourceState{ 7693 Primary: &InstanceState{ 7694 ID: "ifailedprovisioners", 7695 Tainted: true, 7696 }, 7697 }, 7698 }, 7699 }, 7700 }, 7701 }, 7702 }) 7703 7704 plan, err := ctx.Plan() 7705 if err != nil { 7706 t.Fatalf("err: %s", err) 7707 } 7708 7709 // Write / Read plan to simulate running it through a Plan file 7710 var buf bytes.Buffer 7711 if err := WritePlan(plan, &buf); err != nil { 7712 t.Fatalf("err: %s", err) 7713 } 7714 7715 planFromFile, err := ReadPlan(&buf) 7716 if err != nil { 7717 t.Fatalf("err: %s", err) 7718 } 7719 7720 ctx, err = planFromFile.Context(&ContextOpts{ 7721 Module: testModule(t, "apply-tainted-targets"), 7722 Providers: map[string]ResourceProviderFactory{ 7723 "aws": testProviderFuncFixed(p), 7724 }, 7725 }) 7726 if err != nil { 7727 t.Fatalf("err: %s", err) 7728 } 7729 7730 state, err := ctx.Apply() 7731 if err != nil { 7732 t.Fatalf("err: %s", err) 7733 } 7734 7735 actual := strings.TrimSpace(state.String()) 7736 expected := strings.TrimSpace(` 7737 aws_instance.iambeingadded: 7738 ID = foo 7739 aws_instance.ifailedprovisioners: (tainted) 7740 ID = ifailedprovisioners 7741 `) 7742 if actual != expected { 7743 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 7744 } 7745 } 7746 7747 // Higher level test exposing the bug this covers in 7748 // TestResource_ignoreChangesRequired 7749 func TestContext2Apply_ignoreChangesCreate(t *testing.T) { 7750 m := testModule(t, "apply-ignore-changes-create") 7751 p := testProvider("aws") 7752 p.ApplyFn = testApplyFn 7753 p.DiffFn = testDiffFn 7754 ctx := testContext2(t, &ContextOpts{ 7755 Module: m, 7756 Providers: map[string]ResourceProviderFactory{ 7757 "aws": testProviderFuncFixed(p), 7758 }, 7759 }) 7760 7761 if p, err := ctx.Plan(); err != nil { 7762 t.Fatalf("err: %s", err) 7763 } else { 7764 t.Logf(p.String()) 7765 } 7766 7767 state, err := ctx.Apply() 7768 if err != nil { 7769 t.Fatalf("err: %s", err) 7770 } 7771 7772 mod := state.RootModule() 7773 if len(mod.Resources) != 1 { 7774 t.Fatalf("bad: %s", state) 7775 } 7776 7777 actual := strings.TrimSpace(state.String()) 7778 // Expect no changes from original state 7779 expected := strings.TrimSpace(` 7780 aws_instance.foo: 7781 ID = foo 7782 required_field = set 7783 type = aws_instance 7784 `) 7785 if actual != expected { 7786 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 7787 } 7788 } 7789 7790 func TestContext2Apply_ignoreChangesWithDep(t *testing.T) { 7791 m := testModule(t, "apply-ignore-changes-dep") 7792 p := testProvider("aws") 7793 p.ApplyFn = testApplyFn 7794 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 7795 switch i.Type { 7796 case "aws_instance": 7797 newAmi, _ := c.Get("ami") 7798 return &InstanceDiff{ 7799 Attributes: map[string]*ResourceAttrDiff{ 7800 "ami": &ResourceAttrDiff{ 7801 Old: s.Attributes["ami"], 7802 New: newAmi.(string), 7803 RequiresNew: true, 7804 }, 7805 }, 7806 }, nil 7807 case "aws_eip": 7808 return testDiffFn(i, s, c) 7809 default: 7810 t.Fatalf("Unexpected type: %s", i.Type) 7811 return nil, nil 7812 } 7813 } 7814 s := &State{ 7815 Modules: []*ModuleState{ 7816 &ModuleState{ 7817 Path: rootModulePath, 7818 Resources: map[string]*ResourceState{ 7819 "aws_instance.foo.0": &ResourceState{ 7820 Primary: &InstanceState{ 7821 ID: "i-abc123", 7822 Attributes: map[string]string{ 7823 "ami": "ami-abcd1234", 7824 "id": "i-abc123", 7825 }, 7826 }, 7827 }, 7828 "aws_instance.foo.1": &ResourceState{ 7829 Primary: &InstanceState{ 7830 ID: "i-bcd234", 7831 Attributes: map[string]string{ 7832 "ami": "ami-abcd1234", 7833 "id": "i-bcd234", 7834 }, 7835 }, 7836 }, 7837 "aws_eip.foo.0": &ResourceState{ 7838 Primary: &InstanceState{ 7839 ID: "eip-abc123", 7840 Attributes: map[string]string{ 7841 "id": "eip-abc123", 7842 "instance": "i-abc123", 7843 }, 7844 }, 7845 }, 7846 "aws_eip.foo.1": &ResourceState{ 7847 Primary: &InstanceState{ 7848 ID: "eip-bcd234", 7849 Attributes: map[string]string{ 7850 "id": "eip-bcd234", 7851 "instance": "i-bcd234", 7852 }, 7853 }, 7854 }, 7855 }, 7856 }, 7857 }, 7858 } 7859 ctx := testContext2(t, &ContextOpts{ 7860 Module: m, 7861 Providers: map[string]ResourceProviderFactory{ 7862 "aws": testProviderFuncFixed(p), 7863 }, 7864 State: s, 7865 }) 7866 7867 if p, err := ctx.Plan(); err != nil { 7868 t.Fatalf("err: %s", err) 7869 } else { 7870 t.Logf(p.String()) 7871 } 7872 7873 state, err := ctx.Apply() 7874 if err != nil { 7875 t.Fatalf("err: %s", err) 7876 } 7877 7878 actual := strings.TrimSpace(state.String()) 7879 expected := strings.TrimSpace(s.String()) 7880 if actual != expected { 7881 t.Fatalf("bad: \n%s", actual) 7882 } 7883 } 7884 7885 func TestContext2Apply_ignoreChangesWildcard(t *testing.T) { 7886 m := testModule(t, "apply-ignore-changes-wildcard") 7887 p := testProvider("aws") 7888 p.ApplyFn = testApplyFn 7889 p.DiffFn = testDiffFn 7890 ctx := testContext2(t, &ContextOpts{ 7891 Module: m, 7892 Providers: map[string]ResourceProviderFactory{ 7893 "aws": testProviderFuncFixed(p), 7894 }, 7895 }) 7896 7897 if p, err := ctx.Plan(); err != nil { 7898 t.Fatalf("err: %s", err) 7899 } else { 7900 t.Logf(p.String()) 7901 } 7902 7903 state, err := ctx.Apply() 7904 if err != nil { 7905 t.Fatalf("err: %s", err) 7906 } 7907 7908 mod := state.RootModule() 7909 if len(mod.Resources) != 1 { 7910 t.Fatalf("bad: %s", state) 7911 } 7912 7913 actual := strings.TrimSpace(state.String()) 7914 // Expect no changes from original state 7915 expected := strings.TrimSpace(` 7916 aws_instance.foo: 7917 ID = foo 7918 required_field = set 7919 type = aws_instance 7920 `) 7921 if actual != expected { 7922 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 7923 } 7924 } 7925 7926 // https://github.com/hashicorp/terraform/issues/7378 7927 func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) { 7928 m := testModule(t, "apply-destroy-nested-module-with-attrs") 7929 p := testProvider("null") 7930 p.ApplyFn = testApplyFn 7931 p.DiffFn = testDiffFn 7932 7933 var state *State 7934 var err error 7935 { 7936 ctx := testContext2(t, &ContextOpts{ 7937 Module: m, 7938 Providers: map[string]ResourceProviderFactory{ 7939 "null": testProviderFuncFixed(p), 7940 }, 7941 }) 7942 7943 // First plan and apply a create operation 7944 if _, err := ctx.Plan(); err != nil { 7945 t.Fatalf("plan err: %s", err) 7946 } 7947 7948 state, err = ctx.Apply() 7949 if err != nil { 7950 t.Fatalf("apply err: %s", err) 7951 } 7952 } 7953 7954 { 7955 ctx := testContext2(t, &ContextOpts{ 7956 Destroy: true, 7957 Module: m, 7958 State: state, 7959 Providers: map[string]ResourceProviderFactory{ 7960 "null": testProviderFuncFixed(p), 7961 }, 7962 }) 7963 7964 plan, err := ctx.Plan() 7965 if err != nil { 7966 t.Fatalf("destroy plan err: %s", err) 7967 } 7968 7969 var buf bytes.Buffer 7970 if err := WritePlan(plan, &buf); err != nil { 7971 t.Fatalf("plan write err: %s", err) 7972 } 7973 7974 planFromFile, err := ReadPlan(&buf) 7975 if err != nil { 7976 t.Fatalf("plan read err: %s", err) 7977 } 7978 7979 ctx, err = planFromFile.Context(&ContextOpts{ 7980 Providers: map[string]ResourceProviderFactory{ 7981 "null": testProviderFuncFixed(p), 7982 }, 7983 }) 7984 if err != nil { 7985 t.Fatalf("err: %s", err) 7986 } 7987 7988 state, err = ctx.Apply() 7989 if err != nil { 7990 t.Fatalf("destroy apply err: %s", err) 7991 } 7992 } 7993 7994 //Test that things were destroyed 7995 actual := strings.TrimSpace(state.String()) 7996 expected := strings.TrimSpace(` 7997 <no state> 7998 module.middle: 7999 <no state> 8000 module.middle.bottom: 8001 <no state> 8002 `) 8003 if actual != expected { 8004 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 8005 } 8006 } 8007 8008 // If a data source explicitly depends on another resource, it's because we need 8009 // that resource to be applied first. 8010 func TestContext2Apply_dataDependsOn(t *testing.T) { 8011 p := testProvider("null") 8012 m := testModule(t, "apply-data-depends-on") 8013 8014 ctx := testContext2(t, &ContextOpts{ 8015 Module: m, 8016 Providers: map[string]ResourceProviderFactory{ 8017 "null": testProviderFuncFixed(p), 8018 }, 8019 }) 8020 8021 // the "provisioner" here writes to this variable, because the intent is to 8022 // create a dependency which can't be viewed through the graph, and depends 8023 // solely on the configuration providing "depends_on" 8024 provisionerOutput := "" 8025 8026 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 8027 // the side effect of the resource being applied 8028 provisionerOutput = "APPLIED" 8029 return testApplyFn(info, s, d) 8030 } 8031 8032 p.DiffFn = testDiffFn 8033 p.ReadDataDiffFn = testDataDiffFn 8034 8035 p.ReadDataApplyFn = func(*InstanceInfo, *InstanceDiff) (*InstanceState, error) { 8036 // Read the artifact created by our dependency being applied. 8037 // Without any "depends_on", this would be skipped as it's assumed the 8038 // initial diff during refresh was all that's needed. 8039 return &InstanceState{ 8040 ID: "read", 8041 Attributes: map[string]string{ 8042 "foo": provisionerOutput, 8043 }, 8044 }, nil 8045 } 8046 8047 _, err := ctx.Refresh() 8048 if err != nil { 8049 t.Fatalf("err: %s", err) 8050 } 8051 8052 if _, err := ctx.Plan(); err != nil { 8053 t.Fatalf("err: %s", err) 8054 } 8055 8056 state, err := ctx.Apply() 8057 if err != nil { 8058 t.Fatalf("err: %s", err) 8059 } 8060 8061 root := state.ModuleByPath(RootModulePath) 8062 actual := root.Resources["data.null_data_source.read"].Primary.Attributes["foo"] 8063 8064 expected := "APPLIED" 8065 if actual != expected { 8066 t.Fatalf("bad:\n%s", strings.TrimSpace(state.String())) 8067 } 8068 }