github.com/anfernee/terraform@v0.6.16-0.20160430000239-06e5085a92f2/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 func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { 1060 m := testModule(t, "apply-module-grandchild-provider-inherit") 1061 p := testProvider("aws") 1062 p.ApplyFn = testApplyFn 1063 p.DiffFn = testDiffFn 1064 1065 var callLock sync.Mutex 1066 called := false 1067 p.ConfigureFn = func(c *ResourceConfig) error { 1068 if _, ok := c.Get("value"); !ok { 1069 return fmt.Errorf("value is not found") 1070 } 1071 callLock.Lock() 1072 called = true 1073 callLock.Unlock() 1074 1075 return nil 1076 } 1077 1078 ctx := testContext2(t, &ContextOpts{ 1079 Module: m, 1080 Providers: map[string]ResourceProviderFactory{ 1081 "aws": testProviderFuncFixed(p), 1082 }, 1083 }) 1084 1085 if _, err := ctx.Plan(); err != nil { 1086 t.Fatalf("err: %s", err) 1087 } 1088 1089 if _, err := ctx.Apply(); err != nil { 1090 t.Fatalf("err: %s", err) 1091 } 1092 1093 callLock.Lock() 1094 defer callLock.Unlock() 1095 if called != true { 1096 t.Fatalf("err: configure never called") 1097 } 1098 } 1099 1100 // This tests an issue where all the providers in a module but not 1101 // in the root weren't being added to the root properly. In this test 1102 // case: aws is explicitly added to root, but "test" should be added to. 1103 // With the bug, it wasn't. 1104 func TestContext2Apply_moduleOnlyProvider(t *testing.T) { 1105 m := testModule(t, "apply-module-only-provider") 1106 p := testProvider("aws") 1107 p.ApplyFn = testApplyFn 1108 p.DiffFn = testDiffFn 1109 pTest := testProvider("test") 1110 pTest.ApplyFn = testApplyFn 1111 pTest.DiffFn = testDiffFn 1112 1113 ctx := testContext2(t, &ContextOpts{ 1114 Module: m, 1115 Providers: map[string]ResourceProviderFactory{ 1116 "aws": testProviderFuncFixed(p), 1117 "test": testProviderFuncFixed(pTest), 1118 }, 1119 }) 1120 1121 if _, err := ctx.Plan(); err != nil { 1122 t.Fatalf("err: %s", err) 1123 } 1124 1125 state, err := ctx.Apply() 1126 if err != nil { 1127 t.Fatalf("err: %s", err) 1128 } 1129 1130 actual := strings.TrimSpace(state.String()) 1131 expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) 1132 if actual != expected { 1133 t.Fatalf("bad: \n%s", actual) 1134 } 1135 } 1136 1137 func TestContext2Apply_moduleProviderAlias(t *testing.T) { 1138 m := testModule(t, "apply-module-provider-alias") 1139 p := testProvider("aws") 1140 p.ApplyFn = testApplyFn 1141 p.DiffFn = testDiffFn 1142 ctx := testContext2(t, &ContextOpts{ 1143 Module: m, 1144 Providers: map[string]ResourceProviderFactory{ 1145 "aws": testProviderFuncFixed(p), 1146 }, 1147 }) 1148 1149 if _, err := ctx.Plan(); err != nil { 1150 t.Fatalf("err: %s", err) 1151 } 1152 1153 state, err := ctx.Apply() 1154 if err != nil { 1155 t.Fatalf("err: %s", err) 1156 } 1157 1158 actual := strings.TrimSpace(state.String()) 1159 expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) 1160 if actual != expected { 1161 t.Fatalf("bad: \n%s", actual) 1162 } 1163 } 1164 1165 func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { 1166 m := testModule(t, "apply-module-provider-alias") 1167 p := testProvider("aws") 1168 p.ApplyFn = testApplyFn 1169 p.DiffFn = testDiffFn 1170 ctx := testContext2(t, &ContextOpts{ 1171 Module: m, 1172 Providers: map[string]ResourceProviderFactory{ 1173 "aws": testProviderFuncFixed(p), 1174 }, 1175 Targets: []string{"no.thing"}, 1176 }) 1177 1178 if _, err := ctx.Plan(); err != nil { 1179 t.Fatalf("err: %s", err) 1180 } 1181 1182 state, err := ctx.Apply() 1183 if err != nil { 1184 t.Fatalf("err: %s", err) 1185 } 1186 1187 actual := strings.TrimSpace(state.String()) 1188 expected := strings.TrimSpace(` 1189 <no state> 1190 `) 1191 if actual != expected { 1192 t.Fatalf("bad: \n%s", actual) 1193 } 1194 } 1195 1196 func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { 1197 m := testModule(t, "apply-module-provider-close-nested") 1198 p := testProvider("aws") 1199 p.ApplyFn = testApplyFn 1200 p.DiffFn = testDiffFn 1201 ctx := testContext2(t, &ContextOpts{ 1202 Module: m, 1203 Providers: map[string]ResourceProviderFactory{ 1204 "aws": testProviderFuncFixed(p), 1205 }, 1206 State: &State{ 1207 Modules: []*ModuleState{ 1208 &ModuleState{ 1209 Path: []string{"root", "child", "subchild"}, 1210 Resources: map[string]*ResourceState{ 1211 "aws_instance.foo": &ResourceState{ 1212 Type: "aws_instance", 1213 Primary: &InstanceState{ 1214 ID: "bar", 1215 }, 1216 }, 1217 }, 1218 }, 1219 }, 1220 }, 1221 Destroy: true, 1222 }) 1223 1224 if _, err := ctx.Plan(); err != nil { 1225 t.Fatalf("err: %s", err) 1226 } 1227 1228 if _, err := ctx.Apply(); err != nil { 1229 t.Fatalf("err: %s", err) 1230 } 1231 } 1232 1233 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 1234 m := testModule(t, "apply-module-var-resource-count") 1235 p := testProvider("aws") 1236 p.ApplyFn = testApplyFn 1237 p.DiffFn = testDiffFn 1238 ctx := testContext2(t, &ContextOpts{ 1239 Module: m, 1240 Providers: map[string]ResourceProviderFactory{ 1241 "aws": testProviderFuncFixed(p), 1242 }, 1243 Variables: map[string]string{ 1244 "count": "2", 1245 }, 1246 Destroy: true, 1247 }) 1248 1249 if _, err := ctx.Plan(); err != nil { 1250 t.Fatalf("err: %s", err) 1251 } 1252 1253 if _, err := ctx.Apply(); err != nil { 1254 t.Fatalf("err: %s", err) 1255 } 1256 1257 ctx = testContext2(t, &ContextOpts{ 1258 Module: m, 1259 Providers: map[string]ResourceProviderFactory{ 1260 "aws": testProviderFuncFixed(p), 1261 }, 1262 Variables: map[string]string{ 1263 "count": "5", 1264 }, 1265 }) 1266 1267 if _, err := ctx.Plan(); err != nil { 1268 t.Fatalf("err: %s", err) 1269 } 1270 1271 if _, err := ctx.Apply(); err != nil { 1272 t.Fatalf("err: %s", err) 1273 } 1274 } 1275 1276 // GH-819 1277 func TestContext2Apply_moduleBool(t *testing.T) { 1278 m := testModule(t, "apply-module-bool") 1279 p := testProvider("aws") 1280 p.ApplyFn = testApplyFn 1281 p.DiffFn = testDiffFn 1282 ctx := testContext2(t, &ContextOpts{ 1283 Module: m, 1284 Providers: map[string]ResourceProviderFactory{ 1285 "aws": testProviderFuncFixed(p), 1286 }, 1287 }) 1288 1289 if _, err := ctx.Plan(); err != nil { 1290 t.Fatalf("err: %s", err) 1291 } 1292 1293 state, err := ctx.Apply() 1294 if err != nil { 1295 t.Fatalf("err: %s", err) 1296 } 1297 1298 actual := strings.TrimSpace(state.String()) 1299 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 1300 if actual != expected { 1301 t.Fatalf("bad: \n%s", actual) 1302 } 1303 } 1304 1305 func TestContext2Apply_multiProvider(t *testing.T) { 1306 m := testModule(t, "apply-multi-provider") 1307 p := testProvider("aws") 1308 p.ApplyFn = testApplyFn 1309 p.DiffFn = testDiffFn 1310 1311 pDO := testProvider("do") 1312 pDO.ApplyFn = testApplyFn 1313 pDO.DiffFn = testDiffFn 1314 1315 ctx := testContext2(t, &ContextOpts{ 1316 Module: m, 1317 Providers: map[string]ResourceProviderFactory{ 1318 "aws": testProviderFuncFixed(p), 1319 "do": testProviderFuncFixed(pDO), 1320 }, 1321 }) 1322 1323 if _, err := ctx.Plan(); err != nil { 1324 t.Fatalf("err: %s", err) 1325 } 1326 1327 state, err := ctx.Apply() 1328 if err != nil { 1329 t.Fatalf("err: %s", err) 1330 } 1331 1332 mod := state.RootModule() 1333 if len(mod.Resources) < 2 { 1334 t.Fatalf("bad: %#v", mod.Resources) 1335 } 1336 1337 actual := strings.TrimSpace(state.String()) 1338 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 1339 if actual != expected { 1340 t.Fatalf("bad: \n%s", actual) 1341 } 1342 } 1343 1344 func TestContext2Apply_multiVar(t *testing.T) { 1345 m := testModule(t, "apply-multi-var") 1346 p := testProvider("aws") 1347 p.ApplyFn = testApplyFn 1348 p.DiffFn = testDiffFn 1349 1350 // First, apply with a count of 3 1351 ctx := testContext2(t, &ContextOpts{ 1352 Module: m, 1353 Providers: map[string]ResourceProviderFactory{ 1354 "aws": testProviderFuncFixed(p), 1355 }, 1356 Variables: map[string]string{ 1357 "count": "3", 1358 }, 1359 }) 1360 1361 if _, err := ctx.Plan(); err != nil { 1362 t.Fatalf("err: %s", err) 1363 } 1364 1365 state, err := ctx.Apply() 1366 if err != nil { 1367 t.Fatalf("err: %s", err) 1368 } 1369 1370 actual := state.RootModule().Outputs["output"] 1371 expected := "bar0,bar1,bar2" 1372 if actual != expected { 1373 t.Fatalf("bad: \n%s", actual) 1374 } 1375 1376 // Apply again, reduce the count to 1 1377 { 1378 ctx := testContext2(t, &ContextOpts{ 1379 Module: m, 1380 State: state, 1381 Providers: map[string]ResourceProviderFactory{ 1382 "aws": testProviderFuncFixed(p), 1383 }, 1384 Variables: map[string]string{ 1385 "count": "1", 1386 }, 1387 }) 1388 1389 if _, err := ctx.Plan(); err != nil { 1390 t.Fatalf("err: %s", err) 1391 } 1392 1393 state, err := ctx.Apply() 1394 if err != nil { 1395 t.Fatalf("err: %s", err) 1396 } 1397 1398 actual := state.RootModule().Outputs["output"] 1399 expected := "bar0" 1400 if actual != expected { 1401 t.Fatalf("bad: \n%s", actual) 1402 } 1403 } 1404 } 1405 1406 func TestContext2Apply_nilDiff(t *testing.T) { 1407 m := testModule(t, "apply-good") 1408 p := testProvider("aws") 1409 p.ApplyFn = testApplyFn 1410 p.DiffFn = testDiffFn 1411 ctx := testContext2(t, &ContextOpts{ 1412 Module: m, 1413 Providers: map[string]ResourceProviderFactory{ 1414 "aws": testProviderFuncFixed(p), 1415 }, 1416 }) 1417 1418 if _, err := ctx.Plan(); err != nil { 1419 t.Fatalf("err: %s", err) 1420 } 1421 1422 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1423 return nil, nil 1424 } 1425 1426 if _, err := ctx.Apply(); err == nil { 1427 t.Fatal("should error") 1428 } 1429 } 1430 1431 func TestContext2Apply_outputOrphan(t *testing.T) { 1432 m := testModule(t, "apply-output-orphan") 1433 p := testProvider("aws") 1434 p.ApplyFn = testApplyFn 1435 p.DiffFn = testDiffFn 1436 1437 state := &State{ 1438 Modules: []*ModuleState{ 1439 &ModuleState{ 1440 Path: rootModulePath, 1441 Outputs: map[string]string{ 1442 "foo": "bar", 1443 "bar": "baz", 1444 }, 1445 }, 1446 }, 1447 } 1448 1449 ctx := testContext2(t, &ContextOpts{ 1450 Module: m, 1451 Providers: map[string]ResourceProviderFactory{ 1452 "aws": testProviderFuncFixed(p), 1453 }, 1454 State: state, 1455 }) 1456 1457 if _, err := ctx.Plan(); err != nil { 1458 t.Fatalf("err: %s", err) 1459 } 1460 1461 state, err := ctx.Apply() 1462 if err != nil { 1463 t.Fatalf("err: %s", err) 1464 } 1465 1466 actual := strings.TrimSpace(state.String()) 1467 expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) 1468 if actual != expected { 1469 t.Fatalf("bad: \n%s", actual) 1470 } 1471 } 1472 1473 func TestContext2Apply_providerComputedVar(t *testing.T) { 1474 m := testModule(t, "apply-provider-computed") 1475 p := testProvider("aws") 1476 p.ApplyFn = testApplyFn 1477 p.DiffFn = testDiffFn 1478 1479 pTest := testProvider("test") 1480 pTest.ApplyFn = testApplyFn 1481 pTest.DiffFn = testDiffFn 1482 1483 ctx := testContext2(t, &ContextOpts{ 1484 Module: m, 1485 Providers: map[string]ResourceProviderFactory{ 1486 "aws": testProviderFuncFixed(p), 1487 "test": testProviderFuncFixed(pTest), 1488 }, 1489 }) 1490 1491 p.ConfigureFn = func(c *ResourceConfig) error { 1492 if c.IsComputed("value") { 1493 return fmt.Errorf("value is computed") 1494 } 1495 1496 v, ok := c.Get("value") 1497 if !ok { 1498 return fmt.Errorf("value is not found") 1499 } 1500 if v != "yes" { 1501 return fmt.Errorf("value is not 'yes': %v", v) 1502 } 1503 1504 return nil 1505 } 1506 1507 if _, err := ctx.Plan(); err != nil { 1508 t.Fatalf("err: %s", err) 1509 } 1510 1511 if _, err := ctx.Apply(); err != nil { 1512 t.Fatalf("err: %s", err) 1513 } 1514 } 1515 1516 func TestContext2Apply_Provisioner_compute(t *testing.T) { 1517 m := testModule(t, "apply-provisioner-compute") 1518 p := testProvider("aws") 1519 pr := testProvisioner() 1520 p.ApplyFn = testApplyFn 1521 p.DiffFn = testDiffFn 1522 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1523 val, ok := c.Config["foo"] 1524 if !ok || val != "computed_dynamical" { 1525 t.Fatalf("bad value for foo: %v %#v", val, c) 1526 } 1527 1528 return nil 1529 } 1530 ctx := testContext2(t, &ContextOpts{ 1531 Module: m, 1532 Providers: map[string]ResourceProviderFactory{ 1533 "aws": testProviderFuncFixed(p), 1534 }, 1535 Provisioners: map[string]ResourceProvisionerFactory{ 1536 "shell": testProvisionerFuncFixed(pr), 1537 }, 1538 Variables: map[string]string{ 1539 "value": "1", 1540 }, 1541 }) 1542 1543 if _, err := ctx.Plan(); err != nil { 1544 t.Fatalf("err: %s", err) 1545 } 1546 1547 state, err := ctx.Apply() 1548 if err != nil { 1549 t.Fatalf("err: %s", err) 1550 } 1551 1552 actual := strings.TrimSpace(state.String()) 1553 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 1554 if actual != expected { 1555 t.Fatalf("bad: \n%s", actual) 1556 } 1557 1558 // Verify apply was invoked 1559 if !pr.ApplyCalled { 1560 t.Fatalf("provisioner not invoked") 1561 } 1562 } 1563 1564 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 1565 m := testModule(t, "apply-provisioner-fail-create") 1566 p := testProvider("aws") 1567 pr := testProvisioner() 1568 p.DiffFn = testDiffFn 1569 1570 p.ApplyFn = func( 1571 info *InstanceInfo, 1572 is *InstanceState, 1573 id *InstanceDiff) (*InstanceState, error) { 1574 is.ID = "foo" 1575 return is, fmt.Errorf("error") 1576 } 1577 1578 ctx := testContext2(t, &ContextOpts{ 1579 Module: m, 1580 Providers: map[string]ResourceProviderFactory{ 1581 "aws": testProviderFuncFixed(p), 1582 }, 1583 Provisioners: map[string]ResourceProvisionerFactory{ 1584 "shell": testProvisionerFuncFixed(pr), 1585 }, 1586 }) 1587 1588 if _, err := ctx.Plan(); err != nil { 1589 t.Fatalf("err: %s", err) 1590 } 1591 1592 state, err := ctx.Apply() 1593 if err == nil { 1594 t.Fatal("should error") 1595 } 1596 1597 actual := strings.TrimSpace(state.String()) 1598 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 1599 if actual != expected { 1600 t.Fatalf("bad: \n%s", actual) 1601 } 1602 } 1603 1604 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 1605 m := testModule(t, "apply-provisioner-fail-create") 1606 p := testProvider("aws") 1607 pr := testProvisioner() 1608 p.DiffFn = testDiffFn 1609 1610 p.ApplyFn = func( 1611 info *InstanceInfo, 1612 is *InstanceState, 1613 id *InstanceDiff) (*InstanceState, error) { 1614 return nil, fmt.Errorf("error") 1615 } 1616 1617 ctx := testContext2(t, &ContextOpts{ 1618 Module: m, 1619 Providers: map[string]ResourceProviderFactory{ 1620 "aws": testProviderFuncFixed(p), 1621 }, 1622 Provisioners: map[string]ResourceProvisionerFactory{ 1623 "shell": testProvisionerFuncFixed(pr), 1624 }, 1625 }) 1626 1627 if _, err := ctx.Plan(); err != nil { 1628 t.Fatalf("err: %s", err) 1629 } 1630 1631 state, err := ctx.Apply() 1632 if err == nil { 1633 t.Fatal("should error") 1634 } 1635 1636 actual := strings.TrimSpace(state.String()) 1637 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 1638 if actual != expected { 1639 t.Fatalf("bad: \n%s", actual) 1640 } 1641 } 1642 1643 func TestContext2Apply_provisionerFail(t *testing.T) { 1644 m := testModule(t, "apply-provisioner-fail") 1645 p := testProvider("aws") 1646 pr := testProvisioner() 1647 p.ApplyFn = testApplyFn 1648 p.DiffFn = testDiffFn 1649 1650 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 1651 return fmt.Errorf("EXPLOSION") 1652 } 1653 1654 ctx := testContext2(t, &ContextOpts{ 1655 Module: m, 1656 Providers: map[string]ResourceProviderFactory{ 1657 "aws": testProviderFuncFixed(p), 1658 }, 1659 Provisioners: map[string]ResourceProvisionerFactory{ 1660 "shell": testProvisionerFuncFixed(pr), 1661 }, 1662 Variables: map[string]string{ 1663 "value": "1", 1664 }, 1665 }) 1666 1667 if _, err := ctx.Plan(); err != nil { 1668 t.Fatalf("err: %s", err) 1669 } 1670 1671 state, err := ctx.Apply() 1672 if err == nil { 1673 t.Fatal("should error") 1674 } 1675 1676 actual := strings.TrimSpace(state.String()) 1677 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 1678 if actual != expected { 1679 t.Fatalf("bad: \n%s", actual) 1680 } 1681 } 1682 1683 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 1684 m := testModule(t, "apply-provisioner-fail-create-before") 1685 p := testProvider("aws") 1686 pr := testProvisioner() 1687 p.ApplyFn = testApplyFn 1688 p.DiffFn = testDiffFn 1689 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 1690 return fmt.Errorf("EXPLOSION") 1691 } 1692 1693 state := &State{ 1694 Modules: []*ModuleState{ 1695 &ModuleState{ 1696 Path: rootModulePath, 1697 Resources: map[string]*ResourceState{ 1698 "aws_instance.bar": &ResourceState{ 1699 Type: "aws_instance", 1700 Primary: &InstanceState{ 1701 ID: "bar", 1702 Attributes: map[string]string{ 1703 "require_new": "abc", 1704 }, 1705 }, 1706 }, 1707 }, 1708 }, 1709 }, 1710 } 1711 ctx := testContext2(t, &ContextOpts{ 1712 Module: m, 1713 Providers: map[string]ResourceProviderFactory{ 1714 "aws": testProviderFuncFixed(p), 1715 }, 1716 Provisioners: map[string]ResourceProvisionerFactory{ 1717 "shell": testProvisionerFuncFixed(pr), 1718 }, 1719 State: state, 1720 }) 1721 1722 if _, err := ctx.Plan(); err != nil { 1723 t.Fatalf("err: %s", err) 1724 } 1725 1726 state, err := ctx.Apply() 1727 if err == nil { 1728 t.Fatal("should error") 1729 } 1730 1731 actual := strings.TrimSpace(state.String()) 1732 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 1733 if actual != expected { 1734 t.Fatalf("bad: \n%s", actual) 1735 } 1736 } 1737 1738 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 1739 m := testModule(t, "apply-error-create-before") 1740 p := testProvider("aws") 1741 state := &State{ 1742 Modules: []*ModuleState{ 1743 &ModuleState{ 1744 Path: rootModulePath, 1745 Resources: map[string]*ResourceState{ 1746 "aws_instance.bar": &ResourceState{ 1747 Type: "aws_instance", 1748 Primary: &InstanceState{ 1749 ID: "bar", 1750 Attributes: map[string]string{ 1751 "require_new": "abc", 1752 }, 1753 }, 1754 }, 1755 }, 1756 }, 1757 }, 1758 } 1759 ctx := testContext2(t, &ContextOpts{ 1760 Module: m, 1761 Providers: map[string]ResourceProviderFactory{ 1762 "aws": testProviderFuncFixed(p), 1763 }, 1764 State: state, 1765 }) 1766 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1767 return nil, fmt.Errorf("error") 1768 } 1769 p.DiffFn = testDiffFn 1770 1771 if _, err := ctx.Plan(); err != nil { 1772 t.Fatalf("err: %s", err) 1773 } 1774 1775 state, err := ctx.Apply() 1776 if err == nil { 1777 t.Fatal("should have error") 1778 } 1779 1780 actual := strings.TrimSpace(state.String()) 1781 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 1782 if actual != expected { 1783 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 1784 } 1785 } 1786 1787 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 1788 m := testModule(t, "apply-error-create-before") 1789 p := testProvider("aws") 1790 state := &State{ 1791 Modules: []*ModuleState{ 1792 &ModuleState{ 1793 Path: rootModulePath, 1794 Resources: map[string]*ResourceState{ 1795 "aws_instance.bar": &ResourceState{ 1796 Type: "aws_instance", 1797 Primary: &InstanceState{ 1798 ID: "bar", 1799 Attributes: map[string]string{ 1800 "require_new": "abc", 1801 }, 1802 }, 1803 }, 1804 }, 1805 }, 1806 }, 1807 } 1808 ctx := testContext2(t, &ContextOpts{ 1809 Module: m, 1810 Providers: map[string]ResourceProviderFactory{ 1811 "aws": testProviderFuncFixed(p), 1812 }, 1813 State: state, 1814 }) 1815 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1816 // Fail the destroy! 1817 if id.Destroy { 1818 return is, fmt.Errorf("error") 1819 } 1820 1821 // Create should work 1822 is = &InstanceState{ 1823 ID: "foo", 1824 } 1825 return is, nil 1826 } 1827 p.DiffFn = testDiffFn 1828 1829 if _, err := ctx.Plan(); err != nil { 1830 t.Fatalf("err: %s", err) 1831 } 1832 1833 state, err := ctx.Apply() 1834 if err == nil { 1835 t.Fatal("should have error") 1836 } 1837 1838 actual := strings.TrimSpace(state.String()) 1839 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 1840 if actual != expected { 1841 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 1842 } 1843 } 1844 1845 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 1846 m := testModule(t, "apply-multi-depose-create-before-destroy") 1847 p := testProvider("aws") 1848 p.DiffFn = testDiffFn 1849 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 1850 state := &State{ 1851 Modules: []*ModuleState{ 1852 &ModuleState{ 1853 Path: rootModulePath, 1854 Resources: map[string]*ResourceState{ 1855 "aws_instance.web": &ResourceState{ 1856 Type: "aws_instance", 1857 Primary: &InstanceState{ID: "foo"}, 1858 }, 1859 }, 1860 }, 1861 }, 1862 } 1863 1864 ctx := testContext2(t, &ContextOpts{ 1865 Module: m, 1866 Providers: ps, 1867 State: state, 1868 }) 1869 createdInstanceId := "bar" 1870 // Create works 1871 createFunc := func(is *InstanceState) (*InstanceState, error) { 1872 return &InstanceState{ID: createdInstanceId}, nil 1873 } 1874 // Destroy starts broken 1875 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 1876 return is, fmt.Errorf("destroy failed") 1877 } 1878 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 1879 if id.Destroy { 1880 return destroyFunc(is) 1881 } else { 1882 return createFunc(is) 1883 } 1884 } 1885 1886 if _, err := ctx.Plan(); err != nil { 1887 t.Fatalf("err: %s", err) 1888 } 1889 1890 // Destroy is broken, so even though CBD successfully replaces the instance, 1891 // we'll have to save the Deposed instance to destroy later 1892 state, err := ctx.Apply() 1893 if err == nil { 1894 t.Fatal("should have error") 1895 } 1896 1897 checkStateString(t, state, ` 1898 aws_instance.web: (1 deposed) 1899 ID = bar 1900 Deposed ID 1 = foo 1901 `) 1902 1903 createdInstanceId = "baz" 1904 ctx = testContext2(t, &ContextOpts{ 1905 Module: m, 1906 Providers: ps, 1907 State: state, 1908 }) 1909 1910 if _, err := ctx.Plan(); err != nil { 1911 t.Fatalf("err: %s", err) 1912 } 1913 1914 // We're replacing the primary instance once again. Destroy is _still_ 1915 // broken, so the Deposed list gets longer 1916 state, err = ctx.Apply() 1917 if err == nil { 1918 t.Fatal("should have error") 1919 } 1920 1921 checkStateString(t, state, ` 1922 aws_instance.web: (2 deposed) 1923 ID = baz 1924 Deposed ID 1 = foo 1925 Deposed ID 2 = bar 1926 `) 1927 1928 // Destroy partially fixed! 1929 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 1930 if is.ID == "foo" || is.ID == "baz" { 1931 return nil, nil 1932 } else { 1933 return is, fmt.Errorf("destroy partially failed") 1934 } 1935 } 1936 1937 createdInstanceId = "qux" 1938 if _, err := ctx.Plan(); err != nil { 1939 t.Fatalf("err: %s", err) 1940 } 1941 state, err = ctx.Apply() 1942 // Expect error because 1/2 of Deposed destroys failed 1943 if err == nil { 1944 t.Fatal("should have error") 1945 } 1946 1947 // foo and baz are now gone, bar sticks around 1948 checkStateString(t, state, ` 1949 aws_instance.web: (1 deposed) 1950 ID = qux 1951 Deposed ID 1 = bar 1952 `) 1953 1954 // Destroy working fully! 1955 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 1956 return nil, nil 1957 } 1958 1959 createdInstanceId = "quux" 1960 if _, err := ctx.Plan(); err != nil { 1961 t.Fatalf("err: %s", err) 1962 } 1963 state, err = ctx.Apply() 1964 if err != nil { 1965 t.Fatal("should not have error:", err) 1966 } 1967 1968 // And finally the state is clean 1969 checkStateString(t, state, ` 1970 aws_instance.web: 1971 ID = quux 1972 `) 1973 } 1974 1975 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 1976 m := testModule(t, "apply-provisioner-resource-ref") 1977 p := testProvider("aws") 1978 pr := testProvisioner() 1979 p.ApplyFn = testApplyFn 1980 p.DiffFn = testDiffFn 1981 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 1982 val, ok := c.Config["foo"] 1983 if !ok || val != "2" { 1984 t.Fatalf("bad value for foo: %v %#v", val, c) 1985 } 1986 1987 return nil 1988 } 1989 1990 ctx := testContext2(t, &ContextOpts{ 1991 Module: m, 1992 Providers: map[string]ResourceProviderFactory{ 1993 "aws": testProviderFuncFixed(p), 1994 }, 1995 Provisioners: map[string]ResourceProvisionerFactory{ 1996 "shell": testProvisionerFuncFixed(pr), 1997 }, 1998 }) 1999 2000 if _, err := ctx.Plan(); err != nil { 2001 t.Fatalf("err: %s", err) 2002 } 2003 2004 state, err := ctx.Apply() 2005 if err != nil { 2006 t.Fatalf("err: %s", err) 2007 } 2008 2009 actual := strings.TrimSpace(state.String()) 2010 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 2011 if actual != expected { 2012 t.Fatalf("bad: \n%s", actual) 2013 } 2014 2015 // Verify apply was invoked 2016 if !pr.ApplyCalled { 2017 t.Fatalf("provisioner not invoked") 2018 } 2019 } 2020 2021 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 2022 m := testModule(t, "apply-provisioner-self-ref") 2023 p := testProvider("aws") 2024 pr := testProvisioner() 2025 p.ApplyFn = testApplyFn 2026 p.DiffFn = testDiffFn 2027 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2028 val, ok := c.Config["command"] 2029 if !ok || val != "bar" { 2030 t.Fatalf("bad value for command: %v %#v", val, c) 2031 } 2032 2033 return nil 2034 } 2035 2036 ctx := testContext2(t, &ContextOpts{ 2037 Module: m, 2038 Providers: map[string]ResourceProviderFactory{ 2039 "aws": testProviderFuncFixed(p), 2040 }, 2041 Provisioners: map[string]ResourceProvisionerFactory{ 2042 "shell": testProvisionerFuncFixed(pr), 2043 }, 2044 }) 2045 2046 if _, err := ctx.Plan(); err != nil { 2047 t.Fatalf("err: %s", err) 2048 } 2049 2050 state, err := ctx.Apply() 2051 if err != nil { 2052 t.Fatalf("err: %s", err) 2053 } 2054 2055 actual := strings.TrimSpace(state.String()) 2056 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 2057 if actual != expected { 2058 t.Fatalf("bad: \n%s", actual) 2059 } 2060 2061 // Verify apply was invoked 2062 if !pr.ApplyCalled { 2063 t.Fatalf("provisioner not invoked") 2064 } 2065 } 2066 2067 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 2068 var lock sync.Mutex 2069 commands := make([]string, 0, 5) 2070 2071 m := testModule(t, "apply-provisioner-multi-self-ref") 2072 p := testProvider("aws") 2073 pr := testProvisioner() 2074 p.ApplyFn = testApplyFn 2075 p.DiffFn = testDiffFn 2076 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2077 lock.Lock() 2078 defer lock.Unlock() 2079 2080 val, ok := c.Config["command"] 2081 if !ok { 2082 t.Fatalf("bad value for command: %v %#v", val, c) 2083 } 2084 2085 commands = append(commands, val.(string)) 2086 return nil 2087 } 2088 2089 ctx := testContext2(t, &ContextOpts{ 2090 Module: m, 2091 Providers: map[string]ResourceProviderFactory{ 2092 "aws": testProviderFuncFixed(p), 2093 }, 2094 Provisioners: map[string]ResourceProvisionerFactory{ 2095 "shell": testProvisionerFuncFixed(pr), 2096 }, 2097 }) 2098 2099 if _, err := ctx.Plan(); err != nil { 2100 t.Fatalf("err: %s", err) 2101 } 2102 2103 state, err := ctx.Apply() 2104 if err != nil { 2105 t.Fatalf("err: %s", err) 2106 } 2107 2108 actual := strings.TrimSpace(state.String()) 2109 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 2110 if actual != expected { 2111 t.Fatalf("bad: \n%s", actual) 2112 } 2113 2114 // Verify apply was invoked 2115 if !pr.ApplyCalled { 2116 t.Fatalf("provisioner not invoked") 2117 } 2118 2119 // Verify our result 2120 sort.Strings(commands) 2121 expectedCommands := []string{"number 0", "number 1", "number 2"} 2122 if !reflect.DeepEqual(commands, expectedCommands) { 2123 t.Fatalf("bad: %#v", commands) 2124 } 2125 } 2126 2127 // Provisioner should NOT run on a diff, only create 2128 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 2129 m := testModule(t, "apply-provisioner-diff") 2130 p := testProvider("aws") 2131 pr := testProvisioner() 2132 p.ApplyFn = testApplyFn 2133 p.DiffFn = testDiffFn 2134 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2135 return nil 2136 } 2137 ctx := testContext2(t, &ContextOpts{ 2138 Module: m, 2139 Providers: map[string]ResourceProviderFactory{ 2140 "aws": testProviderFuncFixed(p), 2141 }, 2142 Provisioners: map[string]ResourceProvisionerFactory{ 2143 "shell": testProvisionerFuncFixed(pr), 2144 }, 2145 }) 2146 2147 if _, err := ctx.Plan(); err != nil { 2148 t.Fatalf("err: %s", err) 2149 } 2150 2151 state, err := ctx.Apply() 2152 if err != nil { 2153 t.Fatalf("err: %s", err) 2154 } 2155 2156 actual := strings.TrimSpace(state.String()) 2157 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 2158 if actual != expected { 2159 t.Fatalf("bad: \n%s", actual) 2160 } 2161 2162 // Verify apply was invoked 2163 if !pr.ApplyCalled { 2164 t.Fatalf("provisioner not invoked") 2165 } 2166 pr.ApplyCalled = false 2167 2168 // Change the state to force a diff 2169 mod := state.RootModule() 2170 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 2171 2172 // Re-create context with state 2173 ctx = testContext2(t, &ContextOpts{ 2174 Module: m, 2175 Providers: map[string]ResourceProviderFactory{ 2176 "aws": testProviderFuncFixed(p), 2177 }, 2178 Provisioners: map[string]ResourceProvisionerFactory{ 2179 "shell": testProvisionerFuncFixed(pr), 2180 }, 2181 State: state, 2182 }) 2183 2184 if _, err := ctx.Plan(); err != nil { 2185 t.Fatalf("err: %s", err) 2186 } 2187 2188 state2, err := ctx.Apply() 2189 if err != nil { 2190 t.Fatalf("err: %s", err) 2191 } 2192 2193 actual = strings.TrimSpace(state2.String()) 2194 if actual != expected { 2195 t.Fatalf("bad: \n%s", actual) 2196 } 2197 2198 // Verify apply was NOT invoked 2199 if pr.ApplyCalled { 2200 t.Fatalf("provisioner invoked") 2201 } 2202 } 2203 2204 func TestContext2Apply_outputDiffVars(t *testing.T) { 2205 m := testModule(t, "apply-good") 2206 p := testProvider("aws") 2207 s := &State{ 2208 Modules: []*ModuleState{ 2209 &ModuleState{ 2210 Path: rootModulePath, 2211 Resources: map[string]*ResourceState{ 2212 "aws_instance.baz": &ResourceState{ 2213 Type: "aws_instance", 2214 Primary: &InstanceState{ 2215 ID: "bar", 2216 }, 2217 }, 2218 }, 2219 }, 2220 }, 2221 } 2222 ctx := testContext2(t, &ContextOpts{ 2223 Module: m, 2224 Providers: map[string]ResourceProviderFactory{ 2225 "aws": testProviderFuncFixed(p), 2226 }, 2227 State: s, 2228 }) 2229 2230 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2231 for k, ad := range d.Attributes { 2232 if ad.NewComputed { 2233 return nil, fmt.Errorf("%s: computed", k) 2234 } 2235 } 2236 2237 result := s.MergeDiff(d) 2238 result.ID = "foo" 2239 return result, nil 2240 } 2241 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2242 return &InstanceDiff{ 2243 Attributes: map[string]*ResourceAttrDiff{ 2244 "foo": &ResourceAttrDiff{ 2245 NewComputed: true, 2246 Type: DiffAttrOutput, 2247 }, 2248 "bar": &ResourceAttrDiff{ 2249 New: "baz", 2250 }, 2251 }, 2252 }, nil 2253 } 2254 2255 if _, err := ctx.Plan(); err != nil { 2256 t.Fatalf("err: %s", err) 2257 } 2258 if _, err := ctx.Apply(); err != nil { 2259 t.Fatalf("err: %s", err) 2260 } 2261 } 2262 2263 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 2264 m := testModule(t, "apply-provisioner-conninfo") 2265 p := testProvider("aws") 2266 pr := testProvisioner() 2267 2268 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2269 if s.Ephemeral.ConnInfo == nil { 2270 t.Fatalf("ConnInfo not initialized") 2271 } 2272 2273 result, _ := testApplyFn(info, s, d) 2274 result.Ephemeral.ConnInfo = map[string]string{ 2275 "type": "ssh", 2276 "host": "127.0.0.1", 2277 "port": "22", 2278 } 2279 return result, nil 2280 } 2281 p.DiffFn = testDiffFn 2282 2283 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2284 conn := rs.Ephemeral.ConnInfo 2285 if conn["type"] != "telnet" { 2286 t.Fatalf("Bad: %#v", conn) 2287 } 2288 if conn["host"] != "127.0.0.1" { 2289 t.Fatalf("Bad: %#v", conn) 2290 } 2291 if conn["port"] != "2222" { 2292 t.Fatalf("Bad: %#v", conn) 2293 } 2294 if conn["user"] != "superuser" { 2295 t.Fatalf("Bad: %#v", conn) 2296 } 2297 if conn["pass"] != "test" { 2298 t.Fatalf("Bad: %#v", conn) 2299 } 2300 2301 return nil 2302 } 2303 2304 ctx := testContext2(t, &ContextOpts{ 2305 Module: m, 2306 Providers: map[string]ResourceProviderFactory{ 2307 "aws": testProviderFuncFixed(p), 2308 }, 2309 Provisioners: map[string]ResourceProvisionerFactory{ 2310 "shell": testProvisionerFuncFixed(pr), 2311 }, 2312 Variables: map[string]string{ 2313 "value": "1", 2314 "pass": "test", 2315 }, 2316 }) 2317 2318 if _, err := ctx.Plan(); err != nil { 2319 t.Fatalf("err: %s", err) 2320 } 2321 2322 state, err := ctx.Apply() 2323 if err != nil { 2324 t.Fatalf("err: %s", err) 2325 } 2326 2327 actual := strings.TrimSpace(state.String()) 2328 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 2329 if actual != expected { 2330 t.Fatalf("bad: \n%s", actual) 2331 } 2332 2333 // Verify apply was invoked 2334 if !pr.ApplyCalled { 2335 t.Fatalf("provisioner not invoked") 2336 } 2337 } 2338 2339 func TestContext2Apply_destroy(t *testing.T) { 2340 m := testModule(t, "apply-destroy") 2341 h := new(HookRecordApplyOrder) 2342 p := testProvider("aws") 2343 p.ApplyFn = testApplyFn 2344 p.DiffFn = testDiffFn 2345 ctx := testContext2(t, &ContextOpts{ 2346 Module: m, 2347 Hooks: []Hook{h}, 2348 Providers: map[string]ResourceProviderFactory{ 2349 "aws": testProviderFuncFixed(p), 2350 }, 2351 }) 2352 2353 // First plan and apply a create operation 2354 if _, err := ctx.Plan(); err != nil { 2355 t.Fatalf("err: %s", err) 2356 } 2357 2358 state, err := ctx.Apply() 2359 if err != nil { 2360 t.Fatalf("err: %s", err) 2361 } 2362 2363 // Next, plan and apply a destroy operation 2364 h.Active = true 2365 ctx = testContext2(t, &ContextOpts{ 2366 Destroy: true, 2367 State: state, 2368 Module: m, 2369 Hooks: []Hook{h}, 2370 Providers: map[string]ResourceProviderFactory{ 2371 "aws": testProviderFuncFixed(p), 2372 }, 2373 }) 2374 2375 if _, err := ctx.Plan(); err != nil { 2376 t.Fatalf("err: %s", err) 2377 } 2378 2379 state, err = ctx.Apply() 2380 if err != nil { 2381 t.Fatalf("err: %s", err) 2382 } 2383 2384 // Test that things were destroyed 2385 actual := strings.TrimSpace(state.String()) 2386 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 2387 if actual != expected { 2388 t.Fatalf("bad: \n%s", actual) 2389 } 2390 2391 // Test that things were destroyed _in the right order_ 2392 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 2393 actual2 := h.IDs 2394 if !reflect.DeepEqual(actual2, expected2) { 2395 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 2396 } 2397 } 2398 2399 func TestContext2Apply_destroyNestedModule(t *testing.T) { 2400 m := testModule(t, "apply-destroy-nested-module") 2401 p := testProvider("aws") 2402 p.ApplyFn = testApplyFn 2403 p.DiffFn = testDiffFn 2404 2405 s := &State{ 2406 Modules: []*ModuleState{ 2407 &ModuleState{ 2408 Path: []string{"root", "child", "subchild"}, 2409 Resources: map[string]*ResourceState{ 2410 "aws_instance.bar": &ResourceState{ 2411 Type: "aws_instance", 2412 Primary: &InstanceState{ 2413 ID: "bar", 2414 }, 2415 }, 2416 }, 2417 }, 2418 }, 2419 } 2420 2421 ctx := testContext2(t, &ContextOpts{ 2422 Module: m, 2423 Providers: map[string]ResourceProviderFactory{ 2424 "aws": testProviderFuncFixed(p), 2425 }, 2426 State: s, 2427 }) 2428 2429 // First plan and apply a create operation 2430 if _, err := ctx.Plan(); err != nil { 2431 t.Fatalf("err: %s", err) 2432 } 2433 2434 state, err := ctx.Apply() 2435 if err != nil { 2436 t.Fatalf("err: %s", err) 2437 } 2438 2439 // Test that things were destroyed 2440 actual := strings.TrimSpace(state.String()) 2441 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 2442 if actual != expected { 2443 t.Fatalf("bad: \n%s", actual) 2444 } 2445 } 2446 2447 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 2448 m := testModule(t, "apply-destroy-deeply-nested-module") 2449 p := testProvider("aws") 2450 p.ApplyFn = testApplyFn 2451 p.DiffFn = testDiffFn 2452 2453 s := &State{ 2454 Modules: []*ModuleState{ 2455 &ModuleState{ 2456 Path: []string{"root", "child", "subchild", "subsubchild"}, 2457 Resources: map[string]*ResourceState{ 2458 "aws_instance.bar": &ResourceState{ 2459 Type: "aws_instance", 2460 Primary: &InstanceState{ 2461 ID: "bar", 2462 }, 2463 }, 2464 }, 2465 }, 2466 }, 2467 } 2468 2469 ctx := testContext2(t, &ContextOpts{ 2470 Module: m, 2471 Providers: map[string]ResourceProviderFactory{ 2472 "aws": testProviderFuncFixed(p), 2473 }, 2474 State: s, 2475 }) 2476 2477 // First plan and apply a create operation 2478 if _, err := ctx.Plan(); err != nil { 2479 t.Fatalf("err: %s", err) 2480 } 2481 2482 state, err := ctx.Apply() 2483 if err != nil { 2484 t.Fatalf("err: %s", err) 2485 } 2486 2487 // Test that things were destroyed 2488 actual := strings.TrimSpace(state.String()) 2489 expected := strings.TrimSpace(` 2490 module.child.subchild.subsubchild: 2491 <no state> 2492 `) 2493 if actual != expected { 2494 t.Fatalf("bad: \n%s", actual) 2495 } 2496 } 2497 2498 func TestContext2Apply_destroyOutputs(t *testing.T) { 2499 m := testModule(t, "apply-destroy-outputs") 2500 h := new(HookRecordApplyOrder) 2501 p := testProvider("aws") 2502 p.ApplyFn = testApplyFn 2503 p.DiffFn = testDiffFn 2504 ctx := testContext2(t, &ContextOpts{ 2505 Module: m, 2506 Hooks: []Hook{h}, 2507 Providers: map[string]ResourceProviderFactory{ 2508 "aws": testProviderFuncFixed(p), 2509 }, 2510 }) 2511 2512 // First plan and apply a create operation 2513 if _, err := ctx.Plan(); err != nil { 2514 t.Fatalf("err: %s", err) 2515 } 2516 2517 state, err := ctx.Apply() 2518 2519 if err != nil { 2520 t.Fatalf("err: %s", err) 2521 } 2522 2523 // Next, plan and apply a destroy operation 2524 h.Active = true 2525 ctx = testContext2(t, &ContextOpts{ 2526 Destroy: true, 2527 State: state, 2528 Module: m, 2529 Hooks: []Hook{h}, 2530 Providers: map[string]ResourceProviderFactory{ 2531 "aws": testProviderFuncFixed(p), 2532 }, 2533 }) 2534 2535 if _, err := ctx.Plan(); err != nil { 2536 t.Fatalf("err: %s", err) 2537 } 2538 2539 state, err = ctx.Apply() 2540 if err != nil { 2541 t.Fatalf("err: %s", err) 2542 } 2543 2544 mod := state.RootModule() 2545 if len(mod.Resources) > 0 { 2546 t.Fatalf("bad: %#v", mod) 2547 } 2548 } 2549 2550 func TestContext2Apply_destroyOrphan(t *testing.T) { 2551 m := testModule(t, "apply-error") 2552 p := testProvider("aws") 2553 s := &State{ 2554 Modules: []*ModuleState{ 2555 &ModuleState{ 2556 Path: rootModulePath, 2557 Resources: map[string]*ResourceState{ 2558 "aws_instance.baz": &ResourceState{ 2559 Type: "aws_instance", 2560 Primary: &InstanceState{ 2561 ID: "bar", 2562 }, 2563 }, 2564 }, 2565 }, 2566 }, 2567 } 2568 ctx := testContext2(t, &ContextOpts{ 2569 Module: m, 2570 Providers: map[string]ResourceProviderFactory{ 2571 "aws": testProviderFuncFixed(p), 2572 }, 2573 State: s, 2574 }) 2575 2576 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2577 if d.Destroy { 2578 return nil, nil 2579 } 2580 2581 result := s.MergeDiff(d) 2582 result.ID = "foo" 2583 return result, nil 2584 } 2585 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2586 return &InstanceDiff{ 2587 Attributes: map[string]*ResourceAttrDiff{ 2588 "num": &ResourceAttrDiff{ 2589 New: "bar", 2590 }, 2591 }, 2592 }, nil 2593 } 2594 2595 if _, err := ctx.Plan(); err != nil { 2596 t.Fatalf("err: %s", err) 2597 } 2598 2599 state, err := ctx.Apply() 2600 if err != nil { 2601 t.Fatalf("err: %s", err) 2602 } 2603 2604 mod := state.RootModule() 2605 if _, ok := mod.Resources["aws_instance.baz"]; ok { 2606 t.Fatalf("bad: %#v", mod.Resources) 2607 } 2608 } 2609 2610 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 2611 m := testModule(t, "apply-destroy-provisioner") 2612 p := testProvider("aws") 2613 pr := testProvisioner() 2614 p.ApplyFn = testApplyFn 2615 p.DiffFn = testDiffFn 2616 2617 called := false 2618 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2619 called = true 2620 return nil 2621 } 2622 2623 s := &State{ 2624 Modules: []*ModuleState{ 2625 &ModuleState{ 2626 Path: rootModulePath, 2627 Resources: map[string]*ResourceState{ 2628 "aws_instance.foo": &ResourceState{ 2629 Type: "aws_instance", 2630 Tainted: []*InstanceState{ 2631 &InstanceState{ 2632 ID: "bar", 2633 Attributes: map[string]string{ 2634 "id": "bar", 2635 }, 2636 }, 2637 }, 2638 }, 2639 }, 2640 }, 2641 }, 2642 } 2643 2644 ctx := testContext2(t, &ContextOpts{ 2645 Module: m, 2646 Providers: map[string]ResourceProviderFactory{ 2647 "aws": testProviderFuncFixed(p), 2648 }, 2649 Provisioners: map[string]ResourceProvisionerFactory{ 2650 "shell": testProvisionerFuncFixed(pr), 2651 }, 2652 State: s, 2653 Destroy: true, 2654 }) 2655 2656 if _, err := ctx.Plan(); err != nil { 2657 t.Fatalf("err: %s", err) 2658 } 2659 2660 state, err := ctx.Apply() 2661 if err != nil { 2662 t.Fatalf("err: %s", err) 2663 } 2664 2665 if called { 2666 t.Fatal("provisioner should not be called") 2667 } 2668 2669 actual := strings.TrimSpace(state.String()) 2670 expected := strings.TrimSpace("<no state>") 2671 if actual != expected { 2672 t.Fatalf("bad: \n%s", actual) 2673 } 2674 } 2675 2676 func TestContext2Apply_error(t *testing.T) { 2677 errored := false 2678 2679 m := testModule(t, "apply-error") 2680 p := testProvider("aws") 2681 ctx := testContext2(t, &ContextOpts{ 2682 Module: m, 2683 Providers: map[string]ResourceProviderFactory{ 2684 "aws": testProviderFuncFixed(p), 2685 }, 2686 }) 2687 2688 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 2689 if errored { 2690 state := &InstanceState{ 2691 ID: "bar", 2692 } 2693 return state, fmt.Errorf("error") 2694 } 2695 errored = true 2696 2697 return &InstanceState{ 2698 ID: "foo", 2699 Attributes: map[string]string{ 2700 "num": "2", 2701 }, 2702 }, nil 2703 } 2704 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2705 return &InstanceDiff{ 2706 Attributes: map[string]*ResourceAttrDiff{ 2707 "num": &ResourceAttrDiff{ 2708 New: "bar", 2709 }, 2710 }, 2711 }, nil 2712 } 2713 2714 if _, err := ctx.Plan(); err != nil { 2715 t.Fatalf("err: %s", err) 2716 } 2717 2718 state, err := ctx.Apply() 2719 if err == nil { 2720 t.Fatal("should have error") 2721 } 2722 2723 actual := strings.TrimSpace(state.String()) 2724 expected := strings.TrimSpace(testTerraformApplyErrorStr) 2725 if actual != expected { 2726 t.Fatalf("bad: \n%s", actual) 2727 } 2728 } 2729 2730 func TestContext2Apply_errorPartial(t *testing.T) { 2731 errored := false 2732 2733 m := testModule(t, "apply-error") 2734 p := testProvider("aws") 2735 s := &State{ 2736 Modules: []*ModuleState{ 2737 &ModuleState{ 2738 Path: rootModulePath, 2739 Resources: map[string]*ResourceState{ 2740 "aws_instance.bar": &ResourceState{ 2741 Type: "aws_instance", 2742 Primary: &InstanceState{ 2743 ID: "bar", 2744 }, 2745 }, 2746 }, 2747 }, 2748 }, 2749 } 2750 ctx := testContext2(t, &ContextOpts{ 2751 Module: m, 2752 Providers: map[string]ResourceProviderFactory{ 2753 "aws": testProviderFuncFixed(p), 2754 }, 2755 State: s, 2756 }) 2757 2758 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2759 if errored { 2760 return s, fmt.Errorf("error") 2761 } 2762 errored = true 2763 2764 return &InstanceState{ 2765 ID: "foo", 2766 Attributes: map[string]string{ 2767 "num": "2", 2768 }, 2769 }, nil 2770 } 2771 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2772 return &InstanceDiff{ 2773 Attributes: map[string]*ResourceAttrDiff{ 2774 "num": &ResourceAttrDiff{ 2775 New: "bar", 2776 }, 2777 }, 2778 }, nil 2779 } 2780 2781 if _, err := ctx.Plan(); err != nil { 2782 t.Fatalf("err: %s", err) 2783 } 2784 2785 state, err := ctx.Apply() 2786 if err == nil { 2787 t.Fatal("should have error") 2788 } 2789 2790 mod := state.RootModule() 2791 if len(mod.Resources) != 2 { 2792 t.Fatalf("bad: %#v", mod.Resources) 2793 } 2794 2795 actual := strings.TrimSpace(state.String()) 2796 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 2797 if actual != expected { 2798 t.Fatalf("bad: \n%s", actual) 2799 } 2800 } 2801 2802 func TestContext2Apply_hook(t *testing.T) { 2803 m := testModule(t, "apply-good") 2804 h := new(MockHook) 2805 p := testProvider("aws") 2806 p.ApplyFn = testApplyFn 2807 p.DiffFn = testDiffFn 2808 ctx := testContext2(t, &ContextOpts{ 2809 Module: m, 2810 Hooks: []Hook{h}, 2811 Providers: map[string]ResourceProviderFactory{ 2812 "aws": testProviderFuncFixed(p), 2813 }, 2814 }) 2815 2816 if _, err := ctx.Plan(); err != nil { 2817 t.Fatalf("err: %s", err) 2818 } 2819 2820 if _, err := ctx.Apply(); err != nil { 2821 t.Fatalf("err: %s", err) 2822 } 2823 2824 if !h.PreApplyCalled { 2825 t.Fatal("should be called") 2826 } 2827 if !h.PostApplyCalled { 2828 t.Fatal("should be called") 2829 } 2830 if !h.PostStateUpdateCalled { 2831 t.Fatalf("should call post state update") 2832 } 2833 } 2834 2835 func TestContext2Apply_hookOrphan(t *testing.T) { 2836 m := testModule(t, "apply-blank") 2837 h := new(MockHook) 2838 p := testProvider("aws") 2839 p.ApplyFn = testApplyFn 2840 p.DiffFn = testDiffFn 2841 2842 state := &State{ 2843 Modules: []*ModuleState{ 2844 &ModuleState{ 2845 Path: rootModulePath, 2846 Resources: map[string]*ResourceState{ 2847 "aws_instance.bar": &ResourceState{ 2848 Type: "aws_instance", 2849 Primary: &InstanceState{ 2850 ID: "bar", 2851 }, 2852 }, 2853 }, 2854 }, 2855 }, 2856 } 2857 2858 ctx := testContext2(t, &ContextOpts{ 2859 Module: m, 2860 State: state, 2861 Hooks: []Hook{h}, 2862 Providers: map[string]ResourceProviderFactory{ 2863 "aws": testProviderFuncFixed(p), 2864 }, 2865 }) 2866 2867 if _, err := ctx.Plan(); err != nil { 2868 t.Fatalf("err: %s", err) 2869 } 2870 2871 if _, err := ctx.Apply(); err != nil { 2872 t.Fatalf("err: %s", err) 2873 } 2874 2875 if !h.PreApplyCalled { 2876 t.Fatal("should be called") 2877 } 2878 if !h.PostApplyCalled { 2879 t.Fatal("should be called") 2880 } 2881 if !h.PostStateUpdateCalled { 2882 t.Fatalf("should call post state update") 2883 } 2884 } 2885 2886 func TestContext2Apply_idAttr(t *testing.T) { 2887 m := testModule(t, "apply-idattr") 2888 p := testProvider("aws") 2889 ctx := testContext2(t, &ContextOpts{ 2890 Module: m, 2891 Providers: map[string]ResourceProviderFactory{ 2892 "aws": testProviderFuncFixed(p), 2893 }, 2894 }) 2895 2896 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 2897 result := s.MergeDiff(d) 2898 result.ID = "foo" 2899 result.Attributes = map[string]string{ 2900 "id": "bar", 2901 } 2902 2903 return result, nil 2904 } 2905 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2906 return &InstanceDiff{ 2907 Attributes: map[string]*ResourceAttrDiff{ 2908 "num": &ResourceAttrDiff{ 2909 New: "bar", 2910 }, 2911 }, 2912 }, nil 2913 } 2914 2915 if _, err := ctx.Plan(); err != nil { 2916 t.Fatalf("err: %s", err) 2917 } 2918 2919 state, err := ctx.Apply() 2920 if err != nil { 2921 t.Fatalf("err: %s", err) 2922 } 2923 2924 mod := state.RootModule() 2925 rs, ok := mod.Resources["aws_instance.foo"] 2926 if !ok { 2927 t.Fatal("not in state") 2928 } 2929 if rs.Primary.ID != "foo" { 2930 t.Fatalf("bad: %#v", rs.Primary.ID) 2931 } 2932 if rs.Primary.Attributes["id"] != "foo" { 2933 t.Fatalf("bad: %#v", rs.Primary.Attributes) 2934 } 2935 } 2936 2937 func TestContext2Apply_output(t *testing.T) { 2938 m := testModule(t, "apply-output") 2939 p := testProvider("aws") 2940 p.ApplyFn = testApplyFn 2941 p.DiffFn = testDiffFn 2942 ctx := testContext2(t, &ContextOpts{ 2943 Module: m, 2944 Providers: map[string]ResourceProviderFactory{ 2945 "aws": testProviderFuncFixed(p), 2946 }, 2947 }) 2948 2949 if _, err := ctx.Plan(); err != nil { 2950 t.Fatalf("err: %s", err) 2951 } 2952 2953 state, err := ctx.Apply() 2954 if err != nil { 2955 t.Fatalf("err: %s", err) 2956 } 2957 2958 actual := strings.TrimSpace(state.String()) 2959 expected := strings.TrimSpace(testTerraformApplyOutputStr) 2960 if actual != expected { 2961 t.Fatalf("bad: \n%s", actual) 2962 } 2963 } 2964 2965 func TestContext2Apply_outputInvalid(t *testing.T) { 2966 m := testModule(t, "apply-output-invalid") 2967 p := testProvider("aws") 2968 p.ApplyFn = testApplyFn 2969 p.DiffFn = testDiffFn 2970 ctx := testContext2(t, &ContextOpts{ 2971 Module: m, 2972 Providers: map[string]ResourceProviderFactory{ 2973 "aws": testProviderFuncFixed(p), 2974 }, 2975 }) 2976 2977 _, err := ctx.Plan() 2978 if err == nil { 2979 t.Fatalf("err: %s", err) 2980 } 2981 if !strings.Contains(err.Error(), "is not a string") { 2982 t.Fatalf("err: %s", err) 2983 } 2984 } 2985 2986 func TestContext2Apply_outputAdd(t *testing.T) { 2987 m1 := testModule(t, "apply-output-add-before") 2988 p1 := testProvider("aws") 2989 p1.ApplyFn = testApplyFn 2990 p1.DiffFn = testDiffFn 2991 ctx1 := testContext2(t, &ContextOpts{ 2992 Module: m1, 2993 Providers: map[string]ResourceProviderFactory{ 2994 "aws": testProviderFuncFixed(p1), 2995 }, 2996 }) 2997 2998 if _, err := ctx1.Plan(); err != nil { 2999 t.Fatalf("err: %s", err) 3000 } 3001 3002 state1, err := ctx1.Apply() 3003 if err != nil { 3004 t.Fatalf("err: %s", err) 3005 } 3006 3007 m2 := testModule(t, "apply-output-add-after") 3008 p2 := testProvider("aws") 3009 p2.ApplyFn = testApplyFn 3010 p2.DiffFn = testDiffFn 3011 ctx2 := testContext2(t, &ContextOpts{ 3012 Module: m2, 3013 Providers: map[string]ResourceProviderFactory{ 3014 "aws": testProviderFuncFixed(p2), 3015 }, 3016 State: state1, 3017 }) 3018 3019 if _, err := ctx2.Plan(); err != nil { 3020 t.Fatalf("err: %s", err) 3021 } 3022 3023 state2, err := ctx2.Apply() 3024 if err != nil { 3025 t.Fatalf("err: %s", err) 3026 } 3027 3028 actual := strings.TrimSpace(state2.String()) 3029 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 3030 if actual != expected { 3031 t.Fatalf("bad: \n%s", actual) 3032 } 3033 } 3034 3035 func TestContext2Apply_outputList(t *testing.T) { 3036 m := testModule(t, "apply-output-list") 3037 p := testProvider("aws") 3038 p.ApplyFn = testApplyFn 3039 p.DiffFn = testDiffFn 3040 ctx := testContext2(t, &ContextOpts{ 3041 Module: m, 3042 Providers: map[string]ResourceProviderFactory{ 3043 "aws": testProviderFuncFixed(p), 3044 }, 3045 }) 3046 3047 if _, err := ctx.Plan(); err != nil { 3048 t.Fatalf("err: %s", err) 3049 } 3050 3051 state, err := ctx.Apply() 3052 if err != nil { 3053 t.Fatalf("err: %s", err) 3054 } 3055 3056 actual := strings.TrimSpace(state.String()) 3057 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 3058 if actual != expected { 3059 t.Fatalf("bad: \n%s", actual) 3060 } 3061 } 3062 3063 func TestContext2Apply_outputMulti(t *testing.T) { 3064 m := testModule(t, "apply-output-multi") 3065 p := testProvider("aws") 3066 p.ApplyFn = testApplyFn 3067 p.DiffFn = testDiffFn 3068 ctx := testContext2(t, &ContextOpts{ 3069 Module: m, 3070 Providers: map[string]ResourceProviderFactory{ 3071 "aws": testProviderFuncFixed(p), 3072 }, 3073 }) 3074 3075 if _, err := ctx.Plan(); err != nil { 3076 t.Fatalf("err: %s", err) 3077 } 3078 3079 state, err := ctx.Apply() 3080 if err != nil { 3081 t.Fatalf("err: %s", err) 3082 } 3083 3084 actual := strings.TrimSpace(state.String()) 3085 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 3086 if actual != expected { 3087 t.Fatalf("bad: \n%s", actual) 3088 } 3089 } 3090 3091 func TestContext2Apply_outputMultiIndex(t *testing.T) { 3092 m := testModule(t, "apply-output-multi-index") 3093 p := testProvider("aws") 3094 p.ApplyFn = testApplyFn 3095 p.DiffFn = testDiffFn 3096 ctx := testContext2(t, &ContextOpts{ 3097 Module: m, 3098 Providers: map[string]ResourceProviderFactory{ 3099 "aws": testProviderFuncFixed(p), 3100 }, 3101 }) 3102 3103 if _, err := ctx.Plan(); err != nil { 3104 t.Fatalf("err: %s", err) 3105 } 3106 3107 state, err := ctx.Apply() 3108 if err != nil { 3109 t.Fatalf("err: %s", err) 3110 } 3111 3112 actual := strings.TrimSpace(state.String()) 3113 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 3114 if actual != expected { 3115 t.Fatalf("bad: \n%s", actual) 3116 } 3117 } 3118 3119 func TestContext2Apply_taint(t *testing.T) { 3120 m := testModule(t, "apply-taint") 3121 p := testProvider("aws") 3122 3123 // destroyCount tests against regression of 3124 // https://github.com/hashicorp/terraform/issues/1056 3125 var destroyCount = int32(0) 3126 var once sync.Once 3127 simulateProviderDelay := func() { 3128 time.Sleep(10 * time.Millisecond) 3129 } 3130 3131 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3132 once.Do(simulateProviderDelay) 3133 if d.Destroy { 3134 atomic.AddInt32(&destroyCount, 1) 3135 } 3136 return testApplyFn(info, s, d) 3137 } 3138 p.DiffFn = testDiffFn 3139 s := &State{ 3140 Modules: []*ModuleState{ 3141 &ModuleState{ 3142 Path: rootModulePath, 3143 Resources: map[string]*ResourceState{ 3144 "aws_instance.bar": &ResourceState{ 3145 Type: "aws_instance", 3146 Tainted: []*InstanceState{ 3147 &InstanceState{ 3148 ID: "baz", 3149 Attributes: map[string]string{ 3150 "num": "2", 3151 "type": "aws_instance", 3152 }, 3153 }, 3154 }, 3155 }, 3156 }, 3157 }, 3158 }, 3159 } 3160 ctx := testContext2(t, &ContextOpts{ 3161 Module: m, 3162 Providers: map[string]ResourceProviderFactory{ 3163 "aws": testProviderFuncFixed(p), 3164 }, 3165 State: s, 3166 }) 3167 3168 if _, err := ctx.Plan(); err != nil { 3169 t.Fatalf("err: %s", err) 3170 } 3171 3172 state, err := ctx.Apply() 3173 if err != nil { 3174 t.Fatalf("err: %s", err) 3175 } 3176 3177 actual := strings.TrimSpace(state.String()) 3178 expected := strings.TrimSpace(testTerraformApplyTaintStr) 3179 if actual != expected { 3180 t.Fatalf("bad:\n%s", actual) 3181 } 3182 3183 if destroyCount != 1 { 3184 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 3185 } 3186 } 3187 3188 func TestContext2Apply_taintDep(t *testing.T) { 3189 m := testModule(t, "apply-taint-dep") 3190 p := testProvider("aws") 3191 p.ApplyFn = testApplyFn 3192 p.DiffFn = testDiffFn 3193 s := &State{ 3194 Modules: []*ModuleState{ 3195 &ModuleState{ 3196 Path: rootModulePath, 3197 Resources: map[string]*ResourceState{ 3198 "aws_instance.foo": &ResourceState{ 3199 Type: "aws_instance", 3200 Tainted: []*InstanceState{ 3201 &InstanceState{ 3202 ID: "baz", 3203 Attributes: map[string]string{ 3204 "num": "2", 3205 "type": "aws_instance", 3206 }, 3207 }, 3208 }, 3209 }, 3210 "aws_instance.bar": &ResourceState{ 3211 Type: "aws_instance", 3212 Primary: &InstanceState{ 3213 ID: "bar", 3214 Attributes: map[string]string{ 3215 "foo": "baz", 3216 "num": "2", 3217 "type": "aws_instance", 3218 }, 3219 }, 3220 }, 3221 }, 3222 }, 3223 }, 3224 } 3225 ctx := testContext2(t, &ContextOpts{ 3226 Module: m, 3227 Providers: map[string]ResourceProviderFactory{ 3228 "aws": testProviderFuncFixed(p), 3229 }, 3230 State: s, 3231 }) 3232 3233 if p, err := ctx.Plan(); err != nil { 3234 t.Fatalf("err: %s", err) 3235 } else { 3236 t.Logf("plan: %s", p) 3237 } 3238 3239 state, err := ctx.Apply() 3240 if err != nil { 3241 t.Fatalf("err: %s", err) 3242 } 3243 3244 actual := strings.TrimSpace(state.String()) 3245 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 3246 if actual != expected { 3247 t.Fatalf("bad:\n%s", actual) 3248 } 3249 } 3250 3251 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 3252 m := testModule(t, "apply-taint-dep-requires-new") 3253 p := testProvider("aws") 3254 p.ApplyFn = testApplyFn 3255 p.DiffFn = testDiffFn 3256 s := &State{ 3257 Modules: []*ModuleState{ 3258 &ModuleState{ 3259 Path: rootModulePath, 3260 Resources: map[string]*ResourceState{ 3261 "aws_instance.foo": &ResourceState{ 3262 Type: "aws_instance", 3263 Tainted: []*InstanceState{ 3264 &InstanceState{ 3265 ID: "baz", 3266 Attributes: map[string]string{ 3267 "num": "2", 3268 "type": "aws_instance", 3269 }, 3270 }, 3271 }, 3272 }, 3273 "aws_instance.bar": &ResourceState{ 3274 Type: "aws_instance", 3275 Primary: &InstanceState{ 3276 ID: "bar", 3277 Attributes: map[string]string{ 3278 "foo": "baz", 3279 "num": "2", 3280 "type": "aws_instance", 3281 }, 3282 }, 3283 }, 3284 }, 3285 }, 3286 }, 3287 } 3288 ctx := testContext2(t, &ContextOpts{ 3289 Module: m, 3290 Providers: map[string]ResourceProviderFactory{ 3291 "aws": testProviderFuncFixed(p), 3292 }, 3293 State: s, 3294 }) 3295 3296 if p, err := ctx.Plan(); err != nil { 3297 t.Fatalf("err: %s", err) 3298 } else { 3299 t.Logf("plan: %s", p) 3300 } 3301 3302 state, err := ctx.Apply() 3303 if err != nil { 3304 t.Fatalf("err: %s", err) 3305 } 3306 3307 actual := strings.TrimSpace(state.String()) 3308 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 3309 if actual != expected { 3310 t.Fatalf("bad:\n%s", actual) 3311 } 3312 } 3313 3314 func TestContext2Apply_targeted(t *testing.T) { 3315 m := testModule(t, "apply-targeted") 3316 p := testProvider("aws") 3317 p.ApplyFn = testApplyFn 3318 p.DiffFn = testDiffFn 3319 ctx := testContext2(t, &ContextOpts{ 3320 Module: m, 3321 Providers: map[string]ResourceProviderFactory{ 3322 "aws": testProviderFuncFixed(p), 3323 }, 3324 Targets: []string{"aws_instance.foo"}, 3325 }) 3326 3327 if _, err := ctx.Plan(); err != nil { 3328 t.Fatalf("err: %s", err) 3329 } 3330 3331 state, err := ctx.Apply() 3332 if err != nil { 3333 t.Fatalf("err: %s", err) 3334 } 3335 3336 mod := state.RootModule() 3337 if len(mod.Resources) != 1 { 3338 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3339 } 3340 3341 checkStateString(t, state, ` 3342 aws_instance.foo: 3343 ID = foo 3344 num = 2 3345 type = aws_instance 3346 `) 3347 } 3348 3349 func TestContext2Apply_targetedCount(t *testing.T) { 3350 m := testModule(t, "apply-targeted-count") 3351 p := testProvider("aws") 3352 p.ApplyFn = testApplyFn 3353 p.DiffFn = testDiffFn 3354 ctx := testContext2(t, &ContextOpts{ 3355 Module: m, 3356 Providers: map[string]ResourceProviderFactory{ 3357 "aws": testProviderFuncFixed(p), 3358 }, 3359 Targets: []string{"aws_instance.foo"}, 3360 }) 3361 3362 if _, err := ctx.Plan(); err != nil { 3363 t.Fatalf("err: %s", err) 3364 } 3365 3366 state, err := ctx.Apply() 3367 if err != nil { 3368 t.Fatalf("err: %s", err) 3369 } 3370 3371 checkStateString(t, state, ` 3372 aws_instance.foo.0: 3373 ID = foo 3374 aws_instance.foo.1: 3375 ID = foo 3376 aws_instance.foo.2: 3377 ID = foo 3378 `) 3379 } 3380 3381 func TestContext2Apply_targetedCountIndex(t *testing.T) { 3382 m := testModule(t, "apply-targeted-count") 3383 p := testProvider("aws") 3384 p.ApplyFn = testApplyFn 3385 p.DiffFn = testDiffFn 3386 ctx := testContext2(t, &ContextOpts{ 3387 Module: m, 3388 Providers: map[string]ResourceProviderFactory{ 3389 "aws": testProviderFuncFixed(p), 3390 }, 3391 Targets: []string{"aws_instance.foo[1]"}, 3392 }) 3393 3394 if _, err := ctx.Plan(); err != nil { 3395 t.Fatalf("err: %s", err) 3396 } 3397 3398 state, err := ctx.Apply() 3399 if err != nil { 3400 t.Fatalf("err: %s", err) 3401 } 3402 3403 checkStateString(t, state, ` 3404 aws_instance.foo.1: 3405 ID = foo 3406 `) 3407 } 3408 3409 func TestContext2Apply_targetedDestroy(t *testing.T) { 3410 m := testModule(t, "apply-targeted") 3411 p := testProvider("aws") 3412 p.ApplyFn = testApplyFn 3413 p.DiffFn = testDiffFn 3414 ctx := testContext2(t, &ContextOpts{ 3415 Module: m, 3416 Providers: map[string]ResourceProviderFactory{ 3417 "aws": testProviderFuncFixed(p), 3418 }, 3419 State: &State{ 3420 Modules: []*ModuleState{ 3421 &ModuleState{ 3422 Path: rootModulePath, 3423 Resources: map[string]*ResourceState{ 3424 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3425 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3426 }, 3427 }, 3428 }, 3429 }, 3430 Targets: []string{"aws_instance.foo"}, 3431 Destroy: true, 3432 }) 3433 3434 if _, err := ctx.Plan(); err != nil { 3435 t.Fatalf("err: %s", err) 3436 } 3437 3438 state, err := ctx.Apply() 3439 if err != nil { 3440 t.Fatalf("err: %s", err) 3441 } 3442 3443 mod := state.RootModule() 3444 if len(mod.Resources) != 1 { 3445 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3446 } 3447 3448 checkStateString(t, state, ` 3449 aws_instance.bar: 3450 ID = i-abc123 3451 `) 3452 } 3453 3454 // https://github.com/hashicorp/terraform/issues/4462 3455 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 3456 m := testModule(t, "apply-targeted-module") 3457 p := testProvider("aws") 3458 p.ApplyFn = testApplyFn 3459 p.DiffFn = testDiffFn 3460 ctx := testContext2(t, &ContextOpts{ 3461 Module: m, 3462 Providers: map[string]ResourceProviderFactory{ 3463 "aws": testProviderFuncFixed(p), 3464 }, 3465 State: &State{ 3466 Modules: []*ModuleState{ 3467 &ModuleState{ 3468 Path: rootModulePath, 3469 Resources: map[string]*ResourceState{ 3470 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3471 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3472 }, 3473 }, 3474 &ModuleState{ 3475 Path: []string{"root", "child"}, 3476 Resources: map[string]*ResourceState{ 3477 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 3478 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 3479 }, 3480 }, 3481 }, 3482 }, 3483 Targets: []string{"module.child.aws_instance.foo"}, 3484 Destroy: true, 3485 }) 3486 3487 if _, err := ctx.Plan(); err != nil { 3488 t.Fatalf("err: %s", err) 3489 } 3490 3491 state, err := ctx.Apply() 3492 if err != nil { 3493 t.Fatalf("err: %s", err) 3494 } 3495 3496 checkStateString(t, state, ` 3497 aws_instance.bar: 3498 ID = i-abc123 3499 aws_instance.foo: 3500 ID = i-bcd345 3501 3502 module.child: 3503 aws_instance.bar: 3504 ID = i-abc123 3505 `) 3506 } 3507 3508 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 3509 m := testModule(t, "apply-targeted-count") 3510 p := testProvider("aws") 3511 p.ApplyFn = testApplyFn 3512 p.DiffFn = testDiffFn 3513 ctx := testContext2(t, &ContextOpts{ 3514 Module: m, 3515 Providers: map[string]ResourceProviderFactory{ 3516 "aws": testProviderFuncFixed(p), 3517 }, 3518 State: &State{ 3519 Modules: []*ModuleState{ 3520 &ModuleState{ 3521 Path: rootModulePath, 3522 Resources: map[string]*ResourceState{ 3523 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 3524 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 3525 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 3526 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 3527 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 3528 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 3529 }, 3530 }, 3531 }, 3532 }, 3533 Targets: []string{ 3534 "aws_instance.foo[2]", 3535 "aws_instance.bar[1]", 3536 }, 3537 Destroy: true, 3538 }) 3539 3540 if _, err := ctx.Plan(); err != nil { 3541 t.Fatalf("err: %s", err) 3542 } 3543 3544 state, err := ctx.Apply() 3545 if err != nil { 3546 t.Fatalf("err: %s", err) 3547 } 3548 3549 checkStateString(t, state, ` 3550 aws_instance.bar.0: 3551 ID = i-abc123 3552 aws_instance.bar.2: 3553 ID = i-abc123 3554 aws_instance.foo.0: 3555 ID = i-bcd345 3556 aws_instance.foo.1: 3557 ID = i-bcd345 3558 `) 3559 } 3560 3561 func TestContext2Apply_targetedModule(t *testing.T) { 3562 m := testModule(t, "apply-targeted-module") 3563 p := testProvider("aws") 3564 p.ApplyFn = testApplyFn 3565 p.DiffFn = testDiffFn 3566 ctx := testContext2(t, &ContextOpts{ 3567 Module: m, 3568 Providers: map[string]ResourceProviderFactory{ 3569 "aws": testProviderFuncFixed(p), 3570 }, 3571 Targets: []string{"module.child"}, 3572 }) 3573 3574 if _, err := ctx.Plan(); err != nil { 3575 t.Fatalf("err: %s", err) 3576 } 3577 3578 state, err := ctx.Apply() 3579 if err != nil { 3580 t.Fatalf("err: %s", err) 3581 } 3582 3583 mod := state.ModuleByPath([]string{"root", "child"}) 3584 if mod == nil { 3585 t.Fatalf("no child module found in the state!\n\n%#v", state) 3586 } 3587 if len(mod.Resources) != 2 { 3588 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 3589 } 3590 3591 checkStateString(t, state, ` 3592 <no state> 3593 module.child: 3594 aws_instance.bar: 3595 ID = foo 3596 num = 2 3597 type = aws_instance 3598 aws_instance.foo: 3599 ID = foo 3600 num = 2 3601 type = aws_instance 3602 `) 3603 } 3604 3605 // GH-1858 3606 func TestContext2Apply_targetedModuleDep(t *testing.T) { 3607 m := testModule(t, "apply-targeted-module-dep") 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{"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 checkStateString(t, state, ` 3629 aws_instance.foo: 3630 ID = foo 3631 foo = foo 3632 type = aws_instance 3633 3634 Dependencies: 3635 module.child 3636 3637 module.child: 3638 aws_instance.mod: 3639 ID = foo 3640 3641 Outputs: 3642 3643 output = foo 3644 `) 3645 } 3646 3647 func TestContext2Apply_targetedModuleResource(t *testing.T) { 3648 m := testModule(t, "apply-targeted-module-resource") 3649 p := testProvider("aws") 3650 p.ApplyFn = testApplyFn 3651 p.DiffFn = testDiffFn 3652 ctx := testContext2(t, &ContextOpts{ 3653 Module: m, 3654 Providers: map[string]ResourceProviderFactory{ 3655 "aws": testProviderFuncFixed(p), 3656 }, 3657 Targets: []string{"module.child.aws_instance.foo"}, 3658 }) 3659 3660 if _, err := ctx.Plan(); err != nil { 3661 t.Fatalf("err: %s", err) 3662 } 3663 3664 state, err := ctx.Apply() 3665 if err != nil { 3666 t.Fatalf("err: %s", err) 3667 } 3668 3669 mod := state.ModuleByPath([]string{"root", "child"}) 3670 if len(mod.Resources) != 1 { 3671 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 3672 } 3673 3674 checkStateString(t, state, ` 3675 <no state> 3676 module.child: 3677 aws_instance.foo: 3678 ID = foo 3679 num = 2 3680 type = aws_instance 3681 `) 3682 } 3683 3684 func TestContext2Apply_unknownAttribute(t *testing.T) { 3685 m := testModule(t, "apply-unknown") 3686 p := testProvider("aws") 3687 p.ApplyFn = testApplyFn 3688 p.DiffFn = testDiffFn 3689 ctx := testContext2(t, &ContextOpts{ 3690 Module: m, 3691 Providers: map[string]ResourceProviderFactory{ 3692 "aws": testProviderFuncFixed(p), 3693 }, 3694 }) 3695 3696 if _, err := ctx.Plan(); err != nil { 3697 t.Fatalf("err: %s", err) 3698 } 3699 3700 state, err := ctx.Apply() 3701 if err == nil { 3702 t.Fatal("should error") 3703 } 3704 3705 actual := strings.TrimSpace(state.String()) 3706 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 3707 if actual != expected { 3708 t.Fatalf("bad: \n%s", actual) 3709 } 3710 } 3711 3712 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 3713 m := testModule(t, "apply-unknown-interpolate") 3714 p := testProvider("aws") 3715 p.ApplyFn = testApplyFn 3716 p.DiffFn = testDiffFn 3717 ctx := testContext2(t, &ContextOpts{ 3718 Module: m, 3719 Providers: map[string]ResourceProviderFactory{ 3720 "aws": testProviderFuncFixed(p), 3721 }, 3722 }) 3723 3724 if _, err := ctx.Plan(); err == nil { 3725 t.Fatal("should error") 3726 } 3727 } 3728 3729 func TestContext2Apply_vars(t *testing.T) { 3730 m := testModule(t, "apply-vars") 3731 p := testProvider("aws") 3732 p.ApplyFn = testApplyFn 3733 p.DiffFn = testDiffFn 3734 ctx := testContext2(t, &ContextOpts{ 3735 Module: m, 3736 Providers: map[string]ResourceProviderFactory{ 3737 "aws": testProviderFuncFixed(p), 3738 }, 3739 Variables: map[string]string{ 3740 "foo": "us-west-2", 3741 "amis.us-east-1": "override", 3742 }, 3743 }) 3744 3745 w, e := ctx.Validate() 3746 if len(w) > 0 { 3747 t.Fatalf("bad: %#v", w) 3748 } 3749 if len(e) > 0 { 3750 t.Fatalf("bad: %s", e) 3751 } 3752 3753 if _, err := ctx.Plan(); err != nil { 3754 t.Fatalf("err: %s", err) 3755 } 3756 3757 state, err := ctx.Apply() 3758 if err != nil { 3759 t.Fatalf("err: %s", err) 3760 } 3761 3762 actual := strings.TrimSpace(state.String()) 3763 expected := strings.TrimSpace(testTerraformApplyVarsStr) 3764 if actual != expected { 3765 t.Fatalf("bad: \n%s", actual) 3766 } 3767 } 3768 3769 func TestContext2Apply_varsEnv(t *testing.T) { 3770 // Set the env var 3771 old := tempEnv(t, "TF_VAR_ami", "baz") 3772 defer os.Setenv("TF_VAR_ami", old) 3773 3774 m := testModule(t, "apply-vars-env") 3775 p := testProvider("aws") 3776 p.ApplyFn = testApplyFn 3777 p.DiffFn = testDiffFn 3778 ctx := testContext2(t, &ContextOpts{ 3779 Module: m, 3780 Providers: map[string]ResourceProviderFactory{ 3781 "aws": testProviderFuncFixed(p), 3782 }, 3783 }) 3784 3785 w, e := ctx.Validate() 3786 if len(w) > 0 { 3787 t.Fatalf("bad: %#v", w) 3788 } 3789 if len(e) > 0 { 3790 t.Fatalf("bad: %s", e) 3791 } 3792 3793 if _, err := ctx.Plan(); err != nil { 3794 t.Fatalf("err: %s", err) 3795 } 3796 3797 state, err := ctx.Apply() 3798 if err != nil { 3799 t.Fatalf("err: %s", err) 3800 } 3801 3802 actual := strings.TrimSpace(state.String()) 3803 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 3804 if actual != expected { 3805 t.Fatalf("bad: \n%s", actual) 3806 } 3807 } 3808 3809 func TestContext2Apply_createBefore_depends(t *testing.T) { 3810 m := testModule(t, "apply-depends-create-before") 3811 h := new(HookRecordApplyOrder) 3812 p := testProvider("aws") 3813 p.ApplyFn = testApplyFn 3814 p.DiffFn = testDiffFn 3815 state := &State{ 3816 Modules: []*ModuleState{ 3817 &ModuleState{ 3818 Path: rootModulePath, 3819 Resources: map[string]*ResourceState{ 3820 "aws_instance.web": &ResourceState{ 3821 Type: "aws_instance", 3822 Primary: &InstanceState{ 3823 ID: "bar", 3824 Attributes: map[string]string{ 3825 "require_new": "ami-old", 3826 }, 3827 }, 3828 }, 3829 "aws_instance.lb": &ResourceState{ 3830 Type: "aws_instance", 3831 Primary: &InstanceState{ 3832 ID: "baz", 3833 Attributes: map[string]string{ 3834 "instance": "bar", 3835 }, 3836 }, 3837 }, 3838 }, 3839 }, 3840 }, 3841 } 3842 ctx := testContext2(t, &ContextOpts{ 3843 Module: m, 3844 Hooks: []Hook{h}, 3845 Providers: map[string]ResourceProviderFactory{ 3846 "aws": testProviderFuncFixed(p), 3847 }, 3848 State: state, 3849 }) 3850 3851 if _, err := ctx.Plan(); err != nil { 3852 t.Fatalf("err: %s", err) 3853 } 3854 3855 h.Active = true 3856 state, err := ctx.Apply() 3857 if err != nil { 3858 t.Fatalf("err: %s", err) 3859 } 3860 3861 mod := state.RootModule() 3862 if len(mod.Resources) < 2 { 3863 t.Fatalf("bad: %#v", mod.Resources) 3864 } 3865 3866 actual := strings.TrimSpace(state.String()) 3867 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 3868 if actual != expected { 3869 t.Fatalf("bad: \n%s\n%s", actual, expected) 3870 } 3871 3872 // Test that things were managed _in the right order_ 3873 order := h.States 3874 diffs := h.Diffs 3875 if order[0].ID != "" || diffs[0].Destroy { 3876 t.Fatalf("should create new instance first: %#v", order) 3877 } 3878 3879 if order[1].ID != "baz" { 3880 t.Fatalf("update must happen after create: %#v", order) 3881 } 3882 3883 if order[2].ID != "bar" || !diffs[2].Destroy { 3884 t.Fatalf("destroy must happen after update: %#v", order) 3885 } 3886 } 3887 3888 func TestContext2Apply_singleDestroy(t *testing.T) { 3889 m := testModule(t, "apply-depends-create-before") 3890 h := new(HookRecordApplyOrder) 3891 p := testProvider("aws") 3892 3893 invokeCount := 0 3894 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3895 invokeCount++ 3896 switch invokeCount { 3897 case 1: 3898 if d.Destroy { 3899 t.Fatalf("should not destroy") 3900 } 3901 if s.ID != "" { 3902 t.Fatalf("should not have ID") 3903 } 3904 case 2: 3905 if d.Destroy { 3906 t.Fatalf("should not destroy") 3907 } 3908 if s.ID != "baz" { 3909 t.Fatalf("should have id") 3910 } 3911 case 3: 3912 if !d.Destroy { 3913 t.Fatalf("should destroy") 3914 } 3915 if s.ID == "" { 3916 t.Fatalf("should have ID") 3917 } 3918 default: 3919 t.Fatalf("bad invoke count %d", invokeCount) 3920 } 3921 return testApplyFn(info, s, d) 3922 } 3923 p.DiffFn = testDiffFn 3924 state := &State{ 3925 Modules: []*ModuleState{ 3926 &ModuleState{ 3927 Path: rootModulePath, 3928 Resources: map[string]*ResourceState{ 3929 "aws_instance.web": &ResourceState{ 3930 Type: "aws_instance", 3931 Primary: &InstanceState{ 3932 ID: "bar", 3933 Attributes: map[string]string{ 3934 "require_new": "ami-old", 3935 }, 3936 }, 3937 }, 3938 "aws_instance.lb": &ResourceState{ 3939 Type: "aws_instance", 3940 Primary: &InstanceState{ 3941 ID: "baz", 3942 Attributes: map[string]string{ 3943 "instance": "bar", 3944 }, 3945 }, 3946 }, 3947 }, 3948 }, 3949 }, 3950 } 3951 ctx := testContext2(t, &ContextOpts{ 3952 Module: m, 3953 Hooks: []Hook{h}, 3954 Providers: map[string]ResourceProviderFactory{ 3955 "aws": testProviderFuncFixed(p), 3956 }, 3957 State: state, 3958 }) 3959 3960 if _, err := ctx.Plan(); err != nil { 3961 t.Fatalf("err: %s", err) 3962 } 3963 3964 h.Active = true 3965 state, err := ctx.Apply() 3966 if err != nil { 3967 t.Fatalf("err: %s", err) 3968 } 3969 3970 if invokeCount != 3 { 3971 t.Fatalf("bad: %d", invokeCount) 3972 } 3973 } 3974 3975 // GH-5254 3976 func TestContext2Apply_issue5254(t *testing.T) { 3977 // Create a provider. We use "template" here just to match the repro 3978 // we got from the issue itself. 3979 p := testProvider("template") 3980 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 3981 Name: "template_file", 3982 }) 3983 3984 p.ApplyFn = testApplyFn 3985 p.DiffFn = testDiffFn 3986 3987 // Apply cleanly step 0 3988 ctx := testContext2(t, &ContextOpts{ 3989 Module: testModule(t, "issue-5254/step-0"), 3990 Providers: map[string]ResourceProviderFactory{ 3991 "template": testProviderFuncFixed(p), 3992 }, 3993 }) 3994 3995 plan, err := ctx.Plan() 3996 if err != nil { 3997 t.Fatalf("err: %s", err) 3998 } 3999 4000 state, err := ctx.Apply() 4001 if err != nil { 4002 t.Fatalf("err: %s", err) 4003 } 4004 4005 // Application success. Now make the modification and store a plan 4006 ctx = testContext2(t, &ContextOpts{ 4007 Module: testModule(t, "issue-5254/step-1"), 4008 State: state, 4009 Providers: map[string]ResourceProviderFactory{ 4010 "template": testProviderFuncFixed(p), 4011 }, 4012 }) 4013 4014 plan, err = ctx.Plan() 4015 if err != nil { 4016 t.Fatalf("err: %s", err) 4017 } 4018 4019 // Write / Read plan to simulate running it through a Plan file 4020 var buf bytes.Buffer 4021 if err := WritePlan(plan, &buf); err != nil { 4022 t.Fatalf("err: %s", err) 4023 } 4024 4025 planFromFile, err := ReadPlan(&buf) 4026 if err != nil { 4027 t.Fatalf("err: %s", err) 4028 } 4029 4030 ctx = planFromFile.Context(&ContextOpts{ 4031 Providers: map[string]ResourceProviderFactory{ 4032 "template": testProviderFuncFixed(p), 4033 }, 4034 }) 4035 4036 state, err = ctx.Apply() 4037 if err != nil { 4038 t.Fatalf("err: %s", err) 4039 } 4040 4041 actual := strings.TrimSpace(state.String()) 4042 expected := strings.TrimSpace(` 4043 template_file.child: 4044 ID = foo 4045 template = Hi 4046 type = template_file 4047 4048 Dependencies: 4049 template_file.parent 4050 template_file.parent: 4051 ID = foo 4052 template = Hi 4053 type = template_file 4054 `) 4055 if actual != expected { 4056 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 4057 } 4058 } 4059 4060 func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { 4061 p := testProvider("aws") 4062 p.DiffFn = testDiffFn 4063 p.ApplyFn = testApplyFn 4064 ctx := testContext2(t, &ContextOpts{ 4065 Module: testModule(t, "apply-tainted-targets"), 4066 Providers: map[string]ResourceProviderFactory{ 4067 "aws": testProviderFuncFixed(p), 4068 }, 4069 Targets: []string{"aws_instance.iambeingadded"}, 4070 State: &State{ 4071 Modules: []*ModuleState{ 4072 &ModuleState{ 4073 Path: rootModulePath, 4074 Resources: map[string]*ResourceState{ 4075 "aws_instance.ifailedprovisioners": &ResourceState{ 4076 Tainted: []*InstanceState{ 4077 &InstanceState{ 4078 ID: "ifailedprovisioners", 4079 }, 4080 }, 4081 }, 4082 }, 4083 }, 4084 }, 4085 }, 4086 }) 4087 4088 plan, err := ctx.Plan() 4089 if err != nil { 4090 t.Fatalf("err: %s", err) 4091 } 4092 4093 // Write / Read plan to simulate running it through a Plan file 4094 var buf bytes.Buffer 4095 if err := WritePlan(plan, &buf); err != nil { 4096 t.Fatalf("err: %s", err) 4097 } 4098 4099 planFromFile, err := ReadPlan(&buf) 4100 if err != nil { 4101 t.Fatalf("err: %s", err) 4102 } 4103 4104 ctx = planFromFile.Context(&ContextOpts{ 4105 Module: testModule(t, "apply-tainted-targets"), 4106 Providers: map[string]ResourceProviderFactory{ 4107 "aws": testProviderFuncFixed(p), 4108 }, 4109 }) 4110 4111 state, err := ctx.Apply() 4112 if err != nil { 4113 t.Fatalf("err: %s", err) 4114 } 4115 4116 actual := strings.TrimSpace(state.String()) 4117 expected := strings.TrimSpace(` 4118 aws_instance.iambeingadded: 4119 ID = foo 4120 aws_instance.ifailedprovisioners: (1 tainted) 4121 ID = <not created> 4122 Tainted ID 1 = ifailedprovisioners 4123 `) 4124 if actual != expected { 4125 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 4126 } 4127 } 4128 4129 // Higher level test exposing the bug this covers in 4130 // TestResource_ignoreChangesRequired 4131 func TestContext2Apply_ignoreChangesCreate(t *testing.T) { 4132 m := testModule(t, "apply-ignore-changes-create") 4133 p := testProvider("aws") 4134 p.ApplyFn = testApplyFn 4135 p.DiffFn = testDiffFn 4136 ctx := testContext2(t, &ContextOpts{ 4137 Module: m, 4138 Providers: map[string]ResourceProviderFactory{ 4139 "aws": testProviderFuncFixed(p), 4140 }, 4141 }) 4142 4143 if p, err := ctx.Plan(); err != nil { 4144 t.Fatalf("err: %s", err) 4145 } else { 4146 t.Logf(p.String()) 4147 } 4148 4149 state, err := ctx.Apply() 4150 if err != nil { 4151 t.Fatalf("err: %s", err) 4152 } 4153 4154 mod := state.RootModule() 4155 if len(mod.Resources) != 1 { 4156 t.Fatalf("bad: %s", state) 4157 } 4158 4159 actual := strings.TrimSpace(state.String()) 4160 // Expect no changes from original state 4161 expected := strings.TrimSpace(` 4162 aws_instance.foo: 4163 ID = foo 4164 required_field = set 4165 type = aws_instance 4166 `) 4167 if actual != expected { 4168 t.Fatalf("bad: \n%s", actual) 4169 } 4170 }