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