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