github.com/mikesimons/terraform@v0.6.13-0.20160304043642-f11448c69214/terraform/context_apply_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "fmt" 6 "os" 7 "reflect" 8 "sort" 9 "strings" 10 "sync" 11 "sync/atomic" 12 "testing" 13 "time" 14 15 "github.com/hashicorp/terraform/config/module" 16 ) 17 18 func TestContext2Apply(t *testing.T) { 19 m := testModule(t, "apply-good") 20 p := testProvider("aws") 21 p.ApplyFn = testApplyFn 22 p.DiffFn = testDiffFn 23 ctx := testContext2(t, &ContextOpts{ 24 Module: m, 25 Providers: map[string]ResourceProviderFactory{ 26 "aws": testProviderFuncFixed(p), 27 }, 28 }) 29 30 if _, err := ctx.Plan(); err != nil { 31 t.Fatalf("err: %s", err) 32 } 33 34 state, err := ctx.Apply() 35 if err != nil { 36 t.Fatalf("err: %s", err) 37 } 38 39 mod := state.RootModule() 40 if len(mod.Resources) < 2 { 41 t.Fatalf("bad: %#v", mod.Resources) 42 } 43 44 actual := strings.TrimSpace(state.String()) 45 expected := strings.TrimSpace(testTerraformApplyStr) 46 if actual != expected { 47 t.Fatalf("bad: \n%s", actual) 48 } 49 } 50 51 func TestContext2Apply_providerAlias(t *testing.T) { 52 m := testModule(t, "apply-provider-alias") 53 p := testProvider("aws") 54 p.ApplyFn = testApplyFn 55 p.DiffFn = testDiffFn 56 ctx := testContext2(t, &ContextOpts{ 57 Module: m, 58 Providers: map[string]ResourceProviderFactory{ 59 "aws": testProviderFuncFixed(p), 60 }, 61 }) 62 63 if _, err := ctx.Plan(); err != nil { 64 t.Fatalf("err: %s", err) 65 } 66 67 state, err := ctx.Apply() 68 if err != nil { 69 t.Fatalf("err: %s", err) 70 } 71 72 mod := state.RootModule() 73 if len(mod.Resources) < 2 { 74 t.Fatalf("bad: %#v", mod.Resources) 75 } 76 77 actual := strings.TrimSpace(state.String()) 78 expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) 79 if actual != expected { 80 t.Fatalf("bad: \n%s", actual) 81 } 82 } 83 84 // GH-2870 85 func TestContext2Apply_providerWarning(t *testing.T) { 86 m := testModule(t, "apply-provider-warning") 87 p := testProvider("aws") 88 p.ApplyFn = testApplyFn 89 p.DiffFn = testDiffFn 90 p.ValidateFn = func(c *ResourceConfig) (ws []string, es []error) { 91 ws = append(ws, "Just a warning") 92 return 93 } 94 ctx := testContext2(t, &ContextOpts{ 95 Module: m, 96 Providers: map[string]ResourceProviderFactory{ 97 "aws": testProviderFuncFixed(p), 98 }, 99 }) 100 101 if _, err := ctx.Plan(); err != nil { 102 t.Fatalf("err: %s", err) 103 } 104 105 state, err := ctx.Apply() 106 if err != nil { 107 t.Fatalf("err: %s", err) 108 } 109 110 actual := strings.TrimSpace(state.String()) 111 expected := strings.TrimSpace(` 112 aws_instance.foo: 113 ID = foo 114 `) 115 if actual != expected { 116 t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected) 117 } 118 119 if !p.ConfigureCalled { 120 t.Fatalf("provider Configure() was never called!") 121 } 122 } 123 124 func TestContext2Apply_emptyModule(t *testing.T) { 125 m := testModule(t, "apply-empty-module") 126 p := testProvider("aws") 127 p.ApplyFn = testApplyFn 128 p.DiffFn = testDiffFn 129 ctx := testContext2(t, &ContextOpts{ 130 Module: m, 131 Providers: map[string]ResourceProviderFactory{ 132 "aws": testProviderFuncFixed(p), 133 }, 134 }) 135 136 if _, err := ctx.Plan(); err != nil { 137 t.Fatalf("err: %s", err) 138 } 139 140 state, err := ctx.Apply() 141 if err != nil { 142 t.Fatalf("err: %s", err) 143 } 144 145 actual := strings.TrimSpace(state.String()) 146 actual = strings.Replace(actual, " ", "", -1) 147 expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr) 148 if actual != expected { 149 t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected) 150 } 151 } 152 153 func TestContext2Apply_createBeforeDestroy(t *testing.T) { 154 m := testModule(t, "apply-good-create-before") 155 p := testProvider("aws") 156 p.ApplyFn = testApplyFn 157 p.DiffFn = testDiffFn 158 state := &State{ 159 Modules: []*ModuleState{ 160 &ModuleState{ 161 Path: rootModulePath, 162 Resources: map[string]*ResourceState{ 163 "aws_instance.bar": &ResourceState{ 164 Type: "aws_instance", 165 Primary: &InstanceState{ 166 ID: "bar", 167 Attributes: map[string]string{ 168 "require_new": "abc", 169 }, 170 }, 171 }, 172 }, 173 }, 174 }, 175 } 176 ctx := testContext2(t, &ContextOpts{ 177 Module: m, 178 Providers: map[string]ResourceProviderFactory{ 179 "aws": testProviderFuncFixed(p), 180 }, 181 State: state, 182 }) 183 184 if p, err := ctx.Plan(); err != nil { 185 t.Fatalf("err: %s", err) 186 } else { 187 t.Logf(p.String()) 188 } 189 190 state, err := ctx.Apply() 191 if err != nil { 192 t.Fatalf("err: %s", err) 193 } 194 195 mod := state.RootModule() 196 if len(mod.Resources) != 1 { 197 t.Fatalf("bad: %s", state) 198 } 199 200 actual := strings.TrimSpace(state.String()) 201 expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr) 202 if actual != expected { 203 t.Fatalf("bad: \n%s", actual) 204 } 205 } 206 207 func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { 208 m := testModule(t, "apply-good-create-before-update") 209 p := testProvider("aws") 210 p.ApplyFn = testApplyFn 211 p.DiffFn = testDiffFn 212 state := &State{ 213 Modules: []*ModuleState{ 214 &ModuleState{ 215 Path: rootModulePath, 216 Resources: map[string]*ResourceState{ 217 "aws_instance.bar": &ResourceState{ 218 Type: "aws_instance", 219 Primary: &InstanceState{ 220 ID: "bar", 221 Attributes: map[string]string{ 222 "foo": "bar", 223 }, 224 }, 225 }, 226 }, 227 }, 228 }, 229 } 230 ctx := testContext2(t, &ContextOpts{ 231 Module: m, 232 Providers: map[string]ResourceProviderFactory{ 233 "aws": testProviderFuncFixed(p), 234 }, 235 State: state, 236 }) 237 238 if p, err := ctx.Plan(); err != nil { 239 t.Fatalf("err: %s", err) 240 } else { 241 t.Logf(p.String()) 242 } 243 244 state, err := ctx.Apply() 245 if err != nil { 246 t.Fatalf("err: %s", err) 247 } 248 249 mod := state.RootModule() 250 if len(mod.Resources) != 1 { 251 t.Fatalf("bad: %s", state) 252 } 253 254 actual := strings.TrimSpace(state.String()) 255 expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr) 256 if actual != expected { 257 t.Fatalf("bad: \n%s", actual) 258 } 259 } 260 261 func TestContext2Apply_destroyComputed(t *testing.T) { 262 m := testModule(t, "apply-destroy-computed") 263 p := testProvider("aws") 264 p.ApplyFn = testApplyFn 265 p.DiffFn = testDiffFn 266 state := &State{ 267 Modules: []*ModuleState{ 268 &ModuleState{ 269 Path: rootModulePath, 270 Resources: map[string]*ResourceState{ 271 "aws_instance.foo": &ResourceState{ 272 Type: "aws_instance", 273 Primary: &InstanceState{ 274 ID: "foo", 275 Attributes: map[string]string{ 276 "output": "value", 277 }, 278 }, 279 }, 280 }, 281 }, 282 }, 283 } 284 ctx := testContext2(t, &ContextOpts{ 285 Module: m, 286 Providers: map[string]ResourceProviderFactory{ 287 "aws": testProviderFuncFixed(p), 288 }, 289 State: state, 290 Destroy: true, 291 }) 292 293 if p, err := ctx.Plan(); err != nil { 294 t.Fatalf("err: %s", err) 295 } else { 296 t.Logf(p.String()) 297 } 298 299 if _, err := ctx.Apply(); err != nil { 300 t.Fatalf("err: %s", err) 301 } 302 } 303 304 // https://github.com/hashicorp/terraform/pull/5096 305 func TestContext2Apply_destroySkipsCBD(t *testing.T) { 306 // Config contains CBD resource depending on non-CBD resource, which triggers 307 // a cycle if they are both replaced, but should _not_ trigger a cycle when 308 // just doing a `terraform destroy`. 309 m := testModule(t, "apply-destroy-cbd") 310 p := testProvider("aws") 311 p.ApplyFn = testApplyFn 312 p.DiffFn = testDiffFn 313 state := &State{ 314 Modules: []*ModuleState{ 315 &ModuleState{ 316 Path: rootModulePath, 317 Resources: map[string]*ResourceState{ 318 "aws_instance.foo": &ResourceState{ 319 Type: "aws_instance", 320 Primary: &InstanceState{ 321 ID: "foo", 322 }, 323 }, 324 "aws_instance.bar": &ResourceState{ 325 Type: "aws_instance", 326 Primary: &InstanceState{ 327 ID: "foo", 328 }, 329 }, 330 }, 331 }, 332 }, 333 } 334 ctx := testContext2(t, &ContextOpts{ 335 Module: m, 336 Providers: map[string]ResourceProviderFactory{ 337 "aws": testProviderFuncFixed(p), 338 }, 339 State: state, 340 Destroy: true, 341 }) 342 343 if p, err := ctx.Plan(); err != nil { 344 t.Fatalf("err: %s", err) 345 } else { 346 t.Logf(p.String()) 347 } 348 349 if _, err := ctx.Apply(); err != nil { 350 t.Fatalf("err: %s", err) 351 } 352 } 353 354 // https://github.com/hashicorp/terraform/issues/2892 355 func TestContext2Apply_destroyCrossProviders(t *testing.T) { 356 m := testModule(t, "apply-destroy-cross-providers") 357 358 p_aws := testProvider("aws") 359 p_aws.ApplyFn = testApplyFn 360 p_aws.DiffFn = testDiffFn 361 362 p_tf := testProvider("terraform") 363 p_tf.ApplyFn = testApplyFn 364 p_tf.DiffFn = testDiffFn 365 366 providers := map[string]ResourceProviderFactory{ 367 "aws": testProviderFuncFixed(p_aws), 368 "terraform": testProviderFuncFixed(p_tf), 369 } 370 371 // Bug only appears from time to time, 372 // so we run this test multiple times 373 // to check for the race-condition 374 for i := 0; i <= 10; i++ { 375 ctx := getContextForApply_destroyCrossProviders( 376 t, m, providers) 377 378 if p, err := ctx.Plan(); err != nil { 379 t.Fatalf("err: %s", err) 380 } else { 381 t.Logf(p.String()) 382 } 383 384 if _, err := ctx.Apply(); err != nil { 385 t.Fatalf("err: %s", err) 386 } 387 } 388 } 389 390 func getContextForApply_destroyCrossProviders( 391 t *testing.T, 392 m *module.Tree, 393 providers map[string]ResourceProviderFactory) *Context { 394 state := &State{ 395 Modules: []*ModuleState{ 396 &ModuleState{ 397 Path: rootModulePath, 398 Resources: map[string]*ResourceState{ 399 "terraform_remote_state.shared": &ResourceState{ 400 Type: "terraform_remote_state", 401 Primary: &InstanceState{ 402 ID: "remote-2652591293", 403 Attributes: map[string]string{ 404 "output.env_name": "test", 405 }, 406 }, 407 }, 408 }, 409 }, 410 &ModuleState{ 411 Path: []string{"root", "example"}, 412 Resources: map[string]*ResourceState{ 413 "aws_vpc.bar": &ResourceState{ 414 Type: "aws_vpc", 415 Primary: &InstanceState{ 416 ID: "vpc-aaabbb12", 417 Attributes: map[string]string{ 418 "value": "test", 419 }, 420 }, 421 }, 422 }, 423 }, 424 }, 425 } 426 ctx := testContext2(t, &ContextOpts{ 427 Module: m, 428 Providers: providers, 429 State: state, 430 Destroy: true, 431 }) 432 433 return ctx 434 } 435 436 func TestContext2Apply_minimal(t *testing.T) { 437 m := testModule(t, "apply-minimal") 438 p := testProvider("aws") 439 p.ApplyFn = testApplyFn 440 p.DiffFn = testDiffFn 441 ctx := testContext2(t, &ContextOpts{ 442 Module: m, 443 Providers: map[string]ResourceProviderFactory{ 444 "aws": testProviderFuncFixed(p), 445 }, 446 }) 447 448 if _, err := ctx.Plan(); err != nil { 449 t.Fatalf("err: %s", err) 450 } 451 452 state, err := ctx.Apply() 453 if err != nil { 454 t.Fatalf("err: %s", err) 455 } 456 457 actual := strings.TrimSpace(state.String()) 458 expected := strings.TrimSpace(testTerraformApplyMinimalStr) 459 if actual != expected { 460 t.Fatalf("bad: \n%s", actual) 461 } 462 } 463 464 func TestContext2Apply_badDiff(t *testing.T) { 465 m := testModule(t, "apply-good") 466 p := testProvider("aws") 467 p.ApplyFn = testApplyFn 468 p.DiffFn = testDiffFn 469 ctx := testContext2(t, &ContextOpts{ 470 Module: m, 471 Providers: map[string]ResourceProviderFactory{ 472 "aws": testProviderFuncFixed(p), 473 }, 474 }) 475 476 if _, err := ctx.Plan(); err != nil { 477 t.Fatalf("err: %s", err) 478 } 479 480 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 481 return &InstanceDiff{ 482 Attributes: map[string]*ResourceAttrDiff{ 483 "newp": nil, 484 }, 485 }, nil 486 } 487 488 if _, err := ctx.Apply(); err == nil { 489 t.Fatal("should error") 490 } 491 } 492 493 func TestContext2Apply_cancel(t *testing.T) { 494 stopped := false 495 496 m := testModule(t, "apply-cancel") 497 p := testProvider("aws") 498 ctx := testContext2(t, &ContextOpts{ 499 Module: m, 500 Providers: map[string]ResourceProviderFactory{ 501 "aws": testProviderFuncFixed(p), 502 }, 503 }) 504 505 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 506 if !stopped { 507 stopped = true 508 go ctx.Stop() 509 510 for { 511 if ctx.sh.Stopped() { 512 break 513 } 514 } 515 } 516 517 return &InstanceState{ 518 ID: "foo", 519 Attributes: map[string]string{ 520 "num": "2", 521 }, 522 }, nil 523 } 524 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 525 return &InstanceDiff{ 526 Attributes: map[string]*ResourceAttrDiff{ 527 "num": &ResourceAttrDiff{ 528 New: "bar", 529 }, 530 }, 531 }, nil 532 } 533 534 if _, err := ctx.Plan(); err != nil { 535 t.Fatalf("err: %s", err) 536 } 537 538 // Start the Apply in a goroutine 539 stateCh := make(chan *State) 540 go func() { 541 state, err := ctx.Apply() 542 if err != nil { 543 panic(err) 544 } 545 546 stateCh <- state 547 }() 548 549 state := <-stateCh 550 551 mod := state.RootModule() 552 if len(mod.Resources) != 1 { 553 t.Fatalf("bad: %s", state.String()) 554 } 555 556 actual := strings.TrimSpace(state.String()) 557 expected := strings.TrimSpace(testTerraformApplyCancelStr) 558 if actual != expected { 559 t.Fatalf("bad: \n%s", actual) 560 } 561 } 562 563 func TestContext2Apply_compute(t *testing.T) { 564 m := testModule(t, "apply-compute") 565 p := testProvider("aws") 566 p.ApplyFn = testApplyFn 567 p.DiffFn = testDiffFn 568 ctx := testContext2(t, &ContextOpts{ 569 Module: m, 570 Providers: map[string]ResourceProviderFactory{ 571 "aws": testProviderFuncFixed(p), 572 }, 573 }) 574 575 if _, err := ctx.Plan(); err != nil { 576 t.Fatalf("err: %s", err) 577 } 578 579 ctx.variables = map[string]string{"value": "1"} 580 581 state, err := ctx.Apply() 582 if err != nil { 583 t.Fatalf("err: %s", err) 584 } 585 586 actual := strings.TrimSpace(state.String()) 587 expected := strings.TrimSpace(testTerraformApplyComputeStr) 588 if actual != expected { 589 t.Fatalf("bad: \n%s", actual) 590 } 591 } 592 593 func TestContext2Apply_countDecrease(t *testing.T) { 594 m := testModule(t, "apply-count-dec") 595 p := testProvider("aws") 596 p.DiffFn = testDiffFn 597 s := &State{ 598 Modules: []*ModuleState{ 599 &ModuleState{ 600 Path: rootModulePath, 601 Resources: map[string]*ResourceState{ 602 "aws_instance.foo.0": &ResourceState{ 603 Type: "aws_instance", 604 Primary: &InstanceState{ 605 ID: "bar", 606 Attributes: map[string]string{ 607 "foo": "foo", 608 "type": "aws_instance", 609 }, 610 }, 611 }, 612 "aws_instance.foo.1": &ResourceState{ 613 Type: "aws_instance", 614 Primary: &InstanceState{ 615 ID: "bar", 616 Attributes: map[string]string{ 617 "foo": "foo", 618 "type": "aws_instance", 619 }, 620 }, 621 }, 622 "aws_instance.foo.2": &ResourceState{ 623 Type: "aws_instance", 624 Primary: &InstanceState{ 625 ID: "bar", 626 Attributes: map[string]string{ 627 "foo": "foo", 628 "type": "aws_instance", 629 }, 630 }, 631 }, 632 }, 633 }, 634 }, 635 } 636 ctx := testContext2(t, &ContextOpts{ 637 Module: m, 638 Providers: map[string]ResourceProviderFactory{ 639 "aws": testProviderFuncFixed(p), 640 }, 641 State: s, 642 }) 643 644 if _, err := ctx.Plan(); err != nil { 645 t.Fatalf("err: %s", err) 646 } 647 648 state, err := ctx.Apply() 649 if err != nil { 650 t.Fatalf("err: %s", err) 651 } 652 653 actual := strings.TrimSpace(state.String()) 654 expected := strings.TrimSpace(testTerraformApplyCountDecStr) 655 if actual != expected { 656 t.Fatalf("bad: \n%s", actual) 657 } 658 } 659 660 func TestContext2Apply_countDecreaseToOne(t *testing.T) { 661 m := testModule(t, "apply-count-dec-one") 662 p := testProvider("aws") 663 p.ApplyFn = testApplyFn 664 p.DiffFn = testDiffFn 665 s := &State{ 666 Modules: []*ModuleState{ 667 &ModuleState{ 668 Path: rootModulePath, 669 Resources: map[string]*ResourceState{ 670 "aws_instance.foo.0": &ResourceState{ 671 Type: "aws_instance", 672 Primary: &InstanceState{ 673 ID: "bar", 674 Attributes: map[string]string{ 675 "foo": "foo", 676 "type": "aws_instance", 677 }, 678 }, 679 }, 680 "aws_instance.foo.1": &ResourceState{ 681 Type: "aws_instance", 682 Primary: &InstanceState{ 683 ID: "bar", 684 }, 685 }, 686 "aws_instance.foo.2": &ResourceState{ 687 Type: "aws_instance", 688 Primary: &InstanceState{ 689 ID: "bar", 690 }, 691 }, 692 }, 693 }, 694 }, 695 } 696 ctx := testContext2(t, &ContextOpts{ 697 Module: m, 698 Providers: map[string]ResourceProviderFactory{ 699 "aws": testProviderFuncFixed(p), 700 }, 701 State: s, 702 }) 703 704 if _, err := ctx.Plan(); err != nil { 705 t.Fatalf("err: %s", err) 706 } 707 708 state, err := ctx.Apply() 709 if err != nil { 710 t.Fatalf("err: %s", err) 711 } 712 713 actual := strings.TrimSpace(state.String()) 714 expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) 715 if actual != expected { 716 t.Fatalf("bad: \n%s", actual) 717 } 718 } 719 720 // https://github.com/PeoplePerHour/terraform/pull/11 721 // 722 // This tests a case where both a "resource" and "resource.0" are in 723 // the state file, which apparently is a reasonable backwards compatibility 724 // concern found in the above 3rd party repo. 725 func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { 726 m := testModule(t, "apply-count-dec-one") 727 p := testProvider("aws") 728 p.ApplyFn = testApplyFn 729 p.DiffFn = testDiffFn 730 s := &State{ 731 Modules: []*ModuleState{ 732 &ModuleState{ 733 Path: rootModulePath, 734 Resources: map[string]*ResourceState{ 735 "aws_instance.foo": &ResourceState{ 736 Type: "aws_instance", 737 Primary: &InstanceState{ 738 ID: "bar", 739 Attributes: map[string]string{ 740 "foo": "foo", 741 "type": "aws_instance", 742 }, 743 }, 744 }, 745 "aws_instance.foo.0": &ResourceState{ 746 Type: "aws_instance", 747 Primary: &InstanceState{ 748 ID: "baz", 749 Attributes: map[string]string{ 750 "type": "aws_instance", 751 }, 752 }, 753 }, 754 }, 755 }, 756 }, 757 } 758 ctx := testContext2(t, &ContextOpts{ 759 Module: m, 760 Providers: map[string]ResourceProviderFactory{ 761 "aws": testProviderFuncFixed(p), 762 }, 763 State: s, 764 }) 765 766 if p, err := ctx.Plan(); err != nil { 767 t.Fatalf("err: %s", err) 768 } else { 769 testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr) 770 } 771 772 state, err := ctx.Apply() 773 if err != nil { 774 t.Fatalf("err: %s", err) 775 } 776 777 actual := strings.TrimSpace(state.String()) 778 expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) 779 if actual != expected { 780 t.Fatalf("bad: \n%s", actual) 781 } 782 } 783 784 func TestContext2Apply_countTainted(t *testing.T) { 785 m := testModule(t, "apply-count-tainted") 786 p := testProvider("aws") 787 p.DiffFn = testDiffFn 788 s := &State{ 789 Modules: []*ModuleState{ 790 &ModuleState{ 791 Path: rootModulePath, 792 Resources: map[string]*ResourceState{ 793 "aws_instance.foo.0": &ResourceState{ 794 Type: "aws_instance", 795 Tainted: []*InstanceState{ 796 &InstanceState{ 797 ID: "bar", 798 Attributes: map[string]string{ 799 "foo": "foo", 800 "type": "aws_instance", 801 }, 802 }, 803 }, 804 }, 805 }, 806 }, 807 }, 808 } 809 ctx := testContext2(t, &ContextOpts{ 810 Module: m, 811 Providers: map[string]ResourceProviderFactory{ 812 "aws": testProviderFuncFixed(p), 813 }, 814 State: s, 815 }) 816 817 if _, err := ctx.Plan(); err != nil { 818 t.Fatalf("err: %s", err) 819 } 820 821 state, err := ctx.Apply() 822 if err != nil { 823 t.Fatalf("err: %s", err) 824 } 825 826 actual := strings.TrimSpace(state.String()) 827 expected := strings.TrimSpace(testTerraformApplyCountTaintedStr) 828 if actual != expected { 829 t.Fatalf("bad: \n%s", actual) 830 } 831 } 832 833 func TestContext2Apply_countVariable(t *testing.T) { 834 m := testModule(t, "apply-count-variable") 835 p := testProvider("aws") 836 p.ApplyFn = testApplyFn 837 p.DiffFn = testDiffFn 838 ctx := testContext2(t, &ContextOpts{ 839 Module: m, 840 Providers: map[string]ResourceProviderFactory{ 841 "aws": testProviderFuncFixed(p), 842 }, 843 }) 844 845 if _, err := ctx.Plan(); err != nil { 846 t.Fatalf("err: %s", err) 847 } 848 849 state, err := ctx.Apply() 850 if err != nil { 851 t.Fatalf("err: %s", err) 852 } 853 854 actual := strings.TrimSpace(state.String()) 855 expected := strings.TrimSpace(testTerraformApplyCountVariableStr) 856 if actual != expected { 857 t.Fatalf("bad: \n%s", actual) 858 } 859 } 860 861 func TestContext2Apply_mapVariableOverride(t *testing.T) { 862 m := testModule(t, "apply-map-var-override") 863 p := testProvider("aws") 864 p.ApplyFn = testApplyFn 865 p.DiffFn = testDiffFn 866 ctx := testContext2(t, &ContextOpts{ 867 Module: m, 868 Providers: map[string]ResourceProviderFactory{ 869 "aws": testProviderFuncFixed(p), 870 }, 871 Variables: map[string]string{ 872 "images.us-west-2": "overridden", 873 }, 874 }) 875 876 if _, err := ctx.Plan(); err != nil { 877 t.Fatalf("err: %s", err) 878 } 879 880 state, err := ctx.Apply() 881 if err != nil { 882 t.Fatalf("err: %s", err) 883 } 884 885 actual := strings.TrimSpace(state.String()) 886 expected := strings.TrimSpace(` 887 aws_instance.bar: 888 ID = foo 889 ami = overridden 890 type = aws_instance 891 aws_instance.foo: 892 ID = foo 893 ami = image-1234 894 type = aws_instance 895 `) 896 if actual != expected { 897 t.Fatalf("got: \n%s\nexpected: \n%s", actual, expected) 898 } 899 } 900 901 func TestContext2Apply_module(t *testing.T) { 902 m := testModule(t, "apply-module") 903 p := testProvider("aws") 904 p.ApplyFn = testApplyFn 905 p.DiffFn = testDiffFn 906 ctx := testContext2(t, &ContextOpts{ 907 Module: m, 908 Providers: map[string]ResourceProviderFactory{ 909 "aws": testProviderFuncFixed(p), 910 }, 911 }) 912 913 if _, err := ctx.Plan(); err != nil { 914 t.Fatalf("err: %s", err) 915 } 916 917 state, err := ctx.Apply() 918 if err != nil { 919 t.Fatalf("err: %s", err) 920 } 921 922 actual := strings.TrimSpace(state.String()) 923 expected := strings.TrimSpace(testTerraformApplyModuleStr) 924 if actual != expected { 925 t.Fatalf("bad: \n%s", actual) 926 } 927 } 928 929 func TestContext2Apply_moduleDestroyOrder(t *testing.T) { 930 m := testModule(t, "apply-module-destroy-order") 931 p := testProvider("aws") 932 p.DiffFn = testDiffFn 933 934 // Create a custom apply function to track the order they were destroyed 935 var order []string 936 var orderLock sync.Mutex 937 p.ApplyFn = func( 938 info *InstanceInfo, 939 is *InstanceState, 940 id *InstanceDiff) (*InstanceState, error) { 941 orderLock.Lock() 942 defer orderLock.Unlock() 943 944 order = append(order, is.ID) 945 return nil, nil 946 } 947 948 state := &State{ 949 Modules: []*ModuleState{ 950 &ModuleState{ 951 Path: rootModulePath, 952 Resources: map[string]*ResourceState{ 953 "aws_instance.b": &ResourceState{ 954 Type: "aws_instance", 955 Primary: &InstanceState{ 956 ID: "b", 957 }, 958 }, 959 }, 960 }, 961 962 &ModuleState{ 963 Path: []string{"root", "child"}, 964 Resources: map[string]*ResourceState{ 965 "aws_instance.a": &ResourceState{ 966 Type: "aws_instance", 967 Primary: &InstanceState{ 968 ID: "a", 969 }, 970 }, 971 }, 972 Outputs: map[string]string{ 973 "a_output": "a", 974 }, 975 }, 976 }, 977 } 978 979 ctx := testContext2(t, &ContextOpts{ 980 Module: m, 981 Providers: map[string]ResourceProviderFactory{ 982 "aws": testProviderFuncFixed(p), 983 }, 984 State: state, 985 Destroy: true, 986 }) 987 988 if _, err := ctx.Plan(); err != nil { 989 t.Fatalf("err: %s", err) 990 } 991 992 state, err := ctx.Apply() 993 if err != nil { 994 t.Fatalf("err: %s", err) 995 } 996 997 expected := []string{"b", "a"} 998 if !reflect.DeepEqual(order, expected) { 999 t.Fatalf("bad: %#v", order) 1000 } 1001 1002 { 1003 actual := strings.TrimSpace(state.String()) 1004 expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr) 1005 if actual != expected { 1006 t.Fatalf("bad: \n%s", actual) 1007 } 1008 } 1009 } 1010 1011 func TestContext2Apply_moduleOrphanProvider(t *testing.T) { 1012 m := testModule(t, "apply-module-orphan-provider-inherit") 1013 p := testProvider("aws") 1014 p.ApplyFn = testApplyFn 1015 p.DiffFn = testDiffFn 1016 1017 p.ConfigureFn = func(c *ResourceConfig) error { 1018 if _, ok := c.Get("value"); !ok { 1019 return fmt.Errorf("value is not found") 1020 } 1021 1022 return nil 1023 } 1024 1025 // Create a state with an orphan module 1026 state := &State{ 1027 Modules: []*ModuleState{ 1028 &ModuleState{ 1029 Path: []string{"root", "child"}, 1030 Resources: map[string]*ResourceState{ 1031 "aws_instance.bar": &ResourceState{ 1032 Type: "aws_instance", 1033 Primary: &InstanceState{ 1034 ID: "bar", 1035 }, 1036 }, 1037 }, 1038 }, 1039 }, 1040 } 1041 1042 ctx := testContext2(t, &ContextOpts{ 1043 Module: m, 1044 State: state, 1045 Providers: map[string]ResourceProviderFactory{ 1046 "aws": testProviderFuncFixed(p), 1047 }, 1048 }) 1049 1050 if _, err := ctx.Plan(); err != nil { 1051 t.Fatalf("err: %s", err) 1052 } 1053 1054 if _, err := ctx.Apply(); err != nil { 1055 t.Fatalf("err: %s", err) 1056 } 1057 } 1058 1059 // This tests an issue where all the providers in a module but not 1060 // in the root weren't being added to the root properly. In this test 1061 // case: aws is explicitly added to root, but "test" should be added to. 1062 // With the bug, it wasn't. 1063 func TestContext2Apply_moduleOnlyProvider(t *testing.T) { 1064 m := testModule(t, "apply-module-only-provider") 1065 p := testProvider("aws") 1066 p.ApplyFn = testApplyFn 1067 p.DiffFn = testDiffFn 1068 pTest := testProvider("test") 1069 pTest.ApplyFn = testApplyFn 1070 pTest.DiffFn = testDiffFn 1071 1072 ctx := testContext2(t, &ContextOpts{ 1073 Module: m, 1074 Providers: map[string]ResourceProviderFactory{ 1075 "aws": testProviderFuncFixed(p), 1076 "test": testProviderFuncFixed(pTest), 1077 }, 1078 }) 1079 1080 if _, err := ctx.Plan(); err != nil { 1081 t.Fatalf("err: %s", err) 1082 } 1083 1084 state, err := ctx.Apply() 1085 if err != nil { 1086 t.Fatalf("err: %s", err) 1087 } 1088 1089 actual := strings.TrimSpace(state.String()) 1090 expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) 1091 if actual != expected { 1092 t.Fatalf("bad: \n%s", actual) 1093 } 1094 } 1095 1096 func TestContext2Apply_moduleProviderAlias(t *testing.T) { 1097 m := testModule(t, "apply-module-provider-alias") 1098 p := testProvider("aws") 1099 p.ApplyFn = testApplyFn 1100 p.DiffFn = testDiffFn 1101 ctx := testContext2(t, &ContextOpts{ 1102 Module: m, 1103 Providers: map[string]ResourceProviderFactory{ 1104 "aws": testProviderFuncFixed(p), 1105 }, 1106 }) 1107 1108 if _, err := ctx.Plan(); err != nil { 1109 t.Fatalf("err: %s", err) 1110 } 1111 1112 state, err := ctx.Apply() 1113 if err != nil { 1114 t.Fatalf("err: %s", err) 1115 } 1116 1117 actual := strings.TrimSpace(state.String()) 1118 expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) 1119 if actual != expected { 1120 t.Fatalf("bad: \n%s", actual) 1121 } 1122 } 1123 1124 func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { 1125 m := testModule(t, "apply-module-provider-alias") 1126 p := testProvider("aws") 1127 p.ApplyFn = testApplyFn 1128 p.DiffFn = testDiffFn 1129 ctx := testContext2(t, &ContextOpts{ 1130 Module: m, 1131 Providers: map[string]ResourceProviderFactory{ 1132 "aws": testProviderFuncFixed(p), 1133 }, 1134 Targets: []string{"no.thing"}, 1135 }) 1136 1137 if _, err := ctx.Plan(); err != nil { 1138 t.Fatalf("err: %s", err) 1139 } 1140 1141 state, err := ctx.Apply() 1142 if err != nil { 1143 t.Fatalf("err: %s", err) 1144 } 1145 1146 actual := strings.TrimSpace(state.String()) 1147 expected := strings.TrimSpace(` 1148 <no state> 1149 `) 1150 if actual != expected { 1151 t.Fatalf("bad: \n%s", actual) 1152 } 1153 } 1154 1155 func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { 1156 m := testModule(t, "apply-module-provider-close-nested") 1157 p := testProvider("aws") 1158 p.ApplyFn = testApplyFn 1159 p.DiffFn = testDiffFn 1160 ctx := testContext2(t, &ContextOpts{ 1161 Module: m, 1162 Providers: map[string]ResourceProviderFactory{ 1163 "aws": testProviderFuncFixed(p), 1164 }, 1165 State: &State{ 1166 Modules: []*ModuleState{ 1167 &ModuleState{ 1168 Path: []string{"root", "child", "subchild"}, 1169 Resources: map[string]*ResourceState{ 1170 "aws_instance.foo": &ResourceState{ 1171 Type: "aws_instance", 1172 Primary: &InstanceState{ 1173 ID: "bar", 1174 }, 1175 }, 1176 }, 1177 }, 1178 }, 1179 }, 1180 Destroy: true, 1181 }) 1182 1183 if _, err := ctx.Plan(); err != nil { 1184 t.Fatalf("err: %s", err) 1185 } 1186 1187 if _, err := ctx.Apply(); err != nil { 1188 t.Fatalf("err: %s", err) 1189 } 1190 } 1191 1192 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 1193 m := testModule(t, "apply-module-var-resource-count") 1194 p := testProvider("aws") 1195 p.ApplyFn = testApplyFn 1196 p.DiffFn = testDiffFn 1197 ctx := testContext2(t, &ContextOpts{ 1198 Module: m, 1199 Providers: map[string]ResourceProviderFactory{ 1200 "aws": testProviderFuncFixed(p), 1201 }, 1202 Variables: map[string]string{ 1203 "count": "2", 1204 }, 1205 Destroy: true, 1206 }) 1207 1208 if _, err := ctx.Plan(); err != nil { 1209 t.Fatalf("err: %s", err) 1210 } 1211 1212 if _, err := ctx.Apply(); err != nil { 1213 t.Fatalf("err: %s", err) 1214 } 1215 1216 ctx = testContext2(t, &ContextOpts{ 1217 Module: m, 1218 Providers: map[string]ResourceProviderFactory{ 1219 "aws": testProviderFuncFixed(p), 1220 }, 1221 Variables: map[string]string{ 1222 "count": "5", 1223 }, 1224 }) 1225 1226 if _, err := ctx.Plan(); err != nil { 1227 t.Fatalf("err: %s", err) 1228 } 1229 1230 if _, err := ctx.Apply(); err != nil { 1231 t.Fatalf("err: %s", err) 1232 } 1233 } 1234 1235 // GH-819 1236 func TestContext2Apply_moduleBool(t *testing.T) { 1237 m := testModule(t, "apply-module-bool") 1238 p := testProvider("aws") 1239 p.ApplyFn = testApplyFn 1240 p.DiffFn = testDiffFn 1241 ctx := testContext2(t, &ContextOpts{ 1242 Module: m, 1243 Providers: map[string]ResourceProviderFactory{ 1244 "aws": testProviderFuncFixed(p), 1245 }, 1246 }) 1247 1248 if _, err := ctx.Plan(); err != nil { 1249 t.Fatalf("err: %s", err) 1250 } 1251 1252 state, err := ctx.Apply() 1253 if err != nil { 1254 t.Fatalf("err: %s", err) 1255 } 1256 1257 actual := strings.TrimSpace(state.String()) 1258 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 1259 if actual != expected { 1260 t.Fatalf("bad: \n%s", actual) 1261 } 1262 } 1263 1264 func TestContext2Apply_multiProvider(t *testing.T) { 1265 m := testModule(t, "apply-multi-provider") 1266 p := testProvider("aws") 1267 p.ApplyFn = testApplyFn 1268 p.DiffFn = testDiffFn 1269 1270 pDO := testProvider("do") 1271 pDO.ApplyFn = testApplyFn 1272 pDO.DiffFn = testDiffFn 1273 1274 ctx := testContext2(t, &ContextOpts{ 1275 Module: m, 1276 Providers: map[string]ResourceProviderFactory{ 1277 "aws": testProviderFuncFixed(p), 1278 "do": testProviderFuncFixed(pDO), 1279 }, 1280 }) 1281 1282 if _, err := ctx.Plan(); err != nil { 1283 t.Fatalf("err: %s", err) 1284 } 1285 1286 state, err := ctx.Apply() 1287 if err != nil { 1288 t.Fatalf("err: %s", err) 1289 } 1290 1291 mod := state.RootModule() 1292 if len(mod.Resources) < 2 { 1293 t.Fatalf("bad: %#v", mod.Resources) 1294 } 1295 1296 actual := strings.TrimSpace(state.String()) 1297 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 1298 if actual != expected { 1299 t.Fatalf("bad: \n%s", actual) 1300 } 1301 } 1302 1303 func TestContext2Apply_multiVar(t *testing.T) { 1304 m := testModule(t, "apply-multi-var") 1305 p := testProvider("aws") 1306 p.ApplyFn = testApplyFn 1307 p.DiffFn = testDiffFn 1308 1309 // First, apply with a count of 3 1310 ctx := testContext2(t, &ContextOpts{ 1311 Module: m, 1312 Providers: map[string]ResourceProviderFactory{ 1313 "aws": testProviderFuncFixed(p), 1314 }, 1315 Variables: map[string]string{ 1316 "count": "3", 1317 }, 1318 }) 1319 1320 if _, err := ctx.Plan(); err != nil { 1321 t.Fatalf("err: %s", err) 1322 } 1323 1324 state, err := ctx.Apply() 1325 if err != nil { 1326 t.Fatalf("err: %s", err) 1327 } 1328 1329 actual := state.RootModule().Outputs["output"] 1330 expected := "bar0,bar1,bar2" 1331 if actual != expected { 1332 t.Fatalf("bad: \n%s", actual) 1333 } 1334 1335 // Apply again, reduce the count to 1 1336 { 1337 ctx := testContext2(t, &ContextOpts{ 1338 Module: m, 1339 State: state, 1340 Providers: map[string]ResourceProviderFactory{ 1341 "aws": testProviderFuncFixed(p), 1342 }, 1343 Variables: map[string]string{ 1344 "count": "1", 1345 }, 1346 }) 1347 1348 if _, err := ctx.Plan(); err != nil { 1349 t.Fatalf("err: %s", err) 1350 } 1351 1352 state, err := ctx.Apply() 1353 if err != nil { 1354 t.Fatalf("err: %s", err) 1355 } 1356 1357 actual := state.RootModule().Outputs["output"] 1358 expected := "bar0" 1359 if actual != expected { 1360 t.Fatalf("bad: \n%s", actual) 1361 } 1362 } 1363 } 1364 1365 func TestContext2Apply_nilDiff(t *testing.T) { 1366 m := testModule(t, "apply-good") 1367 p := testProvider("aws") 1368 p.ApplyFn = testApplyFn 1369 p.DiffFn = testDiffFn 1370 ctx := testContext2(t, &ContextOpts{ 1371 Module: m, 1372 Providers: map[string]ResourceProviderFactory{ 1373 "aws": testProviderFuncFixed(p), 1374 }, 1375 }) 1376 1377 if _, err := ctx.Plan(); err != nil { 1378 t.Fatalf("err: %s", err) 1379 } 1380 1381 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1382 return nil, nil 1383 } 1384 1385 if _, err := ctx.Apply(); err == nil { 1386 t.Fatal("should error") 1387 } 1388 } 1389 1390 func TestContext2Apply_outputOrphan(t *testing.T) { 1391 m := testModule(t, "apply-output-orphan") 1392 p := testProvider("aws") 1393 p.ApplyFn = testApplyFn 1394 p.DiffFn = testDiffFn 1395 1396 state := &State{ 1397 Modules: []*ModuleState{ 1398 &ModuleState{ 1399 Path: rootModulePath, 1400 Outputs: map[string]string{ 1401 "foo": "bar", 1402 "bar": "baz", 1403 }, 1404 }, 1405 }, 1406 } 1407 1408 ctx := testContext2(t, &ContextOpts{ 1409 Module: m, 1410 Providers: map[string]ResourceProviderFactory{ 1411 "aws": testProviderFuncFixed(p), 1412 }, 1413 State: state, 1414 }) 1415 1416 if _, err := ctx.Plan(); err != nil { 1417 t.Fatalf("err: %s", err) 1418 } 1419 1420 state, err := ctx.Apply() 1421 if err != nil { 1422 t.Fatalf("err: %s", err) 1423 } 1424 1425 actual := strings.TrimSpace(state.String()) 1426 expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) 1427 if actual != expected { 1428 t.Fatalf("bad: \n%s", actual) 1429 } 1430 } 1431 1432 func TestContext2Apply_providerComputedVar(t *testing.T) { 1433 m := testModule(t, "apply-provider-computed") 1434 p := testProvider("aws") 1435 p.ApplyFn = testApplyFn 1436 p.DiffFn = testDiffFn 1437 1438 pTest := testProvider("test") 1439 pTest.ApplyFn = testApplyFn 1440 pTest.DiffFn = testDiffFn 1441 1442 ctx := testContext2(t, &ContextOpts{ 1443 Module: m, 1444 Providers: map[string]ResourceProviderFactory{ 1445 "aws": testProviderFuncFixed(p), 1446 "test": testProviderFuncFixed(pTest), 1447 }, 1448 }) 1449 1450 p.ConfigureFn = func(c *ResourceConfig) error { 1451 if c.IsComputed("value") { 1452 return fmt.Errorf("value is computed") 1453 } 1454 1455 v, ok := c.Get("value") 1456 if !ok { 1457 return fmt.Errorf("value is not found") 1458 } 1459 if v != "yes" { 1460 return fmt.Errorf("value is not 'yes': %v", v) 1461 } 1462 1463 return nil 1464 } 1465 1466 if _, err := ctx.Plan(); err != nil { 1467 t.Fatalf("err: %s", err) 1468 } 1469 1470 if _, err := ctx.Apply(); err != nil { 1471 t.Fatalf("err: %s", err) 1472 } 1473 } 1474 1475 func TestContext2Apply_Provisioner_compute(t *testing.T) { 1476 m := testModule(t, "apply-provisioner-compute") 1477 p := testProvider("aws") 1478 pr := testProvisioner() 1479 p.ApplyFn = testApplyFn 1480 p.DiffFn = testDiffFn 1481 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1482 val, ok := c.Config["foo"] 1483 if !ok || val != "computed_dynamical" { 1484 t.Fatalf("bad value for foo: %v %#v", val, c) 1485 } 1486 1487 return nil 1488 } 1489 ctx := testContext2(t, &ContextOpts{ 1490 Module: m, 1491 Providers: map[string]ResourceProviderFactory{ 1492 "aws": testProviderFuncFixed(p), 1493 }, 1494 Provisioners: map[string]ResourceProvisionerFactory{ 1495 "shell": testProvisionerFuncFixed(pr), 1496 }, 1497 Variables: map[string]string{ 1498 "value": "1", 1499 }, 1500 }) 1501 1502 if _, err := ctx.Plan(); err != nil { 1503 t.Fatalf("err: %s", err) 1504 } 1505 1506 state, err := ctx.Apply() 1507 if err != nil { 1508 t.Fatalf("err: %s", err) 1509 } 1510 1511 actual := strings.TrimSpace(state.String()) 1512 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 1513 if actual != expected { 1514 t.Fatalf("bad: \n%s", actual) 1515 } 1516 1517 // Verify apply was invoked 1518 if !pr.ApplyCalled { 1519 t.Fatalf("provisioner not invoked") 1520 } 1521 } 1522 1523 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 1524 m := testModule(t, "apply-provisioner-fail-create") 1525 p := testProvider("aws") 1526 pr := testProvisioner() 1527 p.DiffFn = testDiffFn 1528 1529 p.ApplyFn = func( 1530 info *InstanceInfo, 1531 is *InstanceState, 1532 id *InstanceDiff) (*InstanceState, error) { 1533 is.ID = "foo" 1534 return is, fmt.Errorf("error") 1535 } 1536 1537 ctx := testContext2(t, &ContextOpts{ 1538 Module: m, 1539 Providers: map[string]ResourceProviderFactory{ 1540 "aws": testProviderFuncFixed(p), 1541 }, 1542 Provisioners: map[string]ResourceProvisionerFactory{ 1543 "shell": testProvisionerFuncFixed(pr), 1544 }, 1545 }) 1546 1547 if _, err := ctx.Plan(); err != nil { 1548 t.Fatalf("err: %s", err) 1549 } 1550 1551 state, err := ctx.Apply() 1552 if err == nil { 1553 t.Fatal("should error") 1554 } 1555 1556 actual := strings.TrimSpace(state.String()) 1557 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 1558 if actual != expected { 1559 t.Fatalf("bad: \n%s", actual) 1560 } 1561 } 1562 1563 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 1564 m := testModule(t, "apply-provisioner-fail-create") 1565 p := testProvider("aws") 1566 pr := testProvisioner() 1567 p.DiffFn = testDiffFn 1568 1569 p.ApplyFn = func( 1570 info *InstanceInfo, 1571 is *InstanceState, 1572 id *InstanceDiff) (*InstanceState, error) { 1573 return nil, fmt.Errorf("error") 1574 } 1575 1576 ctx := testContext2(t, &ContextOpts{ 1577 Module: m, 1578 Providers: map[string]ResourceProviderFactory{ 1579 "aws": testProviderFuncFixed(p), 1580 }, 1581 Provisioners: map[string]ResourceProvisionerFactory{ 1582 "shell": testProvisionerFuncFixed(pr), 1583 }, 1584 }) 1585 1586 if _, err := ctx.Plan(); err != nil { 1587 t.Fatalf("err: %s", err) 1588 } 1589 1590 state, err := ctx.Apply() 1591 if err == nil { 1592 t.Fatal("should error") 1593 } 1594 1595 actual := strings.TrimSpace(state.String()) 1596 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 1597 if actual != expected { 1598 t.Fatalf("bad: \n%s", actual) 1599 } 1600 } 1601 1602 func TestContext2Apply_provisionerFail(t *testing.T) { 1603 m := testModule(t, "apply-provisioner-fail") 1604 p := testProvider("aws") 1605 pr := testProvisioner() 1606 p.ApplyFn = testApplyFn 1607 p.DiffFn = testDiffFn 1608 1609 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 1610 return fmt.Errorf("EXPLOSION") 1611 } 1612 1613 ctx := testContext2(t, &ContextOpts{ 1614 Module: m, 1615 Providers: map[string]ResourceProviderFactory{ 1616 "aws": testProviderFuncFixed(p), 1617 }, 1618 Provisioners: map[string]ResourceProvisionerFactory{ 1619 "shell": testProvisionerFuncFixed(pr), 1620 }, 1621 Variables: map[string]string{ 1622 "value": "1", 1623 }, 1624 }) 1625 1626 if _, err := ctx.Plan(); err != nil { 1627 t.Fatalf("err: %s", err) 1628 } 1629 1630 state, err := ctx.Apply() 1631 if err == nil { 1632 t.Fatal("should error") 1633 } 1634 1635 actual := strings.TrimSpace(state.String()) 1636 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 1637 if actual != expected { 1638 t.Fatalf("bad: \n%s", actual) 1639 } 1640 } 1641 1642 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 1643 m := testModule(t, "apply-provisioner-fail-create-before") 1644 p := testProvider("aws") 1645 pr := testProvisioner() 1646 p.ApplyFn = testApplyFn 1647 p.DiffFn = testDiffFn 1648 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 1649 return fmt.Errorf("EXPLOSION") 1650 } 1651 1652 state := &State{ 1653 Modules: []*ModuleState{ 1654 &ModuleState{ 1655 Path: rootModulePath, 1656 Resources: map[string]*ResourceState{ 1657 "aws_instance.bar": &ResourceState{ 1658 Type: "aws_instance", 1659 Primary: &InstanceState{ 1660 ID: "bar", 1661 Attributes: map[string]string{ 1662 "require_new": "abc", 1663 }, 1664 }, 1665 }, 1666 }, 1667 }, 1668 }, 1669 } 1670 ctx := testContext2(t, &ContextOpts{ 1671 Module: m, 1672 Providers: map[string]ResourceProviderFactory{ 1673 "aws": testProviderFuncFixed(p), 1674 }, 1675 Provisioners: map[string]ResourceProvisionerFactory{ 1676 "shell": testProvisionerFuncFixed(pr), 1677 }, 1678 State: state, 1679 }) 1680 1681 if _, err := ctx.Plan(); err != nil { 1682 t.Fatalf("err: %s", err) 1683 } 1684 1685 state, err := ctx.Apply() 1686 if err == nil { 1687 t.Fatal("should error") 1688 } 1689 1690 actual := strings.TrimSpace(state.String()) 1691 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 1692 if actual != expected { 1693 t.Fatalf("bad: \n%s", actual) 1694 } 1695 } 1696 1697 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 1698 m := testModule(t, "apply-error-create-before") 1699 p := testProvider("aws") 1700 state := &State{ 1701 Modules: []*ModuleState{ 1702 &ModuleState{ 1703 Path: rootModulePath, 1704 Resources: map[string]*ResourceState{ 1705 "aws_instance.bar": &ResourceState{ 1706 Type: "aws_instance", 1707 Primary: &InstanceState{ 1708 ID: "bar", 1709 Attributes: map[string]string{ 1710 "require_new": "abc", 1711 }, 1712 }, 1713 }, 1714 }, 1715 }, 1716 }, 1717 } 1718 ctx := testContext2(t, &ContextOpts{ 1719 Module: m, 1720 Providers: map[string]ResourceProviderFactory{ 1721 "aws": testProviderFuncFixed(p), 1722 }, 1723 State: state, 1724 }) 1725 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1726 return nil, fmt.Errorf("error") 1727 } 1728 p.DiffFn = testDiffFn 1729 1730 if _, err := ctx.Plan(); err != nil { 1731 t.Fatalf("err: %s", err) 1732 } 1733 1734 state, err := ctx.Apply() 1735 if err == nil { 1736 t.Fatal("should have error") 1737 } 1738 1739 actual := strings.TrimSpace(state.String()) 1740 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 1741 if actual != expected { 1742 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 1743 } 1744 } 1745 1746 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 1747 m := testModule(t, "apply-error-create-before") 1748 p := testProvider("aws") 1749 state := &State{ 1750 Modules: []*ModuleState{ 1751 &ModuleState{ 1752 Path: rootModulePath, 1753 Resources: map[string]*ResourceState{ 1754 "aws_instance.bar": &ResourceState{ 1755 Type: "aws_instance", 1756 Primary: &InstanceState{ 1757 ID: "bar", 1758 Attributes: map[string]string{ 1759 "require_new": "abc", 1760 }, 1761 }, 1762 }, 1763 }, 1764 }, 1765 }, 1766 } 1767 ctx := testContext2(t, &ContextOpts{ 1768 Module: m, 1769 Providers: map[string]ResourceProviderFactory{ 1770 "aws": testProviderFuncFixed(p), 1771 }, 1772 State: state, 1773 }) 1774 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1775 // Fail the destroy! 1776 if id.Destroy { 1777 return is, fmt.Errorf("error") 1778 } 1779 1780 // Create should work 1781 is = &InstanceState{ 1782 ID: "foo", 1783 } 1784 return is, nil 1785 } 1786 p.DiffFn = testDiffFn 1787 1788 if _, err := ctx.Plan(); err != nil { 1789 t.Fatalf("err: %s", err) 1790 } 1791 1792 state, err := ctx.Apply() 1793 if err == nil { 1794 t.Fatal("should have error") 1795 } 1796 1797 actual := strings.TrimSpace(state.String()) 1798 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 1799 if actual != expected { 1800 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 1801 } 1802 } 1803 1804 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 1805 m := testModule(t, "apply-multi-depose-create-before-destroy") 1806 p := testProvider("aws") 1807 p.DiffFn = testDiffFn 1808 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 1809 state := &State{ 1810 Modules: []*ModuleState{ 1811 &ModuleState{ 1812 Path: rootModulePath, 1813 Resources: map[string]*ResourceState{ 1814 "aws_instance.web": &ResourceState{ 1815 Type: "aws_instance", 1816 Primary: &InstanceState{ID: "foo"}, 1817 }, 1818 }, 1819 }, 1820 }, 1821 } 1822 1823 ctx := testContext2(t, &ContextOpts{ 1824 Module: m, 1825 Providers: ps, 1826 State: state, 1827 }) 1828 createdInstanceId := "bar" 1829 // Create works 1830 createFunc := func(is *InstanceState) (*InstanceState, error) { 1831 return &InstanceState{ID: createdInstanceId}, nil 1832 } 1833 // Destroy starts broken 1834 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 1835 return is, fmt.Errorf("destroy failed") 1836 } 1837 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1838 if id.Destroy { 1839 return destroyFunc(is) 1840 } else { 1841 return createFunc(is) 1842 } 1843 } 1844 1845 if _, err := ctx.Plan(); err != nil { 1846 t.Fatalf("err: %s", err) 1847 } 1848 1849 // Destroy is broken, so even though CBD successfully replaces the instance, 1850 // we'll have to save the Deposed instance to destroy later 1851 state, err := ctx.Apply() 1852 if err == nil { 1853 t.Fatal("should have error") 1854 } 1855 1856 checkStateString(t, state, ` 1857 aws_instance.web: (1 deposed) 1858 ID = bar 1859 Deposed ID 1 = foo 1860 `) 1861 1862 createdInstanceId = "baz" 1863 ctx = testContext2(t, &ContextOpts{ 1864 Module: m, 1865 Providers: ps, 1866 State: state, 1867 }) 1868 1869 if _, err := ctx.Plan(); err != nil { 1870 t.Fatalf("err: %s", err) 1871 } 1872 1873 // We're replacing the primary instance once again. Destroy is _still_ 1874 // broken, so the Deposed list gets longer 1875 state, err = ctx.Apply() 1876 if err == nil { 1877 t.Fatal("should have error") 1878 } 1879 1880 checkStateString(t, state, ` 1881 aws_instance.web: (2 deposed) 1882 ID = baz 1883 Deposed ID 1 = foo 1884 Deposed ID 2 = bar 1885 `) 1886 1887 // Destroy partially fixed! 1888 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 1889 if is.ID == "foo" || is.ID == "baz" { 1890 return nil, nil 1891 } else { 1892 return is, fmt.Errorf("destroy partially failed") 1893 } 1894 } 1895 1896 createdInstanceId = "qux" 1897 if _, err := ctx.Plan(); err != nil { 1898 t.Fatalf("err: %s", err) 1899 } 1900 state, err = ctx.Apply() 1901 // Expect error because 1/2 of Deposed destroys failed 1902 if err == nil { 1903 t.Fatal("should have error") 1904 } 1905 1906 // foo and baz are now gone, bar sticks around 1907 checkStateString(t, state, ` 1908 aws_instance.web: (1 deposed) 1909 ID = qux 1910 Deposed ID 1 = bar 1911 `) 1912 1913 // Destroy working fully! 1914 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 1915 return nil, nil 1916 } 1917 1918 createdInstanceId = "quux" 1919 if _, err := ctx.Plan(); err != nil { 1920 t.Fatalf("err: %s", err) 1921 } 1922 state, err = ctx.Apply() 1923 if err != nil { 1924 t.Fatal("should not have error:", err) 1925 } 1926 1927 // And finally the state is clean 1928 checkStateString(t, state, ` 1929 aws_instance.web: 1930 ID = quux 1931 `) 1932 } 1933 1934 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 1935 m := testModule(t, "apply-provisioner-resource-ref") 1936 p := testProvider("aws") 1937 pr := testProvisioner() 1938 p.ApplyFn = testApplyFn 1939 p.DiffFn = testDiffFn 1940 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1941 val, ok := c.Config["foo"] 1942 if !ok || val != "2" { 1943 t.Fatalf("bad value for foo: %v %#v", val, c) 1944 } 1945 1946 return nil 1947 } 1948 1949 ctx := testContext2(t, &ContextOpts{ 1950 Module: m, 1951 Providers: map[string]ResourceProviderFactory{ 1952 "aws": testProviderFuncFixed(p), 1953 }, 1954 Provisioners: map[string]ResourceProvisionerFactory{ 1955 "shell": testProvisionerFuncFixed(pr), 1956 }, 1957 }) 1958 1959 if _, err := ctx.Plan(); err != nil { 1960 t.Fatalf("err: %s", err) 1961 } 1962 1963 state, err := ctx.Apply() 1964 if err != nil { 1965 t.Fatalf("err: %s", err) 1966 } 1967 1968 actual := strings.TrimSpace(state.String()) 1969 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 1970 if actual != expected { 1971 t.Fatalf("bad: \n%s", actual) 1972 } 1973 1974 // Verify apply was invoked 1975 if !pr.ApplyCalled { 1976 t.Fatalf("provisioner not invoked") 1977 } 1978 } 1979 1980 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 1981 m := testModule(t, "apply-provisioner-self-ref") 1982 p := testProvider("aws") 1983 pr := testProvisioner() 1984 p.ApplyFn = testApplyFn 1985 p.DiffFn = testDiffFn 1986 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1987 val, ok := c.Config["command"] 1988 if !ok || val != "bar" { 1989 t.Fatalf("bad value for command: %v %#v", val, c) 1990 } 1991 1992 return nil 1993 } 1994 1995 ctx := testContext2(t, &ContextOpts{ 1996 Module: m, 1997 Providers: map[string]ResourceProviderFactory{ 1998 "aws": testProviderFuncFixed(p), 1999 }, 2000 Provisioners: map[string]ResourceProvisionerFactory{ 2001 "shell": testProvisionerFuncFixed(pr), 2002 }, 2003 }) 2004 2005 if _, err := ctx.Plan(); err != nil { 2006 t.Fatalf("err: %s", err) 2007 } 2008 2009 state, err := ctx.Apply() 2010 if err != nil { 2011 t.Fatalf("err: %s", err) 2012 } 2013 2014 actual := strings.TrimSpace(state.String()) 2015 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 2016 if actual != expected { 2017 t.Fatalf("bad: \n%s", actual) 2018 } 2019 2020 // Verify apply was invoked 2021 if !pr.ApplyCalled { 2022 t.Fatalf("provisioner not invoked") 2023 } 2024 } 2025 2026 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 2027 var lock sync.Mutex 2028 commands := make([]string, 0, 5) 2029 2030 m := testModule(t, "apply-provisioner-multi-self-ref") 2031 p := testProvider("aws") 2032 pr := testProvisioner() 2033 p.ApplyFn = testApplyFn 2034 p.DiffFn = testDiffFn 2035 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2036 lock.Lock() 2037 defer lock.Unlock() 2038 2039 val, ok := c.Config["command"] 2040 if !ok { 2041 t.Fatalf("bad value for command: %v %#v", val, c) 2042 } 2043 2044 commands = append(commands, val.(string)) 2045 return nil 2046 } 2047 2048 ctx := testContext2(t, &ContextOpts{ 2049 Module: m, 2050 Providers: map[string]ResourceProviderFactory{ 2051 "aws": testProviderFuncFixed(p), 2052 }, 2053 Provisioners: map[string]ResourceProvisionerFactory{ 2054 "shell": testProvisionerFuncFixed(pr), 2055 }, 2056 }) 2057 2058 if _, err := ctx.Plan(); err != nil { 2059 t.Fatalf("err: %s", err) 2060 } 2061 2062 state, err := ctx.Apply() 2063 if err != nil { 2064 t.Fatalf("err: %s", err) 2065 } 2066 2067 actual := strings.TrimSpace(state.String()) 2068 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 2069 if actual != expected { 2070 t.Fatalf("bad: \n%s", actual) 2071 } 2072 2073 // Verify apply was invoked 2074 if !pr.ApplyCalled { 2075 t.Fatalf("provisioner not invoked") 2076 } 2077 2078 // Verify our result 2079 sort.Strings(commands) 2080 expectedCommands := []string{"number 0", "number 1", "number 2"} 2081 if !reflect.DeepEqual(commands, expectedCommands) { 2082 t.Fatalf("bad: %#v", commands) 2083 } 2084 } 2085 2086 // Provisioner should NOT run on a diff, only create 2087 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 2088 m := testModule(t, "apply-provisioner-diff") 2089 p := testProvider("aws") 2090 pr := testProvisioner() 2091 p.ApplyFn = testApplyFn 2092 p.DiffFn = testDiffFn 2093 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2094 return nil 2095 } 2096 ctx := testContext2(t, &ContextOpts{ 2097 Module: m, 2098 Providers: map[string]ResourceProviderFactory{ 2099 "aws": testProviderFuncFixed(p), 2100 }, 2101 Provisioners: map[string]ResourceProvisionerFactory{ 2102 "shell": testProvisionerFuncFixed(pr), 2103 }, 2104 }) 2105 2106 if _, err := ctx.Plan(); err != nil { 2107 t.Fatalf("err: %s", err) 2108 } 2109 2110 state, err := ctx.Apply() 2111 if err != nil { 2112 t.Fatalf("err: %s", err) 2113 } 2114 2115 actual := strings.TrimSpace(state.String()) 2116 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 2117 if actual != expected { 2118 t.Fatalf("bad: \n%s", actual) 2119 } 2120 2121 // Verify apply was invoked 2122 if !pr.ApplyCalled { 2123 t.Fatalf("provisioner not invoked") 2124 } 2125 pr.ApplyCalled = false 2126 2127 // Change the state to force a diff 2128 mod := state.RootModule() 2129 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 2130 2131 // Re-create context with state 2132 ctx = testContext2(t, &ContextOpts{ 2133 Module: m, 2134 Providers: map[string]ResourceProviderFactory{ 2135 "aws": testProviderFuncFixed(p), 2136 }, 2137 Provisioners: map[string]ResourceProvisionerFactory{ 2138 "shell": testProvisionerFuncFixed(pr), 2139 }, 2140 State: state, 2141 }) 2142 2143 if _, err := ctx.Plan(); err != nil { 2144 t.Fatalf("err: %s", err) 2145 } 2146 2147 state2, err := ctx.Apply() 2148 if err != nil { 2149 t.Fatalf("err: %s", err) 2150 } 2151 2152 actual = strings.TrimSpace(state2.String()) 2153 if actual != expected { 2154 t.Fatalf("bad: \n%s", actual) 2155 } 2156 2157 // Verify apply was NOT invoked 2158 if pr.ApplyCalled { 2159 t.Fatalf("provisioner invoked") 2160 } 2161 } 2162 2163 func TestContext2Apply_outputDiffVars(t *testing.T) { 2164 m := testModule(t, "apply-good") 2165 p := testProvider("aws") 2166 s := &State{ 2167 Modules: []*ModuleState{ 2168 &ModuleState{ 2169 Path: rootModulePath, 2170 Resources: map[string]*ResourceState{ 2171 "aws_instance.baz": &ResourceState{ 2172 Type: "aws_instance", 2173 Primary: &InstanceState{ 2174 ID: "bar", 2175 }, 2176 }, 2177 }, 2178 }, 2179 }, 2180 } 2181 ctx := testContext2(t, &ContextOpts{ 2182 Module: m, 2183 Providers: map[string]ResourceProviderFactory{ 2184 "aws": testProviderFuncFixed(p), 2185 }, 2186 State: s, 2187 }) 2188 2189 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2190 for k, ad := range d.Attributes { 2191 if ad.NewComputed { 2192 return nil, fmt.Errorf("%s: computed", k) 2193 } 2194 } 2195 2196 result := s.MergeDiff(d) 2197 result.ID = "foo" 2198 return result, nil 2199 } 2200 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2201 return &InstanceDiff{ 2202 Attributes: map[string]*ResourceAttrDiff{ 2203 "foo": &ResourceAttrDiff{ 2204 NewComputed: true, 2205 Type: DiffAttrOutput, 2206 }, 2207 "bar": &ResourceAttrDiff{ 2208 New: "baz", 2209 }, 2210 }, 2211 }, nil 2212 } 2213 2214 if _, err := ctx.Plan(); err != nil { 2215 t.Fatalf("err: %s", err) 2216 } 2217 if _, err := ctx.Apply(); err != nil { 2218 t.Fatalf("err: %s", err) 2219 } 2220 } 2221 2222 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 2223 m := testModule(t, "apply-provisioner-conninfo") 2224 p := testProvider("aws") 2225 pr := testProvisioner() 2226 2227 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2228 if s.Ephemeral.ConnInfo == nil { 2229 t.Fatalf("ConnInfo not initialized") 2230 } 2231 2232 result, _ := testApplyFn(info, s, d) 2233 result.Ephemeral.ConnInfo = map[string]string{ 2234 "type": "ssh", 2235 "host": "127.0.0.1", 2236 "port": "22", 2237 } 2238 return result, nil 2239 } 2240 p.DiffFn = testDiffFn 2241 2242 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2243 conn := rs.Ephemeral.ConnInfo 2244 if conn["type"] != "telnet" { 2245 t.Fatalf("Bad: %#v", conn) 2246 } 2247 if conn["host"] != "127.0.0.1" { 2248 t.Fatalf("Bad: %#v", conn) 2249 } 2250 if conn["port"] != "2222" { 2251 t.Fatalf("Bad: %#v", conn) 2252 } 2253 if conn["user"] != "superuser" { 2254 t.Fatalf("Bad: %#v", conn) 2255 } 2256 if conn["pass"] != "test" { 2257 t.Fatalf("Bad: %#v", conn) 2258 } 2259 2260 return nil 2261 } 2262 2263 ctx := testContext2(t, &ContextOpts{ 2264 Module: m, 2265 Providers: map[string]ResourceProviderFactory{ 2266 "aws": testProviderFuncFixed(p), 2267 }, 2268 Provisioners: map[string]ResourceProvisionerFactory{ 2269 "shell": testProvisionerFuncFixed(pr), 2270 }, 2271 Variables: map[string]string{ 2272 "value": "1", 2273 "pass": "test", 2274 }, 2275 }) 2276 2277 if _, err := ctx.Plan(); err != nil { 2278 t.Fatalf("err: %s", err) 2279 } 2280 2281 state, err := ctx.Apply() 2282 if err != nil { 2283 t.Fatalf("err: %s", err) 2284 } 2285 2286 actual := strings.TrimSpace(state.String()) 2287 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 2288 if actual != expected { 2289 t.Fatalf("bad: \n%s", actual) 2290 } 2291 2292 // Verify apply was invoked 2293 if !pr.ApplyCalled { 2294 t.Fatalf("provisioner not invoked") 2295 } 2296 } 2297 2298 func TestContext2Apply_destroy(t *testing.T) { 2299 m := testModule(t, "apply-destroy") 2300 h := new(HookRecordApplyOrder) 2301 p := testProvider("aws") 2302 p.ApplyFn = testApplyFn 2303 p.DiffFn = testDiffFn 2304 ctx := testContext2(t, &ContextOpts{ 2305 Module: m, 2306 Hooks: []Hook{h}, 2307 Providers: map[string]ResourceProviderFactory{ 2308 "aws": testProviderFuncFixed(p), 2309 }, 2310 }) 2311 2312 // First plan and apply a create operation 2313 if _, err := ctx.Plan(); err != nil { 2314 t.Fatalf("err: %s", err) 2315 } 2316 2317 state, err := ctx.Apply() 2318 if err != nil { 2319 t.Fatalf("err: %s", err) 2320 } 2321 2322 // Next, plan and apply a destroy operation 2323 h.Active = true 2324 ctx = testContext2(t, &ContextOpts{ 2325 Destroy: true, 2326 State: state, 2327 Module: m, 2328 Hooks: []Hook{h}, 2329 Providers: map[string]ResourceProviderFactory{ 2330 "aws": testProviderFuncFixed(p), 2331 }, 2332 }) 2333 2334 if _, err := ctx.Plan(); err != nil { 2335 t.Fatalf("err: %s", err) 2336 } 2337 2338 state, err = ctx.Apply() 2339 if err != nil { 2340 t.Fatalf("err: %s", err) 2341 } 2342 2343 // Test that things were destroyed 2344 actual := strings.TrimSpace(state.String()) 2345 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 2346 if actual != expected { 2347 t.Fatalf("bad: \n%s", actual) 2348 } 2349 2350 // Test that things were destroyed _in the right order_ 2351 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 2352 actual2 := h.IDs 2353 if !reflect.DeepEqual(actual2, expected2) { 2354 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 2355 } 2356 } 2357 2358 func TestContext2Apply_destroyNestedModule(t *testing.T) { 2359 m := testModule(t, "apply-destroy-nested-module") 2360 p := testProvider("aws") 2361 p.ApplyFn = testApplyFn 2362 p.DiffFn = testDiffFn 2363 2364 s := &State{ 2365 Modules: []*ModuleState{ 2366 &ModuleState{ 2367 Path: []string{"root", "child", "subchild"}, 2368 Resources: map[string]*ResourceState{ 2369 "aws_instance.bar": &ResourceState{ 2370 Type: "aws_instance", 2371 Primary: &InstanceState{ 2372 ID: "bar", 2373 }, 2374 }, 2375 }, 2376 }, 2377 }, 2378 } 2379 2380 ctx := testContext2(t, &ContextOpts{ 2381 Module: m, 2382 Providers: map[string]ResourceProviderFactory{ 2383 "aws": testProviderFuncFixed(p), 2384 }, 2385 State: s, 2386 }) 2387 2388 // First plan and apply a create operation 2389 if _, err := ctx.Plan(); err != nil { 2390 t.Fatalf("err: %s", err) 2391 } 2392 2393 state, err := ctx.Apply() 2394 if err != nil { 2395 t.Fatalf("err: %s", err) 2396 } 2397 2398 // Test that things were destroyed 2399 actual := strings.TrimSpace(state.String()) 2400 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 2401 if actual != expected { 2402 t.Fatalf("bad: \n%s", actual) 2403 } 2404 } 2405 2406 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 2407 m := testModule(t, "apply-destroy-deeply-nested-module") 2408 p := testProvider("aws") 2409 p.ApplyFn = testApplyFn 2410 p.DiffFn = testDiffFn 2411 2412 s := &State{ 2413 Modules: []*ModuleState{ 2414 &ModuleState{ 2415 Path: []string{"root", "child", "subchild", "subsubchild"}, 2416 Resources: map[string]*ResourceState{ 2417 "aws_instance.bar": &ResourceState{ 2418 Type: "aws_instance", 2419 Primary: &InstanceState{ 2420 ID: "bar", 2421 }, 2422 }, 2423 }, 2424 }, 2425 }, 2426 } 2427 2428 ctx := testContext2(t, &ContextOpts{ 2429 Module: m, 2430 Providers: map[string]ResourceProviderFactory{ 2431 "aws": testProviderFuncFixed(p), 2432 }, 2433 State: s, 2434 }) 2435 2436 // First plan and apply a create operation 2437 if _, err := ctx.Plan(); err != nil { 2438 t.Fatalf("err: %s", err) 2439 } 2440 2441 state, err := ctx.Apply() 2442 if err != nil { 2443 t.Fatalf("err: %s", err) 2444 } 2445 2446 // Test that things were destroyed 2447 actual := strings.TrimSpace(state.String()) 2448 expected := strings.TrimSpace(` 2449 module.child.subchild.subsubchild: 2450 <no state> 2451 `) 2452 if actual != expected { 2453 t.Fatalf("bad: \n%s", actual) 2454 } 2455 } 2456 2457 func TestContext2Apply_destroyOutputs(t *testing.T) { 2458 m := testModule(t, "apply-destroy-outputs") 2459 h := new(HookRecordApplyOrder) 2460 p := testProvider("aws") 2461 p.ApplyFn = testApplyFn 2462 p.DiffFn = testDiffFn 2463 ctx := testContext2(t, &ContextOpts{ 2464 Module: m, 2465 Hooks: []Hook{h}, 2466 Providers: map[string]ResourceProviderFactory{ 2467 "aws": testProviderFuncFixed(p), 2468 }, 2469 }) 2470 2471 // First plan and apply a create operation 2472 if _, err := ctx.Plan(); err != nil { 2473 t.Fatalf("err: %s", err) 2474 } 2475 2476 state, err := ctx.Apply() 2477 2478 if err != nil { 2479 t.Fatalf("err: %s", err) 2480 } 2481 2482 // Next, plan and apply a destroy operation 2483 h.Active = true 2484 ctx = testContext2(t, &ContextOpts{ 2485 Destroy: true, 2486 State: state, 2487 Module: m, 2488 Hooks: []Hook{h}, 2489 Providers: map[string]ResourceProviderFactory{ 2490 "aws": testProviderFuncFixed(p), 2491 }, 2492 }) 2493 2494 if _, err := ctx.Plan(); err != nil { 2495 t.Fatalf("err: %s", err) 2496 } 2497 2498 state, err = ctx.Apply() 2499 if err != nil { 2500 t.Fatalf("err: %s", err) 2501 } 2502 2503 mod := state.RootModule() 2504 if len(mod.Resources) > 0 { 2505 t.Fatalf("bad: %#v", mod) 2506 } 2507 } 2508 2509 func TestContext2Apply_destroyOrphan(t *testing.T) { 2510 m := testModule(t, "apply-error") 2511 p := testProvider("aws") 2512 s := &State{ 2513 Modules: []*ModuleState{ 2514 &ModuleState{ 2515 Path: rootModulePath, 2516 Resources: map[string]*ResourceState{ 2517 "aws_instance.baz": &ResourceState{ 2518 Type: "aws_instance", 2519 Primary: &InstanceState{ 2520 ID: "bar", 2521 }, 2522 }, 2523 }, 2524 }, 2525 }, 2526 } 2527 ctx := testContext2(t, &ContextOpts{ 2528 Module: m, 2529 Providers: map[string]ResourceProviderFactory{ 2530 "aws": testProviderFuncFixed(p), 2531 }, 2532 State: s, 2533 }) 2534 2535 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2536 if d.Destroy { 2537 return nil, nil 2538 } 2539 2540 result := s.MergeDiff(d) 2541 result.ID = "foo" 2542 return result, nil 2543 } 2544 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2545 return &InstanceDiff{ 2546 Attributes: map[string]*ResourceAttrDiff{ 2547 "num": &ResourceAttrDiff{ 2548 New: "bar", 2549 }, 2550 }, 2551 }, nil 2552 } 2553 2554 if _, err := ctx.Plan(); err != nil { 2555 t.Fatalf("err: %s", err) 2556 } 2557 2558 state, err := ctx.Apply() 2559 if err != nil { 2560 t.Fatalf("err: %s", err) 2561 } 2562 2563 mod := state.RootModule() 2564 if _, ok := mod.Resources["aws_instance.baz"]; ok { 2565 t.Fatalf("bad: %#v", mod.Resources) 2566 } 2567 } 2568 2569 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 2570 m := testModule(t, "apply-destroy-provisioner") 2571 p := testProvider("aws") 2572 pr := testProvisioner() 2573 p.ApplyFn = testApplyFn 2574 p.DiffFn = testDiffFn 2575 2576 called := false 2577 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2578 called = true 2579 return nil 2580 } 2581 2582 s := &State{ 2583 Modules: []*ModuleState{ 2584 &ModuleState{ 2585 Path: rootModulePath, 2586 Resources: map[string]*ResourceState{ 2587 "aws_instance.foo": &ResourceState{ 2588 Type: "aws_instance", 2589 Tainted: []*InstanceState{ 2590 &InstanceState{ 2591 ID: "bar", 2592 Attributes: map[string]string{ 2593 "id": "bar", 2594 }, 2595 }, 2596 }, 2597 }, 2598 }, 2599 }, 2600 }, 2601 } 2602 2603 ctx := testContext2(t, &ContextOpts{ 2604 Module: m, 2605 Providers: map[string]ResourceProviderFactory{ 2606 "aws": testProviderFuncFixed(p), 2607 }, 2608 Provisioners: map[string]ResourceProvisionerFactory{ 2609 "shell": testProvisionerFuncFixed(pr), 2610 }, 2611 State: s, 2612 Destroy: true, 2613 }) 2614 2615 if _, err := ctx.Plan(); err != nil { 2616 t.Fatalf("err: %s", err) 2617 } 2618 2619 state, err := ctx.Apply() 2620 if err != nil { 2621 t.Fatalf("err: %s", err) 2622 } 2623 2624 if called { 2625 t.Fatal("provisioner should not be called") 2626 } 2627 2628 actual := strings.TrimSpace(state.String()) 2629 expected := strings.TrimSpace("<no state>") 2630 if actual != expected { 2631 t.Fatalf("bad: \n%s", actual) 2632 } 2633 } 2634 2635 func TestContext2Apply_error(t *testing.T) { 2636 errored := false 2637 2638 m := testModule(t, "apply-error") 2639 p := testProvider("aws") 2640 ctx := testContext2(t, &ContextOpts{ 2641 Module: m, 2642 Providers: map[string]ResourceProviderFactory{ 2643 "aws": testProviderFuncFixed(p), 2644 }, 2645 }) 2646 2647 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 2648 if errored { 2649 state := &InstanceState{ 2650 ID: "bar", 2651 } 2652 return state, fmt.Errorf("error") 2653 } 2654 errored = true 2655 2656 return &InstanceState{ 2657 ID: "foo", 2658 Attributes: map[string]string{ 2659 "num": "2", 2660 }, 2661 }, nil 2662 } 2663 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2664 return &InstanceDiff{ 2665 Attributes: map[string]*ResourceAttrDiff{ 2666 "num": &ResourceAttrDiff{ 2667 New: "bar", 2668 }, 2669 }, 2670 }, nil 2671 } 2672 2673 if _, err := ctx.Plan(); err != nil { 2674 t.Fatalf("err: %s", err) 2675 } 2676 2677 state, err := ctx.Apply() 2678 if err == nil { 2679 t.Fatal("should have error") 2680 } 2681 2682 actual := strings.TrimSpace(state.String()) 2683 expected := strings.TrimSpace(testTerraformApplyErrorStr) 2684 if actual != expected { 2685 t.Fatalf("bad: \n%s", actual) 2686 } 2687 } 2688 2689 func TestContext2Apply_errorPartial(t *testing.T) { 2690 errored := false 2691 2692 m := testModule(t, "apply-error") 2693 p := testProvider("aws") 2694 s := &State{ 2695 Modules: []*ModuleState{ 2696 &ModuleState{ 2697 Path: rootModulePath, 2698 Resources: map[string]*ResourceState{ 2699 "aws_instance.bar": &ResourceState{ 2700 Type: "aws_instance", 2701 Primary: &InstanceState{ 2702 ID: "bar", 2703 }, 2704 }, 2705 }, 2706 }, 2707 }, 2708 } 2709 ctx := testContext2(t, &ContextOpts{ 2710 Module: m, 2711 Providers: map[string]ResourceProviderFactory{ 2712 "aws": testProviderFuncFixed(p), 2713 }, 2714 State: s, 2715 }) 2716 2717 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2718 if errored { 2719 return s, fmt.Errorf("error") 2720 } 2721 errored = true 2722 2723 return &InstanceState{ 2724 ID: "foo", 2725 Attributes: map[string]string{ 2726 "num": "2", 2727 }, 2728 }, nil 2729 } 2730 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2731 return &InstanceDiff{ 2732 Attributes: map[string]*ResourceAttrDiff{ 2733 "num": &ResourceAttrDiff{ 2734 New: "bar", 2735 }, 2736 }, 2737 }, nil 2738 } 2739 2740 if _, err := ctx.Plan(); err != nil { 2741 t.Fatalf("err: %s", err) 2742 } 2743 2744 state, err := ctx.Apply() 2745 if err == nil { 2746 t.Fatal("should have error") 2747 } 2748 2749 mod := state.RootModule() 2750 if len(mod.Resources) != 2 { 2751 t.Fatalf("bad: %#v", mod.Resources) 2752 } 2753 2754 actual := strings.TrimSpace(state.String()) 2755 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 2756 if actual != expected { 2757 t.Fatalf("bad: \n%s", actual) 2758 } 2759 } 2760 2761 func TestContext2Apply_hook(t *testing.T) { 2762 m := testModule(t, "apply-good") 2763 h := new(MockHook) 2764 p := testProvider("aws") 2765 p.ApplyFn = testApplyFn 2766 p.DiffFn = testDiffFn 2767 ctx := testContext2(t, &ContextOpts{ 2768 Module: m, 2769 Hooks: []Hook{h}, 2770 Providers: map[string]ResourceProviderFactory{ 2771 "aws": testProviderFuncFixed(p), 2772 }, 2773 }) 2774 2775 if _, err := ctx.Plan(); err != nil { 2776 t.Fatalf("err: %s", err) 2777 } 2778 2779 if _, err := ctx.Apply(); err != nil { 2780 t.Fatalf("err: %s", err) 2781 } 2782 2783 if !h.PreApplyCalled { 2784 t.Fatal("should be called") 2785 } 2786 if !h.PostApplyCalled { 2787 t.Fatal("should be called") 2788 } 2789 if !h.PostStateUpdateCalled { 2790 t.Fatalf("should call post state update") 2791 } 2792 } 2793 2794 func TestContext2Apply_hookOrphan(t *testing.T) { 2795 m := testModule(t, "apply-blank") 2796 h := new(MockHook) 2797 p := testProvider("aws") 2798 p.ApplyFn = testApplyFn 2799 p.DiffFn = testDiffFn 2800 2801 state := &State{ 2802 Modules: []*ModuleState{ 2803 &ModuleState{ 2804 Path: rootModulePath, 2805 Resources: map[string]*ResourceState{ 2806 "aws_instance.bar": &ResourceState{ 2807 Type: "aws_instance", 2808 Primary: &InstanceState{ 2809 ID: "bar", 2810 }, 2811 }, 2812 }, 2813 }, 2814 }, 2815 } 2816 2817 ctx := testContext2(t, &ContextOpts{ 2818 Module: m, 2819 State: state, 2820 Hooks: []Hook{h}, 2821 Providers: map[string]ResourceProviderFactory{ 2822 "aws": testProviderFuncFixed(p), 2823 }, 2824 }) 2825 2826 if _, err := ctx.Plan(); err != nil { 2827 t.Fatalf("err: %s", err) 2828 } 2829 2830 if _, err := ctx.Apply(); err != nil { 2831 t.Fatalf("err: %s", err) 2832 } 2833 2834 if !h.PreApplyCalled { 2835 t.Fatal("should be called") 2836 } 2837 if !h.PostApplyCalled { 2838 t.Fatal("should be called") 2839 } 2840 if !h.PostStateUpdateCalled { 2841 t.Fatalf("should call post state update") 2842 } 2843 } 2844 2845 func TestContext2Apply_idAttr(t *testing.T) { 2846 m := testModule(t, "apply-idattr") 2847 p := testProvider("aws") 2848 ctx := testContext2(t, &ContextOpts{ 2849 Module: m, 2850 Providers: map[string]ResourceProviderFactory{ 2851 "aws": testProviderFuncFixed(p), 2852 }, 2853 }) 2854 2855 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2856 result := s.MergeDiff(d) 2857 result.ID = "foo" 2858 result.Attributes = map[string]string{ 2859 "id": "bar", 2860 } 2861 2862 return result, nil 2863 } 2864 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2865 return &InstanceDiff{ 2866 Attributes: map[string]*ResourceAttrDiff{ 2867 "num": &ResourceAttrDiff{ 2868 New: "bar", 2869 }, 2870 }, 2871 }, nil 2872 } 2873 2874 if _, err := ctx.Plan(); err != nil { 2875 t.Fatalf("err: %s", err) 2876 } 2877 2878 state, err := ctx.Apply() 2879 if err != nil { 2880 t.Fatalf("err: %s", err) 2881 } 2882 2883 mod := state.RootModule() 2884 rs, ok := mod.Resources["aws_instance.foo"] 2885 if !ok { 2886 t.Fatal("not in state") 2887 } 2888 if rs.Primary.ID != "foo" { 2889 t.Fatalf("bad: %#v", rs.Primary.ID) 2890 } 2891 if rs.Primary.Attributes["id"] != "foo" { 2892 t.Fatalf("bad: %#v", rs.Primary.Attributes) 2893 } 2894 } 2895 2896 func TestContext2Apply_output(t *testing.T) { 2897 m := testModule(t, "apply-output") 2898 p := testProvider("aws") 2899 p.ApplyFn = testApplyFn 2900 p.DiffFn = testDiffFn 2901 ctx := testContext2(t, &ContextOpts{ 2902 Module: m, 2903 Providers: map[string]ResourceProviderFactory{ 2904 "aws": testProviderFuncFixed(p), 2905 }, 2906 }) 2907 2908 if _, err := ctx.Plan(); err != nil { 2909 t.Fatalf("err: %s", err) 2910 } 2911 2912 state, err := ctx.Apply() 2913 if err != nil { 2914 t.Fatalf("err: %s", err) 2915 } 2916 2917 actual := strings.TrimSpace(state.String()) 2918 expected := strings.TrimSpace(testTerraformApplyOutputStr) 2919 if actual != expected { 2920 t.Fatalf("bad: \n%s", actual) 2921 } 2922 } 2923 2924 func TestContext2Apply_outputInvalid(t *testing.T) { 2925 m := testModule(t, "apply-output-invalid") 2926 p := testProvider("aws") 2927 p.ApplyFn = testApplyFn 2928 p.DiffFn = testDiffFn 2929 ctx := testContext2(t, &ContextOpts{ 2930 Module: m, 2931 Providers: map[string]ResourceProviderFactory{ 2932 "aws": testProviderFuncFixed(p), 2933 }, 2934 }) 2935 2936 _, err := ctx.Plan() 2937 if err == nil { 2938 t.Fatalf("err: %s", err) 2939 } 2940 if !strings.Contains(err.Error(), "is not a string") { 2941 t.Fatalf("err: %s", err) 2942 } 2943 } 2944 2945 func TestContext2Apply_outputAdd(t *testing.T) { 2946 m1 := testModule(t, "apply-output-add-before") 2947 p1 := testProvider("aws") 2948 p1.ApplyFn = testApplyFn 2949 p1.DiffFn = testDiffFn 2950 ctx1 := testContext2(t, &ContextOpts{ 2951 Module: m1, 2952 Providers: map[string]ResourceProviderFactory{ 2953 "aws": testProviderFuncFixed(p1), 2954 }, 2955 }) 2956 2957 if _, err := ctx1.Plan(); err != nil { 2958 t.Fatalf("err: %s", err) 2959 } 2960 2961 state1, err := ctx1.Apply() 2962 if err != nil { 2963 t.Fatalf("err: %s", err) 2964 } 2965 2966 m2 := testModule(t, "apply-output-add-after") 2967 p2 := testProvider("aws") 2968 p2.ApplyFn = testApplyFn 2969 p2.DiffFn = testDiffFn 2970 ctx2 := testContext2(t, &ContextOpts{ 2971 Module: m2, 2972 Providers: map[string]ResourceProviderFactory{ 2973 "aws": testProviderFuncFixed(p2), 2974 }, 2975 State: state1, 2976 }) 2977 2978 if _, err := ctx2.Plan(); err != nil { 2979 t.Fatalf("err: %s", err) 2980 } 2981 2982 state2, err := ctx2.Apply() 2983 if err != nil { 2984 t.Fatalf("err: %s", err) 2985 } 2986 2987 actual := strings.TrimSpace(state2.String()) 2988 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 2989 if actual != expected { 2990 t.Fatalf("bad: \n%s", actual) 2991 } 2992 } 2993 2994 func TestContext2Apply_outputList(t *testing.T) { 2995 m := testModule(t, "apply-output-list") 2996 p := testProvider("aws") 2997 p.ApplyFn = testApplyFn 2998 p.DiffFn = testDiffFn 2999 ctx := testContext2(t, &ContextOpts{ 3000 Module: m, 3001 Providers: map[string]ResourceProviderFactory{ 3002 "aws": testProviderFuncFixed(p), 3003 }, 3004 }) 3005 3006 if _, err := ctx.Plan(); err != nil { 3007 t.Fatalf("err: %s", err) 3008 } 3009 3010 state, err := ctx.Apply() 3011 if err != nil { 3012 t.Fatalf("err: %s", err) 3013 } 3014 3015 actual := strings.TrimSpace(state.String()) 3016 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 3017 if actual != expected { 3018 t.Fatalf("bad: \n%s", actual) 3019 } 3020 } 3021 3022 func TestContext2Apply_outputMulti(t *testing.T) { 3023 m := testModule(t, "apply-output-multi") 3024 p := testProvider("aws") 3025 p.ApplyFn = testApplyFn 3026 p.DiffFn = testDiffFn 3027 ctx := testContext2(t, &ContextOpts{ 3028 Module: m, 3029 Providers: map[string]ResourceProviderFactory{ 3030 "aws": testProviderFuncFixed(p), 3031 }, 3032 }) 3033 3034 if _, err := ctx.Plan(); err != nil { 3035 t.Fatalf("err: %s", err) 3036 } 3037 3038 state, err := ctx.Apply() 3039 if err != nil { 3040 t.Fatalf("err: %s", err) 3041 } 3042 3043 actual := strings.TrimSpace(state.String()) 3044 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 3045 if actual != expected { 3046 t.Fatalf("bad: \n%s", actual) 3047 } 3048 } 3049 3050 func TestContext2Apply_outputMultiIndex(t *testing.T) { 3051 m := testModule(t, "apply-output-multi-index") 3052 p := testProvider("aws") 3053 p.ApplyFn = testApplyFn 3054 p.DiffFn = testDiffFn 3055 ctx := testContext2(t, &ContextOpts{ 3056 Module: m, 3057 Providers: map[string]ResourceProviderFactory{ 3058 "aws": testProviderFuncFixed(p), 3059 }, 3060 }) 3061 3062 if _, err := ctx.Plan(); err != nil { 3063 t.Fatalf("err: %s", err) 3064 } 3065 3066 state, err := ctx.Apply() 3067 if err != nil { 3068 t.Fatalf("err: %s", err) 3069 } 3070 3071 actual := strings.TrimSpace(state.String()) 3072 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 3073 if actual != expected { 3074 t.Fatalf("bad: \n%s", actual) 3075 } 3076 } 3077 3078 func TestContext2Apply_taint(t *testing.T) { 3079 m := testModule(t, "apply-taint") 3080 p := testProvider("aws") 3081 3082 // destroyCount tests against regression of 3083 // https://github.com/hashicorp/terraform/issues/1056 3084 var destroyCount = int32(0) 3085 var once sync.Once 3086 simulateProviderDelay := func() { 3087 time.Sleep(10 * time.Millisecond) 3088 } 3089 3090 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3091 once.Do(simulateProviderDelay) 3092 if d.Destroy { 3093 atomic.AddInt32(&destroyCount, 1) 3094 } 3095 return testApplyFn(info, s, d) 3096 } 3097 p.DiffFn = testDiffFn 3098 s := &State{ 3099 Modules: []*ModuleState{ 3100 &ModuleState{ 3101 Path: rootModulePath, 3102 Resources: map[string]*ResourceState{ 3103 "aws_instance.bar": &ResourceState{ 3104 Type: "aws_instance", 3105 Tainted: []*InstanceState{ 3106 &InstanceState{ 3107 ID: "baz", 3108 Attributes: map[string]string{ 3109 "num": "2", 3110 "type": "aws_instance", 3111 }, 3112 }, 3113 }, 3114 }, 3115 }, 3116 }, 3117 }, 3118 } 3119 ctx := testContext2(t, &ContextOpts{ 3120 Module: m, 3121 Providers: map[string]ResourceProviderFactory{ 3122 "aws": testProviderFuncFixed(p), 3123 }, 3124 State: s, 3125 }) 3126 3127 if _, err := ctx.Plan(); err != nil { 3128 t.Fatalf("err: %s", err) 3129 } 3130 3131 state, err := ctx.Apply() 3132 if err != nil { 3133 t.Fatalf("err: %s", err) 3134 } 3135 3136 actual := strings.TrimSpace(state.String()) 3137 expected := strings.TrimSpace(testTerraformApplyTaintStr) 3138 if actual != expected { 3139 t.Fatalf("bad:\n%s", actual) 3140 } 3141 3142 if destroyCount != 1 { 3143 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 3144 } 3145 } 3146 3147 func TestContext2Apply_taintDep(t *testing.T) { 3148 m := testModule(t, "apply-taint-dep") 3149 p := testProvider("aws") 3150 p.ApplyFn = testApplyFn 3151 p.DiffFn = testDiffFn 3152 s := &State{ 3153 Modules: []*ModuleState{ 3154 &ModuleState{ 3155 Path: rootModulePath, 3156 Resources: map[string]*ResourceState{ 3157 "aws_instance.foo": &ResourceState{ 3158 Type: "aws_instance", 3159 Tainted: []*InstanceState{ 3160 &InstanceState{ 3161 ID: "baz", 3162 Attributes: map[string]string{ 3163 "num": "2", 3164 "type": "aws_instance", 3165 }, 3166 }, 3167 }, 3168 }, 3169 "aws_instance.bar": &ResourceState{ 3170 Type: "aws_instance", 3171 Primary: &InstanceState{ 3172 ID: "bar", 3173 Attributes: map[string]string{ 3174 "foo": "baz", 3175 "num": "2", 3176 "type": "aws_instance", 3177 }, 3178 }, 3179 }, 3180 }, 3181 }, 3182 }, 3183 } 3184 ctx := testContext2(t, &ContextOpts{ 3185 Module: m, 3186 Providers: map[string]ResourceProviderFactory{ 3187 "aws": testProviderFuncFixed(p), 3188 }, 3189 State: s, 3190 }) 3191 3192 if p, err := ctx.Plan(); err != nil { 3193 t.Fatalf("err: %s", err) 3194 } else { 3195 t.Logf("plan: %s", p) 3196 } 3197 3198 state, err := ctx.Apply() 3199 if err != nil { 3200 t.Fatalf("err: %s", err) 3201 } 3202 3203 actual := strings.TrimSpace(state.String()) 3204 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 3205 if actual != expected { 3206 t.Fatalf("bad:\n%s", actual) 3207 } 3208 } 3209 3210 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 3211 m := testModule(t, "apply-taint-dep-requires-new") 3212 p := testProvider("aws") 3213 p.ApplyFn = testApplyFn 3214 p.DiffFn = testDiffFn 3215 s := &State{ 3216 Modules: []*ModuleState{ 3217 &ModuleState{ 3218 Path: rootModulePath, 3219 Resources: map[string]*ResourceState{ 3220 "aws_instance.foo": &ResourceState{ 3221 Type: "aws_instance", 3222 Tainted: []*InstanceState{ 3223 &InstanceState{ 3224 ID: "baz", 3225 Attributes: map[string]string{ 3226 "num": "2", 3227 "type": "aws_instance", 3228 }, 3229 }, 3230 }, 3231 }, 3232 "aws_instance.bar": &ResourceState{ 3233 Type: "aws_instance", 3234 Primary: &InstanceState{ 3235 ID: "bar", 3236 Attributes: map[string]string{ 3237 "foo": "baz", 3238 "num": "2", 3239 "type": "aws_instance", 3240 }, 3241 }, 3242 }, 3243 }, 3244 }, 3245 }, 3246 } 3247 ctx := testContext2(t, &ContextOpts{ 3248 Module: m, 3249 Providers: map[string]ResourceProviderFactory{ 3250 "aws": testProviderFuncFixed(p), 3251 }, 3252 State: s, 3253 }) 3254 3255 if p, err := ctx.Plan(); err != nil { 3256 t.Fatalf("err: %s", err) 3257 } else { 3258 t.Logf("plan: %s", p) 3259 } 3260 3261 state, err := ctx.Apply() 3262 if err != nil { 3263 t.Fatalf("err: %s", err) 3264 } 3265 3266 actual := strings.TrimSpace(state.String()) 3267 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 3268 if actual != expected { 3269 t.Fatalf("bad:\n%s", actual) 3270 } 3271 } 3272 3273 func TestContext2Apply_targeted(t *testing.T) { 3274 m := testModule(t, "apply-targeted") 3275 p := testProvider("aws") 3276 p.ApplyFn = testApplyFn 3277 p.DiffFn = testDiffFn 3278 ctx := testContext2(t, &ContextOpts{ 3279 Module: m, 3280 Providers: map[string]ResourceProviderFactory{ 3281 "aws": testProviderFuncFixed(p), 3282 }, 3283 Targets: []string{"aws_instance.foo"}, 3284 }) 3285 3286 if _, err := ctx.Plan(); err != nil { 3287 t.Fatalf("err: %s", err) 3288 } 3289 3290 state, err := ctx.Apply() 3291 if err != nil { 3292 t.Fatalf("err: %s", err) 3293 } 3294 3295 mod := state.RootModule() 3296 if len(mod.Resources) != 1 { 3297 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3298 } 3299 3300 checkStateString(t, state, ` 3301 aws_instance.foo: 3302 ID = foo 3303 num = 2 3304 type = aws_instance 3305 `) 3306 } 3307 3308 func TestContext2Apply_targetedCount(t *testing.T) { 3309 m := testModule(t, "apply-targeted-count") 3310 p := testProvider("aws") 3311 p.ApplyFn = testApplyFn 3312 p.DiffFn = testDiffFn 3313 ctx := testContext2(t, &ContextOpts{ 3314 Module: m, 3315 Providers: map[string]ResourceProviderFactory{ 3316 "aws": testProviderFuncFixed(p), 3317 }, 3318 Targets: []string{"aws_instance.foo"}, 3319 }) 3320 3321 if _, err := ctx.Plan(); err != nil { 3322 t.Fatalf("err: %s", err) 3323 } 3324 3325 state, err := ctx.Apply() 3326 if err != nil { 3327 t.Fatalf("err: %s", err) 3328 } 3329 3330 checkStateString(t, state, ` 3331 aws_instance.foo.0: 3332 ID = foo 3333 aws_instance.foo.1: 3334 ID = foo 3335 aws_instance.foo.2: 3336 ID = foo 3337 `) 3338 } 3339 3340 func TestContext2Apply_targetedCountIndex(t *testing.T) { 3341 m := testModule(t, "apply-targeted-count") 3342 p := testProvider("aws") 3343 p.ApplyFn = testApplyFn 3344 p.DiffFn = testDiffFn 3345 ctx := testContext2(t, &ContextOpts{ 3346 Module: m, 3347 Providers: map[string]ResourceProviderFactory{ 3348 "aws": testProviderFuncFixed(p), 3349 }, 3350 Targets: []string{"aws_instance.foo[1]"}, 3351 }) 3352 3353 if _, err := ctx.Plan(); err != nil { 3354 t.Fatalf("err: %s", err) 3355 } 3356 3357 state, err := ctx.Apply() 3358 if err != nil { 3359 t.Fatalf("err: %s", err) 3360 } 3361 3362 checkStateString(t, state, ` 3363 aws_instance.foo.1: 3364 ID = foo 3365 `) 3366 } 3367 3368 func TestContext2Apply_targetedDestroy(t *testing.T) { 3369 m := testModule(t, "apply-targeted") 3370 p := testProvider("aws") 3371 p.ApplyFn = testApplyFn 3372 p.DiffFn = testDiffFn 3373 ctx := testContext2(t, &ContextOpts{ 3374 Module: m, 3375 Providers: map[string]ResourceProviderFactory{ 3376 "aws": testProviderFuncFixed(p), 3377 }, 3378 State: &State{ 3379 Modules: []*ModuleState{ 3380 &ModuleState{ 3381 Path: rootModulePath, 3382 Resources: map[string]*ResourceState{ 3383 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3384 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3385 }, 3386 }, 3387 }, 3388 }, 3389 Targets: []string{"aws_instance.foo"}, 3390 Destroy: true, 3391 }) 3392 3393 if _, err := ctx.Plan(); err != nil { 3394 t.Fatalf("err: %s", err) 3395 } 3396 3397 state, err := ctx.Apply() 3398 if err != nil { 3399 t.Fatalf("err: %s", err) 3400 } 3401 3402 mod := state.RootModule() 3403 if len(mod.Resources) != 1 { 3404 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3405 } 3406 3407 checkStateString(t, state, ` 3408 aws_instance.bar: 3409 ID = i-abc123 3410 `) 3411 } 3412 3413 // https://github.com/hashicorp/terraform/issues/4462 3414 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 3415 m := testModule(t, "apply-targeted-module") 3416 p := testProvider("aws") 3417 p.ApplyFn = testApplyFn 3418 p.DiffFn = testDiffFn 3419 ctx := testContext2(t, &ContextOpts{ 3420 Module: m, 3421 Providers: map[string]ResourceProviderFactory{ 3422 "aws": testProviderFuncFixed(p), 3423 }, 3424 State: &State{ 3425 Modules: []*ModuleState{ 3426 &ModuleState{ 3427 Path: rootModulePath, 3428 Resources: map[string]*ResourceState{ 3429 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3430 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3431 }, 3432 }, 3433 &ModuleState{ 3434 Path: []string{"root", "child"}, 3435 Resources: map[string]*ResourceState{ 3436 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3437 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3438 }, 3439 }, 3440 }, 3441 }, 3442 Targets: []string{"module.child.aws_instance.foo"}, 3443 Destroy: true, 3444 }) 3445 3446 if _, err := ctx.Plan(); err != nil { 3447 t.Fatalf("err: %s", err) 3448 } 3449 3450 state, err := ctx.Apply() 3451 if err != nil { 3452 t.Fatalf("err: %s", err) 3453 } 3454 3455 checkStateString(t, state, ` 3456 aws_instance.bar: 3457 ID = i-abc123 3458 aws_instance.foo: 3459 ID = i-bcd345 3460 3461 module.child: 3462 aws_instance.bar: 3463 ID = i-abc123 3464 `) 3465 } 3466 3467 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 3468 m := testModule(t, "apply-targeted-count") 3469 p := testProvider("aws") 3470 p.ApplyFn = testApplyFn 3471 p.DiffFn = testDiffFn 3472 ctx := testContext2(t, &ContextOpts{ 3473 Module: m, 3474 Providers: map[string]ResourceProviderFactory{ 3475 "aws": testProviderFuncFixed(p), 3476 }, 3477 State: &State{ 3478 Modules: []*ModuleState{ 3479 &ModuleState{ 3480 Path: rootModulePath, 3481 Resources: map[string]*ResourceState{ 3482 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 3483 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 3484 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 3485 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 3486 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 3487 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 3488 }, 3489 }, 3490 }, 3491 }, 3492 Targets: []string{ 3493 "aws_instance.foo[2]", 3494 "aws_instance.bar[1]", 3495 }, 3496 Destroy: true, 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 { 3505 t.Fatalf("err: %s", err) 3506 } 3507 3508 checkStateString(t, state, ` 3509 aws_instance.bar.0: 3510 ID = i-abc123 3511 aws_instance.bar.2: 3512 ID = i-abc123 3513 aws_instance.foo.0: 3514 ID = i-bcd345 3515 aws_instance.foo.1: 3516 ID = i-bcd345 3517 `) 3518 } 3519 3520 func TestContext2Apply_targetedModule(t *testing.T) { 3521 m := testModule(t, "apply-targeted-module") 3522 p := testProvider("aws") 3523 p.ApplyFn = testApplyFn 3524 p.DiffFn = testDiffFn 3525 ctx := testContext2(t, &ContextOpts{ 3526 Module: m, 3527 Providers: map[string]ResourceProviderFactory{ 3528 "aws": testProviderFuncFixed(p), 3529 }, 3530 Targets: []string{"module.child"}, 3531 }) 3532 3533 if _, err := ctx.Plan(); err != nil { 3534 t.Fatalf("err: %s", err) 3535 } 3536 3537 state, err := ctx.Apply() 3538 if err != nil { 3539 t.Fatalf("err: %s", err) 3540 } 3541 3542 mod := state.ModuleByPath([]string{"root", "child"}) 3543 if mod == nil { 3544 t.Fatalf("no child module found in the state!\n\n%#v", state) 3545 } 3546 if len(mod.Resources) != 2 { 3547 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 3548 } 3549 3550 checkStateString(t, state, ` 3551 <no state> 3552 module.child: 3553 aws_instance.bar: 3554 ID = foo 3555 num = 2 3556 type = aws_instance 3557 aws_instance.foo: 3558 ID = foo 3559 num = 2 3560 type = aws_instance 3561 `) 3562 } 3563 3564 // GH-1858 3565 func TestContext2Apply_targetedModuleDep(t *testing.T) { 3566 m := testModule(t, "apply-targeted-module-dep") 3567 p := testProvider("aws") 3568 p.ApplyFn = testApplyFn 3569 p.DiffFn = testDiffFn 3570 ctx := testContext2(t, &ContextOpts{ 3571 Module: m, 3572 Providers: map[string]ResourceProviderFactory{ 3573 "aws": testProviderFuncFixed(p), 3574 }, 3575 Targets: []string{"aws_instance.foo"}, 3576 }) 3577 3578 if _, err := ctx.Plan(); err != nil { 3579 t.Fatalf("err: %s", err) 3580 } 3581 3582 state, err := ctx.Apply() 3583 if err != nil { 3584 t.Fatalf("err: %s", err) 3585 } 3586 3587 checkStateString(t, state, ` 3588 aws_instance.foo: 3589 ID = foo 3590 foo = foo 3591 type = aws_instance 3592 3593 Dependencies: 3594 module.child 3595 3596 module.child: 3597 aws_instance.mod: 3598 ID = foo 3599 3600 Outputs: 3601 3602 output = foo 3603 `) 3604 } 3605 3606 func TestContext2Apply_targetedModuleResource(t *testing.T) { 3607 m := testModule(t, "apply-targeted-module-resource") 3608 p := testProvider("aws") 3609 p.ApplyFn = testApplyFn 3610 p.DiffFn = testDiffFn 3611 ctx := testContext2(t, &ContextOpts{ 3612 Module: m, 3613 Providers: map[string]ResourceProviderFactory{ 3614 "aws": testProviderFuncFixed(p), 3615 }, 3616 Targets: []string{"module.child.aws_instance.foo"}, 3617 }) 3618 3619 if _, err := ctx.Plan(); err != nil { 3620 t.Fatalf("err: %s", err) 3621 } 3622 3623 state, err := ctx.Apply() 3624 if err != nil { 3625 t.Fatalf("err: %s", err) 3626 } 3627 3628 mod := state.ModuleByPath([]string{"root", "child"}) 3629 if len(mod.Resources) != 1 { 3630 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3631 } 3632 3633 checkStateString(t, state, ` 3634 <no state> 3635 module.child: 3636 aws_instance.foo: 3637 ID = foo 3638 num = 2 3639 type = aws_instance 3640 `) 3641 } 3642 3643 func TestContext2Apply_unknownAttribute(t *testing.T) { 3644 m := testModule(t, "apply-unknown") 3645 p := testProvider("aws") 3646 p.ApplyFn = testApplyFn 3647 p.DiffFn = testDiffFn 3648 ctx := testContext2(t, &ContextOpts{ 3649 Module: m, 3650 Providers: map[string]ResourceProviderFactory{ 3651 "aws": testProviderFuncFixed(p), 3652 }, 3653 }) 3654 3655 if _, err := ctx.Plan(); err != nil { 3656 t.Fatalf("err: %s", err) 3657 } 3658 3659 state, err := ctx.Apply() 3660 if err == nil { 3661 t.Fatal("should error") 3662 } 3663 3664 actual := strings.TrimSpace(state.String()) 3665 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 3666 if actual != expected { 3667 t.Fatalf("bad: \n%s", actual) 3668 } 3669 } 3670 3671 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 3672 m := testModule(t, "apply-unknown-interpolate") 3673 p := testProvider("aws") 3674 p.ApplyFn = testApplyFn 3675 p.DiffFn = testDiffFn 3676 ctx := testContext2(t, &ContextOpts{ 3677 Module: m, 3678 Providers: map[string]ResourceProviderFactory{ 3679 "aws": testProviderFuncFixed(p), 3680 }, 3681 }) 3682 3683 if _, err := ctx.Plan(); err == nil { 3684 t.Fatal("should error") 3685 } 3686 } 3687 3688 func TestContext2Apply_vars(t *testing.T) { 3689 m := testModule(t, "apply-vars") 3690 p := testProvider("aws") 3691 p.ApplyFn = testApplyFn 3692 p.DiffFn = testDiffFn 3693 ctx := testContext2(t, &ContextOpts{ 3694 Module: m, 3695 Providers: map[string]ResourceProviderFactory{ 3696 "aws": testProviderFuncFixed(p), 3697 }, 3698 Variables: map[string]string{ 3699 "foo": "us-west-2", 3700 "amis.us-east-1": "override", 3701 }, 3702 }) 3703 3704 w, e := ctx.Validate() 3705 if len(w) > 0 { 3706 t.Fatalf("bad: %#v", w) 3707 } 3708 if len(e) > 0 { 3709 t.Fatalf("bad: %s", e) 3710 } 3711 3712 if _, err := ctx.Plan(); err != nil { 3713 t.Fatalf("err: %s", err) 3714 } 3715 3716 state, err := ctx.Apply() 3717 if err != nil { 3718 t.Fatalf("err: %s", err) 3719 } 3720 3721 actual := strings.TrimSpace(state.String()) 3722 expected := strings.TrimSpace(testTerraformApplyVarsStr) 3723 if actual != expected { 3724 t.Fatalf("bad: \n%s", actual) 3725 } 3726 } 3727 3728 func TestContext2Apply_varsEnv(t *testing.T) { 3729 // Set the env var 3730 old := tempEnv(t, "TF_VAR_ami", "baz") 3731 defer os.Setenv("TF_VAR_ami", old) 3732 3733 m := testModule(t, "apply-vars-env") 3734 p := testProvider("aws") 3735 p.ApplyFn = testApplyFn 3736 p.DiffFn = testDiffFn 3737 ctx := testContext2(t, &ContextOpts{ 3738 Module: m, 3739 Providers: map[string]ResourceProviderFactory{ 3740 "aws": testProviderFuncFixed(p), 3741 }, 3742 }) 3743 3744 w, e := ctx.Validate() 3745 if len(w) > 0 { 3746 t.Fatalf("bad: %#v", w) 3747 } 3748 if len(e) > 0 { 3749 t.Fatalf("bad: %s", e) 3750 } 3751 3752 if _, err := ctx.Plan(); err != nil { 3753 t.Fatalf("err: %s", err) 3754 } 3755 3756 state, err := ctx.Apply() 3757 if err != nil { 3758 t.Fatalf("err: %s", err) 3759 } 3760 3761 actual := strings.TrimSpace(state.String()) 3762 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 3763 if actual != expected { 3764 t.Fatalf("bad: \n%s", actual) 3765 } 3766 } 3767 3768 func TestContext2Apply_createBefore_depends(t *testing.T) { 3769 m := testModule(t, "apply-depends-create-before") 3770 h := new(HookRecordApplyOrder) 3771 p := testProvider("aws") 3772 p.ApplyFn = testApplyFn 3773 p.DiffFn = testDiffFn 3774 state := &State{ 3775 Modules: []*ModuleState{ 3776 &ModuleState{ 3777 Path: rootModulePath, 3778 Resources: map[string]*ResourceState{ 3779 "aws_instance.web": &ResourceState{ 3780 Type: "aws_instance", 3781 Primary: &InstanceState{ 3782 ID: "bar", 3783 Attributes: map[string]string{ 3784 "require_new": "ami-old", 3785 }, 3786 }, 3787 }, 3788 "aws_instance.lb": &ResourceState{ 3789 Type: "aws_instance", 3790 Primary: &InstanceState{ 3791 ID: "baz", 3792 Attributes: map[string]string{ 3793 "instance": "bar", 3794 }, 3795 }, 3796 }, 3797 }, 3798 }, 3799 }, 3800 } 3801 ctx := testContext2(t, &ContextOpts{ 3802 Module: m, 3803 Hooks: []Hook{h}, 3804 Providers: map[string]ResourceProviderFactory{ 3805 "aws": testProviderFuncFixed(p), 3806 }, 3807 State: state, 3808 }) 3809 3810 if _, err := ctx.Plan(); err != nil { 3811 t.Fatalf("err: %s", err) 3812 } 3813 3814 h.Active = true 3815 state, err := ctx.Apply() 3816 if err != nil { 3817 t.Fatalf("err: %s", err) 3818 } 3819 3820 mod := state.RootModule() 3821 if len(mod.Resources) < 2 { 3822 t.Fatalf("bad: %#v", mod.Resources) 3823 } 3824 3825 actual := strings.TrimSpace(state.String()) 3826 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 3827 if actual != expected { 3828 t.Fatalf("bad: \n%s\n%s", actual, expected) 3829 } 3830 3831 // Test that things were managed _in the right order_ 3832 order := h.States 3833 diffs := h.Diffs 3834 if order[0].ID != "" || diffs[0].Destroy { 3835 t.Fatalf("should create new instance first: %#v", order) 3836 } 3837 3838 if order[1].ID != "baz" { 3839 t.Fatalf("update must happen after create: %#v", order) 3840 } 3841 3842 if order[2].ID != "bar" || !diffs[2].Destroy { 3843 t.Fatalf("destroy must happen after update: %#v", order) 3844 } 3845 } 3846 3847 func TestContext2Apply_singleDestroy(t *testing.T) { 3848 m := testModule(t, "apply-depends-create-before") 3849 h := new(HookRecordApplyOrder) 3850 p := testProvider("aws") 3851 3852 invokeCount := 0 3853 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3854 invokeCount++ 3855 switch invokeCount { 3856 case 1: 3857 if d.Destroy { 3858 t.Fatalf("should not destroy") 3859 } 3860 if s.ID != "" { 3861 t.Fatalf("should not have ID") 3862 } 3863 case 2: 3864 if d.Destroy { 3865 t.Fatalf("should not destroy") 3866 } 3867 if s.ID != "baz" { 3868 t.Fatalf("should have id") 3869 } 3870 case 3: 3871 if !d.Destroy { 3872 t.Fatalf("should destroy") 3873 } 3874 if s.ID == "" { 3875 t.Fatalf("should have ID") 3876 } 3877 default: 3878 t.Fatalf("bad invoke count %d", invokeCount) 3879 } 3880 return testApplyFn(info, s, d) 3881 } 3882 p.DiffFn = testDiffFn 3883 state := &State{ 3884 Modules: []*ModuleState{ 3885 &ModuleState{ 3886 Path: rootModulePath, 3887 Resources: map[string]*ResourceState{ 3888 "aws_instance.web": &ResourceState{ 3889 Type: "aws_instance", 3890 Primary: &InstanceState{ 3891 ID: "bar", 3892 Attributes: map[string]string{ 3893 "require_new": "ami-old", 3894 }, 3895 }, 3896 }, 3897 "aws_instance.lb": &ResourceState{ 3898 Type: "aws_instance", 3899 Primary: &InstanceState{ 3900 ID: "baz", 3901 Attributes: map[string]string{ 3902 "instance": "bar", 3903 }, 3904 }, 3905 }, 3906 }, 3907 }, 3908 }, 3909 } 3910 ctx := testContext2(t, &ContextOpts{ 3911 Module: m, 3912 Hooks: []Hook{h}, 3913 Providers: map[string]ResourceProviderFactory{ 3914 "aws": testProviderFuncFixed(p), 3915 }, 3916 State: state, 3917 }) 3918 3919 if _, err := ctx.Plan(); err != nil { 3920 t.Fatalf("err: %s", err) 3921 } 3922 3923 h.Active = true 3924 state, err := ctx.Apply() 3925 if err != nil { 3926 t.Fatalf("err: %s", err) 3927 } 3928 3929 if invokeCount != 3 { 3930 t.Fatalf("bad: %d", invokeCount) 3931 } 3932 } 3933 3934 // GH-5254 3935 func TestContext2Apply_issue5254(t *testing.T) { 3936 // Create a provider. We use "template" here just to match the repro 3937 // we got from the issue itself. 3938 p := testProvider("template") 3939 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 3940 Name: "template_file", 3941 }) 3942 3943 p.ApplyFn = testApplyFn 3944 p.DiffFn = testDiffFn 3945 3946 // Apply cleanly step 0 3947 t.Log("Applying Step 0") 3948 ctx := testContext2(t, &ContextOpts{ 3949 Module: testModule(t, "issue-5254/step-0"), 3950 Providers: map[string]ResourceProviderFactory{ 3951 "template": testProviderFuncFixed(p), 3952 }, 3953 }) 3954 3955 plan, err := ctx.Plan() 3956 if err != nil { 3957 t.Fatalf("err: %s", err) 3958 } 3959 t.Logf("Plan for Step 0: %s", plan) 3960 3961 state, err := ctx.Apply() 3962 if err != nil { 3963 t.Fatalf("err: %s", err) 3964 } 3965 3966 // Application success. Now make the modification and store a plan 3967 println("Planning Step 1") 3968 t.Log("Planning Step 1") 3969 ctx = testContext2(t, &ContextOpts{ 3970 Module: testModule(t, "issue-5254/step-1"), 3971 State: state, 3972 Providers: map[string]ResourceProviderFactory{ 3973 "template": testProviderFuncFixed(p), 3974 }, 3975 }) 3976 3977 plan, err = ctx.Plan() 3978 if err != nil { 3979 t.Fatalf("err: %s", err) 3980 } 3981 3982 // Write / Read plan to simulate running it through a Plan file 3983 var buf bytes.Buffer 3984 if err := WritePlan(plan, &buf); err != nil { 3985 t.Fatalf("err: %s", err) 3986 } 3987 3988 planFromFile, err := ReadPlan(&buf) 3989 if err != nil { 3990 t.Fatalf("err: %s", err) 3991 } 3992 3993 t.Logf("Plan for Step 1: %s", planFromFile) 3994 3995 // Apply the plan 3996 println("Applying Step 1 (from Plan)") 3997 t.Log("Applying Step 1 (from plan)") 3998 ctx = planFromFile.Context(&ContextOpts{ 3999 Providers: map[string]ResourceProviderFactory{ 4000 "template": testProviderFuncFixed(p), 4001 }, 4002 }) 4003 4004 state, err = ctx.Apply() 4005 if err != nil { 4006 t.Fatalf("err: %s", err) 4007 } 4008 4009 /* 4010 actual := strings.TrimSpace(state.String()) 4011 expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) 4012 if actual != expected { 4013 t.Fatalf("bad: \n%s", actual) 4014 } 4015 */ 4016 }