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