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