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