github.com/rhenning/terraform@v0.8.0-beta2/terraform/context_apply_test.go (about) 1 package terraform 2 3 import ( 4 "bytes" 5 "fmt" 6 "reflect" 7 "sort" 8 "strings" 9 "sync" 10 "sync/atomic" 11 "testing" 12 "time" 13 14 "github.com/hashicorp/terraform/config/module" 15 ) 16 17 func TestContext2Apply_basic(t *testing.T) { 18 m := testModule(t, "apply-good") 19 p := testProvider("aws") 20 p.ApplyFn = testApplyFn 21 p.DiffFn = testDiffFn 22 ctx := testContext2(t, &ContextOpts{ 23 Module: m, 24 Providers: map[string]ResourceProviderFactory{ 25 "aws": testProviderFuncFixed(p), 26 }, 27 }) 28 29 if _, err := ctx.Plan(); err != nil { 30 t.Fatalf("err: %s", err) 31 } 32 33 state, err := ctx.Apply() 34 if err != nil { 35 t.Fatalf("err: %s", err) 36 } 37 38 mod := state.RootModule() 39 if len(mod.Resources) < 2 { 40 t.Fatalf("bad: %#v", mod.Resources) 41 } 42 43 actual := strings.TrimSpace(state.String()) 44 expected := strings.TrimSpace(testTerraformApplyStr) 45 if actual != expected { 46 t.Fatalf("bad: \n%s", actual) 47 } 48 } 49 50 func TestContext2Apply_resourceCountOneList(t *testing.T) { 51 m := testModule(t, "apply-resource-count-one-list") 52 p := testProvider("null") 53 p.ApplyFn = testApplyFn 54 p.DiffFn = testDiffFn 55 ctx := testContext2(t, &ContextOpts{ 56 Module: m, 57 Providers: map[string]ResourceProviderFactory{ 58 "null": testProviderFuncFixed(p), 59 }, 60 }) 61 62 if _, err := ctx.Plan(); err != nil { 63 t.Fatalf("err: %s", err) 64 } 65 66 state, err := ctx.Apply() 67 if err != nil { 68 t.Fatalf("err: %s", err) 69 } 70 71 actual := strings.TrimSpace(state.String()) 72 expected := strings.TrimSpace(`null_resource.foo: 73 ID = foo 74 75 Outputs: 76 77 test = [foo]`) 78 if actual != expected { 79 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 80 } 81 } 82 func TestContext2Apply_resourceCountZeroList(t *testing.T) { 83 m := testModule(t, "apply-resource-count-zero-list") 84 p := testProvider("null") 85 p.ApplyFn = testApplyFn 86 p.DiffFn = testDiffFn 87 ctx := testContext2(t, &ContextOpts{ 88 Module: m, 89 Providers: map[string]ResourceProviderFactory{ 90 "null": testProviderFuncFixed(p), 91 }, 92 }) 93 94 if _, err := ctx.Plan(); err != nil { 95 t.Fatalf("err: %s", err) 96 } 97 98 state, err := ctx.Apply() 99 if err != nil { 100 t.Fatalf("err: %s", err) 101 } 102 103 actual := strings.TrimSpace(state.String()) 104 expected := strings.TrimSpace(`<no state> 105 Outputs: 106 107 test = []`) 108 if actual != expected { 109 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 110 } 111 } 112 113 func TestContext2Apply_resourceDependsOnModule(t *testing.T) { 114 m := testModule(t, "apply-resource-depends-on-module") 115 p := testProvider("aws") 116 p.DiffFn = testDiffFn 117 118 { 119 // Wait for the dependency, sleep, and verify the graph never 120 // called a child. 121 var called int32 122 var checked bool 123 p.ApplyFn = func( 124 info *InstanceInfo, 125 is *InstanceState, 126 id *InstanceDiff) (*InstanceState, error) { 127 if info.HumanId() == "module.child.aws_instance.child" { 128 checked = true 129 130 // Sleep to allow parallel execution 131 time.Sleep(50 * time.Millisecond) 132 133 // Verify that called is 0 (dep not called) 134 if atomic.LoadInt32(&called) != 0 { 135 return nil, fmt.Errorf("aws_instance.a should not be called") 136 } 137 } 138 139 atomic.AddInt32(&called, 1) 140 return testApplyFn(info, is, id) 141 } 142 143 ctx := testContext2(t, &ContextOpts{ 144 Module: m, 145 Providers: map[string]ResourceProviderFactory{ 146 "aws": testProviderFuncFixed(p), 147 }, 148 }) 149 150 if _, err := ctx.Plan(); err != nil { 151 t.Fatalf("err: %s", err) 152 } 153 154 state, err := ctx.Apply() 155 if err != nil { 156 t.Fatalf("err: %s", err) 157 } 158 159 if !checked { 160 t.Fatal("should check") 161 } 162 163 checkStateString(t, state, testTerraformApplyResourceDependsOnModuleStr) 164 } 165 } 166 167 // Test that without a config, the Dependencies in the state are enough 168 // to maintain proper ordering. 169 func TestContext2Apply_resourceDependsOnModuleStateOnly(t *testing.T) { 170 m := testModule(t, "apply-resource-depends-on-module-empty") 171 p := testProvider("aws") 172 p.DiffFn = testDiffFn 173 174 state := &State{ 175 Modules: []*ModuleState{ 176 &ModuleState{ 177 Path: rootModulePath, 178 Resources: map[string]*ResourceState{ 179 "aws_instance.a": &ResourceState{ 180 Type: "aws_instance", 181 Primary: &InstanceState{ 182 ID: "bar", 183 }, 184 Dependencies: []string{"module.child"}, 185 }, 186 }, 187 }, 188 &ModuleState{ 189 Path: []string{"root", "child"}, 190 Resources: map[string]*ResourceState{ 191 "aws_instance.child": &ResourceState{ 192 Type: "aws_instance", 193 Primary: &InstanceState{ 194 ID: "bar", 195 }, 196 }, 197 }, 198 }, 199 }, 200 } 201 202 { 203 // Wait for the dependency, sleep, and verify the graph never 204 // called a child. 205 var called int32 206 var checked bool 207 p.ApplyFn = func( 208 info *InstanceInfo, 209 is *InstanceState, 210 id *InstanceDiff) (*InstanceState, error) { 211 if info.HumanId() == "aws_instance.a" { 212 checked = true 213 214 // Sleep to allow parallel execution 215 time.Sleep(50 * time.Millisecond) 216 217 // Verify that called is 0 (dep not called) 218 if atomic.LoadInt32(&called) != 0 { 219 return nil, fmt.Errorf("module child should not be called") 220 } 221 } 222 223 atomic.AddInt32(&called, 1) 224 return testApplyFn(info, is, id) 225 } 226 227 ctx := testContext2(t, &ContextOpts{ 228 Module: m, 229 Providers: map[string]ResourceProviderFactory{ 230 "aws": testProviderFuncFixed(p), 231 }, 232 State: state, 233 }) 234 235 if _, err := ctx.Plan(); err != nil { 236 t.Fatalf("err: %s", err) 237 } 238 239 state, err := ctx.Apply() 240 if err != nil { 241 t.Fatalf("err: %s", err) 242 } 243 244 if !checked { 245 t.Fatal("should check") 246 } 247 248 checkStateString(t, state, ` 249 <no state> 250 module.child: 251 <no state> 252 `) 253 } 254 } 255 256 func TestContext2Apply_resourceDependsOnModuleDestroy(t *testing.T) { 257 m := testModule(t, "apply-resource-depends-on-module") 258 p := testProvider("aws") 259 p.DiffFn = testDiffFn 260 261 var globalState *State 262 { 263 p.ApplyFn = testApplyFn 264 ctx := testContext2(t, &ContextOpts{ 265 Module: m, 266 Providers: map[string]ResourceProviderFactory{ 267 "aws": testProviderFuncFixed(p), 268 }, 269 }) 270 271 if _, err := ctx.Plan(); err != nil { 272 t.Fatalf("err: %s", err) 273 } 274 275 state, err := ctx.Apply() 276 if err != nil { 277 t.Fatalf("err: %s", err) 278 } 279 280 globalState = state 281 } 282 283 { 284 // Wait for the dependency, sleep, and verify the graph never 285 // called a child. 286 var called int32 287 var checked bool 288 p.ApplyFn = func( 289 info *InstanceInfo, 290 is *InstanceState, 291 id *InstanceDiff) (*InstanceState, error) { 292 if info.HumanId() == "aws_instance.a" { 293 checked = true 294 295 // Sleep to allow parallel execution 296 time.Sleep(50 * time.Millisecond) 297 298 // Verify that called is 0 (dep not called) 299 if atomic.LoadInt32(&called) != 0 { 300 return nil, fmt.Errorf("module child should not be called") 301 } 302 } 303 304 atomic.AddInt32(&called, 1) 305 return testApplyFn(info, is, id) 306 } 307 308 ctx := testContext2(t, &ContextOpts{ 309 Module: m, 310 Providers: map[string]ResourceProviderFactory{ 311 "aws": testProviderFuncFixed(p), 312 }, 313 State: globalState, 314 Destroy: true, 315 }) 316 317 if _, err := ctx.Plan(); err != nil { 318 t.Fatalf("err: %s", err) 319 } 320 321 state, err := ctx.Apply() 322 if err != nil { 323 t.Fatalf("err: %s", err) 324 } 325 326 if !checked { 327 t.Fatal("should check") 328 } 329 330 checkStateString(t, state, ` 331 <no state> 332 module.child: 333 <no state> 334 `) 335 } 336 } 337 338 func TestContext2Apply_resourceDependsOnModuleGrandchild(t *testing.T) { 339 m := testModule(t, "apply-resource-depends-on-module-deep") 340 p := testProvider("aws") 341 p.DiffFn = testDiffFn 342 343 { 344 // Wait for the dependency, sleep, and verify the graph never 345 // called a child. 346 var called int32 347 var checked bool 348 p.ApplyFn = func( 349 info *InstanceInfo, 350 is *InstanceState, 351 id *InstanceDiff) (*InstanceState, error) { 352 if info.HumanId() == "module.child.grandchild.aws_instance.c" { 353 checked = true 354 355 // Sleep to allow parallel execution 356 time.Sleep(50 * time.Millisecond) 357 358 // Verify that called is 0 (dep not called) 359 if atomic.LoadInt32(&called) != 0 { 360 return nil, fmt.Errorf("aws_instance.a should not be called") 361 } 362 } 363 364 atomic.AddInt32(&called, 1) 365 return testApplyFn(info, is, id) 366 } 367 368 ctx := testContext2(t, &ContextOpts{ 369 Module: m, 370 Providers: map[string]ResourceProviderFactory{ 371 "aws": testProviderFuncFixed(p), 372 }, 373 }) 374 375 if _, err := ctx.Plan(); err != nil { 376 t.Fatalf("err: %s", err) 377 } 378 379 state, err := ctx.Apply() 380 if err != nil { 381 t.Fatalf("err: %s", err) 382 } 383 384 if !checked { 385 t.Fatal("should check") 386 } 387 388 checkStateString(t, state, testTerraformApplyResourceDependsOnModuleDeepStr) 389 } 390 } 391 392 func TestContext2Apply_resourceDependsOnModuleInModule(t *testing.T) { 393 m := testModule(t, "apply-resource-depends-on-module-in-module") 394 p := testProvider("aws") 395 p.DiffFn = testDiffFn 396 397 { 398 // Wait for the dependency, sleep, and verify the graph never 399 // called a child. 400 var called int32 401 var checked bool 402 p.ApplyFn = func( 403 info *InstanceInfo, 404 is *InstanceState, 405 id *InstanceDiff) (*InstanceState, error) { 406 if info.HumanId() == "module.child.grandchild.aws_instance.c" { 407 checked = true 408 409 // Sleep to allow parallel execution 410 time.Sleep(50 * time.Millisecond) 411 412 // Verify that called is 0 (dep not called) 413 if atomic.LoadInt32(&called) != 0 { 414 return nil, fmt.Errorf("nothing else should not be called") 415 } 416 } 417 418 atomic.AddInt32(&called, 1) 419 return testApplyFn(info, is, id) 420 } 421 422 ctx := testContext2(t, &ContextOpts{ 423 Module: m, 424 Providers: map[string]ResourceProviderFactory{ 425 "aws": testProviderFuncFixed(p), 426 }, 427 }) 428 429 if _, err := ctx.Plan(); err != nil { 430 t.Fatalf("err: %s", err) 431 } 432 433 state, err := ctx.Apply() 434 if err != nil { 435 t.Fatalf("err: %s", err) 436 } 437 438 if !checked { 439 t.Fatal("should check") 440 } 441 442 checkStateString(t, state, testTerraformApplyResourceDependsOnModuleInModuleStr) 443 } 444 } 445 446 func TestContext2Apply_mapVarBetweenModules(t *testing.T) { 447 m := testModule(t, "apply-map-var-through-module") 448 p := testProvider("null") 449 p.ApplyFn = testApplyFn 450 p.DiffFn = testDiffFn 451 ctx := testContext2(t, &ContextOpts{ 452 Module: m, 453 Providers: map[string]ResourceProviderFactory{ 454 "null": testProviderFuncFixed(p), 455 }, 456 }) 457 458 if _, err := ctx.Plan(); err != nil { 459 t.Fatalf("err: %s", err) 460 } 461 462 state, err := ctx.Apply() 463 if err != nil { 464 t.Fatalf("err: %s", err) 465 } 466 467 actual := strings.TrimSpace(state.String()) 468 expected := strings.TrimSpace(`<no state> 469 Outputs: 470 471 amis_from_module = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 } 472 473 module.test: 474 null_resource.noop: 475 ID = foo 476 477 Outputs: 478 479 amis_out = {eu-west-1:ami-789012 eu-west-2:ami-989484 us-west-1:ami-123456 us-west-2:ami-456789 }`) 480 if actual != expected { 481 t.Fatalf("expected: \n%s\n\ngot: \n%s\n", expected, actual) 482 } 483 } 484 485 func TestContext2Apply_refCount(t *testing.T) { 486 m := testModule(t, "apply-ref-count") 487 p := testProvider("aws") 488 p.ApplyFn = testApplyFn 489 p.DiffFn = testDiffFn 490 ctx := testContext2(t, &ContextOpts{ 491 Module: m, 492 Providers: map[string]ResourceProviderFactory{ 493 "aws": testProviderFuncFixed(p), 494 }, 495 }) 496 497 if _, err := ctx.Plan(); err != nil { 498 t.Fatalf("err: %s", err) 499 } 500 501 state, err := ctx.Apply() 502 if err != nil { 503 t.Fatalf("err: %s", err) 504 } 505 506 mod := state.RootModule() 507 if len(mod.Resources) < 2 { 508 t.Fatalf("bad: %#v", mod.Resources) 509 } 510 511 actual := strings.TrimSpace(state.String()) 512 expected := strings.TrimSpace(testTerraformApplyRefCountStr) 513 if actual != expected { 514 t.Fatalf("bad: \n%s", actual) 515 } 516 } 517 518 func TestContext2Apply_providerAlias(t *testing.T) { 519 m := testModule(t, "apply-provider-alias") 520 p := testProvider("aws") 521 p.ApplyFn = testApplyFn 522 p.DiffFn = testDiffFn 523 ctx := testContext2(t, &ContextOpts{ 524 Module: m, 525 Providers: map[string]ResourceProviderFactory{ 526 "aws": testProviderFuncFixed(p), 527 }, 528 }) 529 530 if _, err := ctx.Plan(); err != nil { 531 t.Fatalf("err: %s", err) 532 } 533 534 state, err := ctx.Apply() 535 if err != nil { 536 t.Fatalf("err: %s", err) 537 } 538 539 mod := state.RootModule() 540 if len(mod.Resources) < 2 { 541 t.Fatalf("bad: %#v", mod.Resources) 542 } 543 544 actual := strings.TrimSpace(state.String()) 545 expected := strings.TrimSpace(testTerraformApplyProviderAliasStr) 546 if actual != expected { 547 t.Fatalf("bad: \n%s", actual) 548 } 549 } 550 551 // Two providers that are configured should both be configured prior to apply 552 func TestContext2Apply_providerAliasConfigure(t *testing.T) { 553 m := testModule(t, "apply-provider-alias-configure") 554 555 p2 := testProvider("another") 556 p2.ApplyFn = testApplyFn 557 p2.DiffFn = testDiffFn 558 559 ctx := testContext2(t, &ContextOpts{ 560 Module: m, 561 Providers: map[string]ResourceProviderFactory{ 562 "another": testProviderFuncFixed(p2), 563 }, 564 }) 565 566 if p, err := ctx.Plan(); err != nil { 567 t.Fatalf("err: %s", err) 568 } else { 569 t.Logf(p.String()) 570 } 571 572 // Configure to record calls AFTER Plan above 573 var configCount int32 574 p2.ConfigureFn = func(c *ResourceConfig) error { 575 atomic.AddInt32(&configCount, 1) 576 577 foo, ok := c.Get("foo") 578 if !ok { 579 return fmt.Errorf("foo is not found") 580 } 581 582 if foo != "bar" { 583 return fmt.Errorf("foo: %#v", foo) 584 } 585 586 return nil 587 } 588 589 state, err := ctx.Apply() 590 if err != nil { 591 t.Fatalf("err: %s", err) 592 } 593 594 if configCount != 2 { 595 t.Fatalf("provider config expected 2 calls, got: %d", configCount) 596 } 597 598 actual := strings.TrimSpace(state.String()) 599 expected := strings.TrimSpace(testTerraformApplyProviderAliasConfigStr) 600 if actual != expected { 601 t.Fatalf("bad: \n%s", actual) 602 } 603 } 604 605 // GH-2870 606 func TestContext2Apply_providerWarning(t *testing.T) { 607 m := testModule(t, "apply-provider-warning") 608 p := testProvider("aws") 609 p.ApplyFn = testApplyFn 610 p.DiffFn = testDiffFn 611 p.ValidateFn = func(c *ResourceConfig) (ws []string, es []error) { 612 ws = append(ws, "Just a warning") 613 return 614 } 615 ctx := testContext2(t, &ContextOpts{ 616 Module: m, 617 Providers: map[string]ResourceProviderFactory{ 618 "aws": testProviderFuncFixed(p), 619 }, 620 }) 621 622 if _, err := ctx.Plan(); err != nil { 623 t.Fatalf("err: %s", err) 624 } 625 626 state, err := ctx.Apply() 627 if err != nil { 628 t.Fatalf("err: %s", err) 629 } 630 631 actual := strings.TrimSpace(state.String()) 632 expected := strings.TrimSpace(` 633 aws_instance.foo: 634 ID = foo 635 `) 636 if actual != expected { 637 t.Fatalf("got: \n%s\n\nexpected:\n%s", actual, expected) 638 } 639 640 if !p.ConfigureCalled { 641 t.Fatalf("provider Configure() was never called!") 642 } 643 } 644 645 // Higher level test at TestResource_dataSourceListApplyPanic 646 func TestContext2Apply_computedAttrRefTypeMismatch(t *testing.T) { 647 m := testModule(t, "apply-computed-attr-ref-type-mismatch") 648 p := testProvider("aws") 649 p.DiffFn = testDiffFn 650 p.ValidateResourceFn = func(t string, c *ResourceConfig) (ws []string, es []error) { 651 // Emulate the type checking behavior of helper/schema based validation 652 if t == "aws_instance" { 653 ami, _ := c.Get("ami") 654 switch a := ami.(type) { 655 case string: 656 // ok 657 default: 658 es = append(es, fmt.Errorf("Expected ami to be string, got %T", a)) 659 } 660 } 661 return 662 } 663 p.DiffFn = func( 664 info *InstanceInfo, 665 state *InstanceState, 666 c *ResourceConfig) (*InstanceDiff, error) { 667 switch info.Type { 668 case "aws_ami_list": 669 // Emulate a diff that says "we'll create this list and ids will be populated" 670 return &InstanceDiff{ 671 Attributes: map[string]*ResourceAttrDiff{ 672 "ids.#": &ResourceAttrDiff{NewComputed: true}, 673 }, 674 }, nil 675 case "aws_instance": 676 // If we get to the diff for instance, we should be able to assume types 677 ami, _ := c.Get("ami") 678 _ = ami.(string) 679 } 680 return nil, nil 681 } 682 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 683 if info.Type != "aws_ami_list" { 684 t.Fatalf("Reached apply for unexpected resource type! %s", info.Type) 685 } 686 // Pretend like we make a thing and the computed list "ids" is populated 687 return &InstanceState{ 688 ID: "someid", 689 Attributes: map[string]string{ 690 "ids.#": "2", 691 "ids.0": "ami-abc123", 692 "ids.1": "ami-bcd345", 693 }, 694 }, nil 695 } 696 ctx := testContext2(t, &ContextOpts{ 697 Module: m, 698 Providers: map[string]ResourceProviderFactory{ 699 "aws": testProviderFuncFixed(p), 700 }, 701 }) 702 703 if _, err := ctx.Plan(); err != nil { 704 t.Fatalf("err: %s", err) 705 } 706 707 _, err := ctx.Apply() 708 if err == nil { 709 t.Fatalf("Expected err, got none!") 710 } 711 712 expected := "Expected ami to be string" 713 if !strings.Contains(err.Error(), expected) { 714 t.Fatalf("expected:\n\n%s\n\nto contain:\n\n%s", err, expected) 715 } 716 } 717 718 func TestContext2Apply_emptyModule(t *testing.T) { 719 m := testModule(t, "apply-empty-module") 720 p := testProvider("aws") 721 p.ApplyFn = testApplyFn 722 p.DiffFn = testDiffFn 723 ctx := testContext2(t, &ContextOpts{ 724 Module: m, 725 Providers: map[string]ResourceProviderFactory{ 726 "aws": testProviderFuncFixed(p), 727 }, 728 }) 729 730 if _, err := ctx.Plan(); err != nil { 731 t.Fatalf("err: %s", err) 732 } 733 734 state, err := ctx.Apply() 735 if err != nil { 736 t.Fatalf("err: %s", err) 737 } 738 739 actual := strings.TrimSpace(state.String()) 740 actual = strings.Replace(actual, " ", "", -1) 741 expected := strings.TrimSpace(testTerraformApplyEmptyModuleStr) 742 if actual != expected { 743 t.Fatalf("bad: \n%s\nexpect:\n%s", actual, expected) 744 } 745 } 746 747 func TestContext2Apply_createBeforeDestroy(t *testing.T) { 748 m := testModule(t, "apply-good-create-before") 749 p := testProvider("aws") 750 p.ApplyFn = testApplyFn 751 p.DiffFn = testDiffFn 752 state := &State{ 753 Modules: []*ModuleState{ 754 &ModuleState{ 755 Path: rootModulePath, 756 Resources: map[string]*ResourceState{ 757 "aws_instance.bar": &ResourceState{ 758 Type: "aws_instance", 759 Primary: &InstanceState{ 760 ID: "bar", 761 Attributes: map[string]string{ 762 "require_new": "abc", 763 }, 764 }, 765 }, 766 }, 767 }, 768 }, 769 } 770 ctx := testContext2(t, &ContextOpts{ 771 Module: m, 772 Providers: map[string]ResourceProviderFactory{ 773 "aws": testProviderFuncFixed(p), 774 }, 775 State: state, 776 }) 777 778 if p, err := ctx.Plan(); err != nil { 779 t.Fatalf("err: %s", err) 780 } else { 781 t.Logf(p.String()) 782 } 783 784 state, err := ctx.Apply() 785 if err != nil { 786 t.Fatalf("err: %s", err) 787 } 788 789 mod := state.RootModule() 790 if len(mod.Resources) != 1 { 791 t.Fatalf("bad: %s", state) 792 } 793 794 actual := strings.TrimSpace(state.String()) 795 expected := strings.TrimSpace(testTerraformApplyCreateBeforeStr) 796 if actual != expected { 797 t.Fatalf("bad: \n%s", actual) 798 } 799 } 800 801 func TestContext2Apply_createBeforeDestroyUpdate(t *testing.T) { 802 m := testModule(t, "apply-good-create-before-update") 803 p := testProvider("aws") 804 p.ApplyFn = testApplyFn 805 p.DiffFn = testDiffFn 806 state := &State{ 807 Modules: []*ModuleState{ 808 &ModuleState{ 809 Path: rootModulePath, 810 Resources: map[string]*ResourceState{ 811 "aws_instance.bar": &ResourceState{ 812 Type: "aws_instance", 813 Primary: &InstanceState{ 814 ID: "bar", 815 Attributes: map[string]string{ 816 "foo": "bar", 817 }, 818 }, 819 }, 820 }, 821 }, 822 }, 823 } 824 ctx := testContext2(t, &ContextOpts{ 825 Module: m, 826 Providers: map[string]ResourceProviderFactory{ 827 "aws": testProviderFuncFixed(p), 828 }, 829 State: state, 830 }) 831 832 if p, err := ctx.Plan(); err != nil { 833 t.Fatalf("err: %s", err) 834 } else { 835 t.Logf(p.String()) 836 } 837 838 state, err := ctx.Apply() 839 if err != nil { 840 t.Fatalf("err: %s", err) 841 } 842 843 mod := state.RootModule() 844 if len(mod.Resources) != 1 { 845 t.Fatalf("bad: %s", state) 846 } 847 848 actual := strings.TrimSpace(state.String()) 849 expected := strings.TrimSpace(testTerraformApplyCreateBeforeUpdateStr) 850 if actual != expected { 851 t.Fatalf("bad: \n%s", actual) 852 } 853 } 854 855 func TestContext2Apply_createBeforeDestroy_hook(t *testing.T) { 856 h := new(MockHook) 857 m := testModule(t, "apply-good-create-before") 858 p := testProvider("aws") 859 p.ApplyFn = testApplyFn 860 p.DiffFn = testDiffFn 861 state := &State{ 862 Modules: []*ModuleState{ 863 &ModuleState{ 864 Path: rootModulePath, 865 Resources: map[string]*ResourceState{ 866 "aws_instance.bar": &ResourceState{ 867 Type: "aws_instance", 868 Primary: &InstanceState{ 869 ID: "bar", 870 Attributes: map[string]string{ 871 "require_new": "abc", 872 }, 873 }, 874 }, 875 }, 876 }, 877 }, 878 } 879 880 var actual []string 881 var actualLock sync.Mutex 882 h.PostApplyFn = func(n *InstanceInfo, s *InstanceState, e error) (HookAction, error) { 883 actualLock.Lock() 884 defer actualLock.Unlock() 885 actual = append(actual, n.Id) 886 return HookActionContinue, nil 887 } 888 889 ctx := testContext2(t, &ContextOpts{ 890 Module: m, 891 Hooks: []Hook{h}, 892 Providers: map[string]ResourceProviderFactory{ 893 "aws": testProviderFuncFixed(p), 894 }, 895 State: state, 896 }) 897 898 if p, err := ctx.Plan(); err != nil { 899 t.Fatalf("err: %s", err) 900 } else { 901 t.Logf(p.String()) 902 } 903 904 if _, err := ctx.Apply(); err != nil { 905 t.Fatalf("err: %s", err) 906 } 907 908 expected := []string{"aws_instance.bar", "aws_instance.bar (deposed #0)"} 909 if !reflect.DeepEqual(actual, expected) { 910 t.Fatalf("bad: %#v", actual) 911 } 912 } 913 914 func TestContext2Apply_destroyComputed(t *testing.T) { 915 m := testModule(t, "apply-destroy-computed") 916 p := testProvider("aws") 917 p.ApplyFn = testApplyFn 918 p.DiffFn = testDiffFn 919 state := &State{ 920 Modules: []*ModuleState{ 921 &ModuleState{ 922 Path: rootModulePath, 923 Resources: map[string]*ResourceState{ 924 "aws_instance.foo": &ResourceState{ 925 Type: "aws_instance", 926 Primary: &InstanceState{ 927 ID: "foo", 928 Attributes: map[string]string{ 929 "output": "value", 930 }, 931 }, 932 }, 933 }, 934 }, 935 }, 936 } 937 ctx := testContext2(t, &ContextOpts{ 938 Module: m, 939 Providers: map[string]ResourceProviderFactory{ 940 "aws": testProviderFuncFixed(p), 941 }, 942 State: state, 943 Destroy: true, 944 }) 945 946 if p, err := ctx.Plan(); err != nil { 947 t.Fatalf("err: %s", err) 948 } else { 949 t.Logf(p.String()) 950 } 951 952 if _, err := ctx.Apply(); err != nil { 953 t.Fatalf("err: %s", err) 954 } 955 } 956 957 // Test that the destroy operation uses depends_on as a source of ordering. 958 func TestContext2Apply_destroyDependsOn(t *testing.T) { 959 // It is possible for this to be racy, so we loop a number of times 960 // just to check. 961 for i := 0; i < 10; i++ { 962 testContext2Apply_destroyDependsOn(t) 963 } 964 } 965 966 func testContext2Apply_destroyDependsOn(t *testing.T) { 967 m := testModule(t, "apply-destroy-depends-on") 968 p := testProvider("aws") 969 p.ApplyFn = testApplyFn 970 p.DiffFn = testDiffFn 971 state := &State{ 972 Modules: []*ModuleState{ 973 &ModuleState{ 974 Path: rootModulePath, 975 Resources: map[string]*ResourceState{ 976 "aws_instance.foo": &ResourceState{ 977 Type: "aws_instance", 978 Primary: &InstanceState{ 979 ID: "foo", 980 Attributes: map[string]string{}, 981 }, 982 }, 983 984 "aws_instance.bar": &ResourceState{ 985 Type: "aws_instance", 986 Primary: &InstanceState{ 987 ID: "bar", 988 Attributes: map[string]string{}, 989 }, 990 }, 991 }, 992 }, 993 }, 994 } 995 996 // Record the order we see Apply 997 var actual []string 998 var actualLock sync.Mutex 999 p.ApplyFn = func( 1000 info *InstanceInfo, _ *InstanceState, _ *InstanceDiff) (*InstanceState, error) { 1001 actualLock.Lock() 1002 defer actualLock.Unlock() 1003 actual = append(actual, info.Id) 1004 return nil, nil 1005 } 1006 1007 ctx := testContext2(t, &ContextOpts{ 1008 Module: m, 1009 Providers: map[string]ResourceProviderFactory{ 1010 "aws": testProviderFuncFixed(p), 1011 }, 1012 State: state, 1013 Destroy: true, 1014 Parallelism: 1, // To check ordering 1015 }) 1016 1017 if _, err := ctx.Plan(); err != nil { 1018 t.Fatalf("err: %s", err) 1019 } 1020 1021 if _, err := ctx.Apply(); err != nil { 1022 t.Fatalf("err: %s", err) 1023 } 1024 1025 expected := []string{"aws_instance.foo", "aws_instance.bar"} 1026 if !reflect.DeepEqual(actual, expected) { 1027 t.Fatalf("bad: %#v", actual) 1028 } 1029 } 1030 1031 // Test that destroy ordering is correct with dependencies only 1032 // in the state. 1033 func TestContext2Apply_destroyDependsOnStateOnly(t *testing.T) { 1034 // It is possible for this to be racy, so we loop a number of times 1035 // just to check. 1036 for i := 0; i < 10; i++ { 1037 testContext2Apply_destroyDependsOnStateOnly(t) 1038 } 1039 } 1040 1041 func testContext2Apply_destroyDependsOnStateOnly(t *testing.T) { 1042 m := testModule(t, "empty") 1043 p := testProvider("aws") 1044 p.ApplyFn = testApplyFn 1045 p.DiffFn = testDiffFn 1046 state := &State{ 1047 Modules: []*ModuleState{ 1048 &ModuleState{ 1049 Path: rootModulePath, 1050 Resources: map[string]*ResourceState{ 1051 "aws_instance.foo": &ResourceState{ 1052 Type: "aws_instance", 1053 Primary: &InstanceState{ 1054 ID: "foo", 1055 Attributes: map[string]string{}, 1056 }, 1057 }, 1058 1059 "aws_instance.bar": &ResourceState{ 1060 Type: "aws_instance", 1061 Primary: &InstanceState{ 1062 ID: "bar", 1063 Attributes: map[string]string{}, 1064 }, 1065 Dependencies: []string{"aws_instance.foo"}, 1066 }, 1067 }, 1068 }, 1069 }, 1070 } 1071 1072 // Record the order we see Apply 1073 var actual []string 1074 var actualLock sync.Mutex 1075 p.ApplyFn = func( 1076 info *InstanceInfo, _ *InstanceState, _ *InstanceDiff) (*InstanceState, error) { 1077 actualLock.Lock() 1078 defer actualLock.Unlock() 1079 actual = append(actual, info.Id) 1080 return nil, nil 1081 } 1082 1083 ctx := testContext2(t, &ContextOpts{ 1084 Module: m, 1085 Providers: map[string]ResourceProviderFactory{ 1086 "aws": testProviderFuncFixed(p), 1087 }, 1088 State: state, 1089 Destroy: true, 1090 Parallelism: 1, // To check ordering 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 expected := []string{"aws_instance.bar", "aws_instance.foo"} 1102 if !reflect.DeepEqual(actual, expected) { 1103 t.Fatalf("bad: %#v", actual) 1104 } 1105 } 1106 1107 func TestContext2Apply_dataBasic(t *testing.T) { 1108 m := testModule(t, "apply-data-basic") 1109 p := testProvider("null") 1110 p.ApplyFn = testApplyFn 1111 p.DiffFn = testDiffFn 1112 p.ReadDataApplyReturn = &InstanceState{ID: "yo"} 1113 1114 ctx := testContext2(t, &ContextOpts{ 1115 Module: m, 1116 Providers: map[string]ResourceProviderFactory{ 1117 "null": testProviderFuncFixed(p), 1118 }, 1119 }) 1120 1121 if p, err := ctx.Plan(); err != nil { 1122 t.Fatalf("err: %s", err) 1123 } else { 1124 t.Logf(p.String()) 1125 } 1126 1127 state, err := ctx.Apply() 1128 if err != nil { 1129 t.Fatalf("err: %s", err) 1130 } 1131 1132 actual := strings.TrimSpace(state.String()) 1133 expected := strings.TrimSpace(testTerraformApplyDataBasicStr) 1134 if actual != expected { 1135 t.Fatalf("bad: \n%s", actual) 1136 } 1137 } 1138 1139 func TestContext2Apply_destroyData(t *testing.T) { 1140 m := testModule(t, "apply-destroy-data-resource") 1141 p := testProvider("null") 1142 p.ApplyFn = testApplyFn 1143 p.DiffFn = testDiffFn 1144 state := &State{ 1145 Modules: []*ModuleState{ 1146 &ModuleState{ 1147 Path: rootModulePath, 1148 Resources: map[string]*ResourceState{ 1149 "data.null_data_source.testing": &ResourceState{ 1150 Type: "aws_instance", 1151 Primary: &InstanceState{ 1152 ID: "-", 1153 Attributes: map[string]string{ 1154 "inputs.#": "1", 1155 "inputs.test": "yes", 1156 }, 1157 }, 1158 }, 1159 }, 1160 }, 1161 }, 1162 } 1163 ctx := testContext2(t, &ContextOpts{ 1164 Module: m, 1165 Providers: map[string]ResourceProviderFactory{ 1166 "null": testProviderFuncFixed(p), 1167 }, 1168 State: state, 1169 Destroy: true, 1170 }) 1171 1172 if p, err := ctx.Plan(); err != nil { 1173 t.Fatalf("err: %s", err) 1174 } else { 1175 t.Logf(p.String()) 1176 } 1177 1178 newState, err := ctx.Apply() 1179 if err != nil { 1180 t.Fatalf("err: %s", err) 1181 } 1182 1183 if got := len(newState.Modules); got != 1 { 1184 t.Fatalf("state has %d modules after destroy; want 1", got) 1185 } 1186 1187 if got := len(newState.Modules[0].Resources); got != 0 { 1188 t.Fatalf("state has %d resources after destroy; want 0", got) 1189 } 1190 } 1191 1192 // https://github.com/hashicorp/terraform/pull/5096 1193 func TestContext2Apply_destroySkipsCBD(t *testing.T) { 1194 // Config contains CBD resource depending on non-CBD resource, which triggers 1195 // a cycle if they are both replaced, but should _not_ trigger a cycle when 1196 // just doing a `terraform destroy`. 1197 m := testModule(t, "apply-destroy-cbd") 1198 p := testProvider("aws") 1199 p.ApplyFn = testApplyFn 1200 p.DiffFn = testDiffFn 1201 state := &State{ 1202 Modules: []*ModuleState{ 1203 &ModuleState{ 1204 Path: rootModulePath, 1205 Resources: map[string]*ResourceState{ 1206 "aws_instance.foo": &ResourceState{ 1207 Type: "aws_instance", 1208 Primary: &InstanceState{ 1209 ID: "foo", 1210 }, 1211 }, 1212 "aws_instance.bar": &ResourceState{ 1213 Type: "aws_instance", 1214 Primary: &InstanceState{ 1215 ID: "foo", 1216 }, 1217 }, 1218 }, 1219 }, 1220 }, 1221 } 1222 ctx := testContext2(t, &ContextOpts{ 1223 Module: m, 1224 Providers: map[string]ResourceProviderFactory{ 1225 "aws": testProviderFuncFixed(p), 1226 }, 1227 State: state, 1228 Destroy: true, 1229 }) 1230 1231 if p, err := ctx.Plan(); err != nil { 1232 t.Fatalf("err: %s", err) 1233 } else { 1234 t.Logf(p.String()) 1235 } 1236 1237 if _, err := ctx.Apply(); err != nil { 1238 t.Fatalf("err: %s", err) 1239 } 1240 } 1241 1242 func TestContext2Apply_destroyModuleVarProviderConfig(t *testing.T) { 1243 m := testModule(t, "apply-destroy-mod-var-provider-config") 1244 p := testProvider("aws") 1245 p.ApplyFn = testApplyFn 1246 p.DiffFn = testDiffFn 1247 state := &State{ 1248 Modules: []*ModuleState{ 1249 &ModuleState{ 1250 Path: []string{"root", "child"}, 1251 Resources: map[string]*ResourceState{ 1252 "aws_instance.foo": &ResourceState{ 1253 Type: "aws_instance", 1254 Primary: &InstanceState{ 1255 ID: "foo", 1256 }, 1257 }, 1258 }, 1259 }, 1260 }, 1261 } 1262 ctx := testContext2(t, &ContextOpts{ 1263 Module: m, 1264 Providers: map[string]ResourceProviderFactory{ 1265 "aws": testProviderFuncFixed(p), 1266 }, 1267 State: state, 1268 Destroy: true, 1269 }) 1270 1271 if _, err := ctx.Plan(); err != nil { 1272 t.Fatalf("err: %s", err) 1273 } 1274 1275 _, err := ctx.Apply() 1276 if err != nil { 1277 t.Fatalf("err: %s", err) 1278 } 1279 } 1280 1281 // https://github.com/hashicorp/terraform/issues/2892 1282 func TestContext2Apply_destroyCrossProviders(t *testing.T) { 1283 m := testModule(t, "apply-destroy-cross-providers") 1284 1285 p_aws := testProvider("aws") 1286 p_aws.ApplyFn = testApplyFn 1287 p_aws.DiffFn = testDiffFn 1288 1289 p_tf := testProvider("terraform") 1290 p_tf.ApplyFn = testApplyFn 1291 p_tf.DiffFn = testDiffFn 1292 1293 providers := map[string]ResourceProviderFactory{ 1294 "aws": testProviderFuncFixed(p_aws), 1295 "terraform": testProviderFuncFixed(p_tf), 1296 } 1297 1298 // Bug only appears from time to time, 1299 // so we run this test multiple times 1300 // to check for the race-condition 1301 for i := 0; i <= 10; i++ { 1302 ctx := getContextForApply_destroyCrossProviders( 1303 t, m, providers) 1304 1305 if p, err := ctx.Plan(); err != nil { 1306 t.Fatalf("err: %s", err) 1307 } else { 1308 t.Logf(p.String()) 1309 } 1310 1311 if _, err := ctx.Apply(); err != nil { 1312 t.Fatalf("err: %s", err) 1313 } 1314 } 1315 } 1316 1317 func getContextForApply_destroyCrossProviders( 1318 t *testing.T, 1319 m *module.Tree, 1320 providers map[string]ResourceProviderFactory) *Context { 1321 state := &State{ 1322 Modules: []*ModuleState{ 1323 &ModuleState{ 1324 Path: rootModulePath, 1325 Resources: map[string]*ResourceState{ 1326 "terraform_remote_state.shared": &ResourceState{ 1327 Type: "terraform_remote_state", 1328 Primary: &InstanceState{ 1329 ID: "remote-2652591293", 1330 Attributes: map[string]string{ 1331 "output.env_name": "test", 1332 }, 1333 }, 1334 }, 1335 }, 1336 }, 1337 &ModuleState{ 1338 Path: []string{"root", "child"}, 1339 Resources: map[string]*ResourceState{ 1340 "aws_vpc.bar": &ResourceState{ 1341 Type: "aws_vpc", 1342 Primary: &InstanceState{ 1343 ID: "vpc-aaabbb12", 1344 Attributes: map[string]string{ 1345 "value": "test", 1346 }, 1347 }, 1348 }, 1349 }, 1350 }, 1351 }, 1352 } 1353 ctx := testContext2(t, &ContextOpts{ 1354 Module: m, 1355 Providers: providers, 1356 State: state, 1357 Destroy: true, 1358 }) 1359 1360 return ctx 1361 } 1362 1363 func TestContext2Apply_minimal(t *testing.T) { 1364 m := testModule(t, "apply-minimal") 1365 p := testProvider("aws") 1366 p.ApplyFn = testApplyFn 1367 p.DiffFn = testDiffFn 1368 ctx := testContext2(t, &ContextOpts{ 1369 Module: m, 1370 Providers: map[string]ResourceProviderFactory{ 1371 "aws": testProviderFuncFixed(p), 1372 }, 1373 }) 1374 1375 if _, err := ctx.Plan(); err != nil { 1376 t.Fatalf("err: %s", err) 1377 } 1378 1379 state, err := ctx.Apply() 1380 if err != nil { 1381 t.Fatalf("err: %s", err) 1382 } 1383 1384 actual := strings.TrimSpace(state.String()) 1385 expected := strings.TrimSpace(testTerraformApplyMinimalStr) 1386 if actual != expected { 1387 t.Fatalf("bad: \n%s", actual) 1388 } 1389 } 1390 1391 func TestContext2Apply_badDiff(t *testing.T) { 1392 m := testModule(t, "apply-good") 1393 p := testProvider("aws") 1394 p.ApplyFn = testApplyFn 1395 p.DiffFn = testDiffFn 1396 ctx := testContext2(t, &ContextOpts{ 1397 Module: m, 1398 Providers: map[string]ResourceProviderFactory{ 1399 "aws": testProviderFuncFixed(p), 1400 }, 1401 }) 1402 1403 if _, err := ctx.Plan(); err != nil { 1404 t.Fatalf("err: %s", err) 1405 } 1406 1407 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1408 return &InstanceDiff{ 1409 Attributes: map[string]*ResourceAttrDiff{ 1410 "newp": nil, 1411 }, 1412 }, nil 1413 } 1414 1415 if _, err := ctx.Apply(); err == nil { 1416 t.Fatal("should error") 1417 } 1418 } 1419 1420 func TestContext2Apply_cancel(t *testing.T) { 1421 stopped := false 1422 1423 m := testModule(t, "apply-cancel") 1424 p := testProvider("aws") 1425 ctx := testContext2(t, &ContextOpts{ 1426 Module: m, 1427 Providers: map[string]ResourceProviderFactory{ 1428 "aws": testProviderFuncFixed(p), 1429 }, 1430 }) 1431 1432 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 1433 if !stopped { 1434 stopped = true 1435 go ctx.Stop() 1436 1437 for { 1438 if ctx.sh.Stopped() { 1439 break 1440 } 1441 } 1442 } 1443 1444 return &InstanceState{ 1445 ID: "foo", 1446 Attributes: map[string]string{ 1447 "num": "2", 1448 }, 1449 }, nil 1450 } 1451 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 1452 return &InstanceDiff{ 1453 Attributes: map[string]*ResourceAttrDiff{ 1454 "num": &ResourceAttrDiff{ 1455 New: "bar", 1456 }, 1457 }, 1458 }, nil 1459 } 1460 1461 if _, err := ctx.Plan(); err != nil { 1462 t.Fatalf("err: %s", err) 1463 } 1464 1465 // Start the Apply in a goroutine 1466 var applyErr error 1467 stateCh := make(chan *State) 1468 go func() { 1469 state, err := ctx.Apply() 1470 if err != nil { 1471 applyErr = err 1472 } 1473 1474 stateCh <- state 1475 }() 1476 1477 state := <-stateCh 1478 if applyErr != nil { 1479 t.Fatalf("err: %s", applyErr) 1480 } 1481 1482 mod := state.RootModule() 1483 if len(mod.Resources) != 1 { 1484 t.Fatalf("bad: %s", state.String()) 1485 } 1486 1487 actual := strings.TrimSpace(state.String()) 1488 expected := strings.TrimSpace(testTerraformApplyCancelStr) 1489 if actual != expected { 1490 t.Fatalf("bad: \n%s", actual) 1491 } 1492 1493 if !p.StopCalled { 1494 t.Fatal("stop should be called") 1495 } 1496 } 1497 1498 func TestContext2Apply_compute(t *testing.T) { 1499 m := testModule(t, "apply-compute") 1500 p := testProvider("aws") 1501 p.ApplyFn = testApplyFn 1502 p.DiffFn = testDiffFn 1503 ctx := testContext2(t, &ContextOpts{ 1504 Module: m, 1505 Providers: map[string]ResourceProviderFactory{ 1506 "aws": testProviderFuncFixed(p), 1507 }, 1508 }) 1509 1510 if _, err := ctx.Plan(); err != nil { 1511 t.Fatalf("err: %s", err) 1512 } 1513 1514 ctx.variables = map[string]interface{}{"value": "1"} 1515 1516 state, err := ctx.Apply() 1517 if err != nil { 1518 t.Fatalf("err: %s", err) 1519 } 1520 1521 actual := strings.TrimSpace(state.String()) 1522 expected := strings.TrimSpace(testTerraformApplyComputeStr) 1523 if actual != expected { 1524 t.Fatalf("bad: \n%s", actual) 1525 } 1526 } 1527 1528 func TestContext2Apply_countDecrease(t *testing.T) { 1529 m := testModule(t, "apply-count-dec") 1530 p := testProvider("aws") 1531 p.DiffFn = testDiffFn 1532 s := &State{ 1533 Modules: []*ModuleState{ 1534 &ModuleState{ 1535 Path: rootModulePath, 1536 Resources: map[string]*ResourceState{ 1537 "aws_instance.foo.0": &ResourceState{ 1538 Type: "aws_instance", 1539 Primary: &InstanceState{ 1540 ID: "bar", 1541 Attributes: map[string]string{ 1542 "foo": "foo", 1543 "type": "aws_instance", 1544 }, 1545 }, 1546 }, 1547 "aws_instance.foo.1": &ResourceState{ 1548 Type: "aws_instance", 1549 Primary: &InstanceState{ 1550 ID: "bar", 1551 Attributes: map[string]string{ 1552 "foo": "foo", 1553 "type": "aws_instance", 1554 }, 1555 }, 1556 }, 1557 "aws_instance.foo.2": &ResourceState{ 1558 Type: "aws_instance", 1559 Primary: &InstanceState{ 1560 ID: "bar", 1561 Attributes: map[string]string{ 1562 "foo": "foo", 1563 "type": "aws_instance", 1564 }, 1565 }, 1566 }, 1567 }, 1568 }, 1569 }, 1570 } 1571 ctx := testContext2(t, &ContextOpts{ 1572 Module: m, 1573 Providers: map[string]ResourceProviderFactory{ 1574 "aws": testProviderFuncFixed(p), 1575 }, 1576 State: s, 1577 }) 1578 1579 if _, err := ctx.Plan(); err != nil { 1580 t.Fatalf("err: %s", err) 1581 } 1582 1583 state, err := ctx.Apply() 1584 if err != nil { 1585 t.Fatalf("err: %s", err) 1586 } 1587 1588 actual := strings.TrimSpace(state.String()) 1589 expected := strings.TrimSpace(testTerraformApplyCountDecStr) 1590 if actual != expected { 1591 t.Fatalf("bad: \n%s", actual) 1592 } 1593 } 1594 1595 func TestContext2Apply_countDecreaseToOneX(t *testing.T) { 1596 m := testModule(t, "apply-count-dec-one") 1597 p := testProvider("aws") 1598 p.ApplyFn = testApplyFn 1599 p.DiffFn = testDiffFn 1600 s := &State{ 1601 Modules: []*ModuleState{ 1602 &ModuleState{ 1603 Path: rootModulePath, 1604 Resources: map[string]*ResourceState{ 1605 "aws_instance.foo.0": &ResourceState{ 1606 Type: "aws_instance", 1607 Primary: &InstanceState{ 1608 ID: "bar", 1609 Attributes: map[string]string{ 1610 "foo": "foo", 1611 "type": "aws_instance", 1612 }, 1613 }, 1614 }, 1615 "aws_instance.foo.1": &ResourceState{ 1616 Type: "aws_instance", 1617 Primary: &InstanceState{ 1618 ID: "bar", 1619 }, 1620 }, 1621 "aws_instance.foo.2": &ResourceState{ 1622 Type: "aws_instance", 1623 Primary: &InstanceState{ 1624 ID: "bar", 1625 }, 1626 }, 1627 }, 1628 }, 1629 }, 1630 } 1631 ctx := testContext2(t, &ContextOpts{ 1632 Module: m, 1633 Providers: map[string]ResourceProviderFactory{ 1634 "aws": testProviderFuncFixed(p), 1635 }, 1636 State: s, 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.Fatalf("err: %s", err) 1646 } 1647 1648 actual := strings.TrimSpace(state.String()) 1649 expected := strings.TrimSpace(testTerraformApplyCountDecToOneStr) 1650 if actual != expected { 1651 t.Fatalf("bad: \n%s", actual) 1652 } 1653 } 1654 1655 // https://github.com/PeoplePerHour/terraform/pull/11 1656 // 1657 // This tests a case where both a "resource" and "resource.0" are in 1658 // the state file, which apparently is a reasonable backwards compatibility 1659 // concern found in the above 3rd party repo. 1660 func TestContext2Apply_countDecreaseToOneCorrupted(t *testing.T) { 1661 m := testModule(t, "apply-count-dec-one") 1662 p := testProvider("aws") 1663 p.ApplyFn = testApplyFn 1664 p.DiffFn = testDiffFn 1665 s := &State{ 1666 Modules: []*ModuleState{ 1667 &ModuleState{ 1668 Path: rootModulePath, 1669 Resources: map[string]*ResourceState{ 1670 "aws_instance.foo": &ResourceState{ 1671 Type: "aws_instance", 1672 Primary: &InstanceState{ 1673 ID: "bar", 1674 Attributes: map[string]string{ 1675 "foo": "foo", 1676 "type": "aws_instance", 1677 }, 1678 }, 1679 }, 1680 "aws_instance.foo.0": &ResourceState{ 1681 Type: "aws_instance", 1682 Primary: &InstanceState{ 1683 ID: "baz", 1684 Attributes: map[string]string{ 1685 "type": "aws_instance", 1686 }, 1687 }, 1688 }, 1689 }, 1690 }, 1691 }, 1692 } 1693 ctx := testContext2(t, &ContextOpts{ 1694 Module: m, 1695 Providers: map[string]ResourceProviderFactory{ 1696 "aws": testProviderFuncFixed(p), 1697 }, 1698 State: s, 1699 }) 1700 1701 if p, err := ctx.Plan(); err != nil { 1702 t.Fatalf("err: %s", err) 1703 } else { 1704 testStringMatch(t, p, testTerraformApplyCountDecToOneCorruptedPlanStr) 1705 } 1706 1707 state, err := ctx.Apply() 1708 if err != nil { 1709 t.Fatalf("err: %s", err) 1710 } 1711 1712 actual := strings.TrimSpace(state.String()) 1713 expected := strings.TrimSpace(testTerraformApplyCountDecToOneCorruptedStr) 1714 if actual != expected { 1715 t.Fatalf("bad: \n%s", actual) 1716 } 1717 } 1718 1719 func TestContext2Apply_countTainted(t *testing.T) { 1720 m := testModule(t, "apply-count-tainted") 1721 p := testProvider("aws") 1722 p.DiffFn = testDiffFn 1723 s := &State{ 1724 Modules: []*ModuleState{ 1725 &ModuleState{ 1726 Path: rootModulePath, 1727 Resources: map[string]*ResourceState{ 1728 "aws_instance.foo.0": &ResourceState{ 1729 Type: "aws_instance", 1730 Primary: &InstanceState{ 1731 ID: "bar", 1732 Attributes: map[string]string{ 1733 "foo": "foo", 1734 "type": "aws_instance", 1735 }, 1736 Tainted: true, 1737 }, 1738 }, 1739 }, 1740 }, 1741 }, 1742 } 1743 ctx := testContext2(t, &ContextOpts{ 1744 Module: m, 1745 Providers: map[string]ResourceProviderFactory{ 1746 "aws": testProviderFuncFixed(p), 1747 }, 1748 State: s, 1749 }) 1750 1751 if _, err := ctx.Plan(); err != nil { 1752 t.Fatalf("err: %s", err) 1753 } 1754 1755 state, err := ctx.Apply() 1756 if err != nil { 1757 t.Fatalf("err: %s", err) 1758 } 1759 1760 actual := strings.TrimSpace(state.String()) 1761 expected := strings.TrimSpace(testTerraformApplyCountTaintedStr) 1762 if actual != expected { 1763 t.Fatalf("bad: \n%s", actual) 1764 } 1765 } 1766 1767 func TestContext2Apply_countVariable(t *testing.T) { 1768 m := testModule(t, "apply-count-variable") 1769 p := testProvider("aws") 1770 p.ApplyFn = testApplyFn 1771 p.DiffFn = testDiffFn 1772 ctx := testContext2(t, &ContextOpts{ 1773 Module: m, 1774 Providers: map[string]ResourceProviderFactory{ 1775 "aws": testProviderFuncFixed(p), 1776 }, 1777 }) 1778 1779 if _, err := ctx.Plan(); err != nil { 1780 t.Fatalf("err: %s", err) 1781 } 1782 1783 state, err := ctx.Apply() 1784 if err != nil { 1785 t.Fatalf("err: %s", err) 1786 } 1787 1788 actual := strings.TrimSpace(state.String()) 1789 expected := strings.TrimSpace(testTerraformApplyCountVariableStr) 1790 if actual != expected { 1791 t.Fatalf("bad: \n%s", actual) 1792 } 1793 } 1794 1795 func TestContext2Apply_countVariableRef(t *testing.T) { 1796 m := testModule(t, "apply-count-variable-ref") 1797 p := testProvider("aws") 1798 p.ApplyFn = testApplyFn 1799 p.DiffFn = testDiffFn 1800 ctx := testContext2(t, &ContextOpts{ 1801 Module: m, 1802 Providers: map[string]ResourceProviderFactory{ 1803 "aws": testProviderFuncFixed(p), 1804 }, 1805 }) 1806 1807 if _, err := ctx.Plan(); err != nil { 1808 t.Fatalf("err: %s", err) 1809 } 1810 1811 state, err := ctx.Apply() 1812 if err != nil { 1813 t.Fatalf("err: %s", err) 1814 } 1815 1816 actual := strings.TrimSpace(state.String()) 1817 expected := strings.TrimSpace(testTerraformApplyCountVariableRefStr) 1818 if actual != expected { 1819 t.Fatalf("bad: \n%s", actual) 1820 } 1821 } 1822 1823 func TestContext2Apply_mapVariableOverride(t *testing.T) { 1824 m := testModule(t, "apply-map-var-override") 1825 p := testProvider("aws") 1826 p.ApplyFn = testApplyFn 1827 p.DiffFn = testDiffFn 1828 ctx := testContext2(t, &ContextOpts{ 1829 Module: m, 1830 Providers: map[string]ResourceProviderFactory{ 1831 "aws": testProviderFuncFixed(p), 1832 }, 1833 Variables: map[string]interface{}{ 1834 "images": []map[string]interface{}{ 1835 map[string]interface{}{ 1836 "us-west-2": "overridden", 1837 }, 1838 }, 1839 }, 1840 }) 1841 1842 if _, err := ctx.Plan(); err != nil { 1843 t.Fatalf("err: %s", err) 1844 } 1845 1846 state, err := ctx.Apply() 1847 if err != nil { 1848 t.Fatalf("err: %s", err) 1849 } 1850 1851 actual := strings.TrimSpace(state.String()) 1852 expected := strings.TrimSpace(` 1853 aws_instance.bar: 1854 ID = foo 1855 ami = overridden 1856 type = aws_instance 1857 aws_instance.foo: 1858 ID = foo 1859 ami = image-1234 1860 type = aws_instance 1861 `) 1862 if actual != expected { 1863 t.Fatalf("got: \n%s\nexpected: \n%s", actual, expected) 1864 } 1865 } 1866 1867 func TestContext2Apply_moduleBasic(t *testing.T) { 1868 m := testModule(t, "apply-module") 1869 p := testProvider("aws") 1870 p.ApplyFn = testApplyFn 1871 p.DiffFn = testDiffFn 1872 ctx := testContext2(t, &ContextOpts{ 1873 Module: m, 1874 Providers: map[string]ResourceProviderFactory{ 1875 "aws": testProviderFuncFixed(p), 1876 }, 1877 }) 1878 1879 if _, err := ctx.Plan(); err != nil { 1880 t.Fatalf("err: %s", err) 1881 } 1882 1883 state, err := ctx.Apply() 1884 if err != nil { 1885 t.Fatalf("err: %s", err) 1886 } 1887 1888 actual := strings.TrimSpace(state.String()) 1889 expected := strings.TrimSpace(testTerraformApplyModuleStr) 1890 if actual != expected { 1891 t.Fatalf("bad, expected:\n%s\n\nactual:\n%s", expected, actual) 1892 } 1893 } 1894 1895 func TestContext2Apply_moduleDestroyOrder(t *testing.T) { 1896 m := testModule(t, "apply-module-destroy-order") 1897 p := testProvider("aws") 1898 p.DiffFn = testDiffFn 1899 1900 // Create a custom apply function to track the order they were destroyed 1901 var order []string 1902 var orderLock sync.Mutex 1903 p.ApplyFn = func( 1904 info *InstanceInfo, 1905 is *InstanceState, 1906 id *InstanceDiff) (*InstanceState, error) { 1907 orderLock.Lock() 1908 defer orderLock.Unlock() 1909 1910 order = append(order, is.ID) 1911 return nil, nil 1912 } 1913 1914 state := &State{ 1915 Modules: []*ModuleState{ 1916 &ModuleState{ 1917 Path: rootModulePath, 1918 Resources: map[string]*ResourceState{ 1919 "aws_instance.b": &ResourceState{ 1920 Type: "aws_instance", 1921 Primary: &InstanceState{ 1922 ID: "b", 1923 }, 1924 }, 1925 }, 1926 }, 1927 1928 &ModuleState{ 1929 Path: []string{"root", "child"}, 1930 Resources: map[string]*ResourceState{ 1931 "aws_instance.a": &ResourceState{ 1932 Type: "aws_instance", 1933 Primary: &InstanceState{ 1934 ID: "a", 1935 }, 1936 }, 1937 }, 1938 Outputs: map[string]*OutputState{ 1939 "a_output": &OutputState{ 1940 Type: "string", 1941 Sensitive: false, 1942 Value: "a", 1943 }, 1944 }, 1945 }, 1946 }, 1947 } 1948 1949 ctx := testContext2(t, &ContextOpts{ 1950 Module: m, 1951 Providers: map[string]ResourceProviderFactory{ 1952 "aws": testProviderFuncFixed(p), 1953 }, 1954 State: state, 1955 Destroy: true, 1956 }) 1957 1958 if _, err := ctx.Plan(); err != nil { 1959 t.Fatalf("err: %s", err) 1960 } 1961 1962 state, err := ctx.Apply() 1963 if err != nil { 1964 t.Fatalf("err: %s", err) 1965 } 1966 1967 expected := []string{"b", "a"} 1968 if !reflect.DeepEqual(order, expected) { 1969 t.Fatalf("bad: %#v", order) 1970 } 1971 1972 { 1973 actual := strings.TrimSpace(state.String()) 1974 expected := strings.TrimSpace(testTerraformApplyModuleDestroyOrderStr) 1975 if actual != expected { 1976 t.Fatalf("bad: \n%s", actual) 1977 } 1978 } 1979 } 1980 1981 func TestContext2Apply_moduleOrphanProvider(t *testing.T) { 1982 m := testModule(t, "apply-module-orphan-provider-inherit") 1983 p := testProvider("aws") 1984 p.ApplyFn = testApplyFn 1985 p.DiffFn = testDiffFn 1986 1987 p.ConfigureFn = func(c *ResourceConfig) error { 1988 if _, ok := c.Get("value"); !ok { 1989 return fmt.Errorf("value is not found") 1990 } 1991 1992 return nil 1993 } 1994 1995 // Create a state with an orphan module 1996 state := &State{ 1997 Modules: []*ModuleState{ 1998 &ModuleState{ 1999 Path: []string{"root", "child"}, 2000 Resources: map[string]*ResourceState{ 2001 "aws_instance.bar": &ResourceState{ 2002 Type: "aws_instance", 2003 Primary: &InstanceState{ 2004 ID: "bar", 2005 }, 2006 }, 2007 }, 2008 }, 2009 }, 2010 } 2011 2012 ctx := testContext2(t, &ContextOpts{ 2013 Module: m, 2014 State: state, 2015 Providers: map[string]ResourceProviderFactory{ 2016 "aws": testProviderFuncFixed(p), 2017 }, 2018 }) 2019 2020 if _, err := ctx.Plan(); err != nil { 2021 t.Fatalf("err: %s", err) 2022 } 2023 2024 if _, err := ctx.Apply(); err != nil { 2025 t.Fatalf("err: %s", err) 2026 } 2027 } 2028 2029 func TestContext2Apply_moduleOrphanGrandchildProvider(t *testing.T) { 2030 m := testModule(t, "apply-module-orphan-provider-inherit") 2031 p := testProvider("aws") 2032 p.ApplyFn = testApplyFn 2033 p.DiffFn = testDiffFn 2034 2035 p.ConfigureFn = func(c *ResourceConfig) error { 2036 if _, ok := c.Get("value"); !ok { 2037 return fmt.Errorf("value is not found") 2038 } 2039 2040 return nil 2041 } 2042 2043 // Create a state with an orphan module that is nested (grandchild) 2044 state := &State{ 2045 Modules: []*ModuleState{ 2046 &ModuleState{ 2047 Path: []string{"root", "parent", "child"}, 2048 Resources: map[string]*ResourceState{ 2049 "aws_instance.bar": &ResourceState{ 2050 Type: "aws_instance", 2051 Primary: &InstanceState{ 2052 ID: "bar", 2053 }, 2054 }, 2055 }, 2056 }, 2057 }, 2058 } 2059 2060 ctx := testContext2(t, &ContextOpts{ 2061 Module: m, 2062 State: state, 2063 Providers: map[string]ResourceProviderFactory{ 2064 "aws": testProviderFuncFixed(p), 2065 }, 2066 }) 2067 2068 if _, err := ctx.Plan(); err != nil { 2069 t.Fatalf("err: %s", err) 2070 } 2071 2072 if _, err := ctx.Apply(); err != nil { 2073 t.Fatalf("err: %s", err) 2074 } 2075 } 2076 2077 func TestContext2Apply_moduleGrandchildProvider(t *testing.T) { 2078 m := testModule(t, "apply-module-grandchild-provider-inherit") 2079 p := testProvider("aws") 2080 p.ApplyFn = testApplyFn 2081 p.DiffFn = testDiffFn 2082 2083 var callLock sync.Mutex 2084 called := false 2085 p.ConfigureFn = func(c *ResourceConfig) error { 2086 if _, ok := c.Get("value"); !ok { 2087 return fmt.Errorf("value is not found") 2088 } 2089 callLock.Lock() 2090 called = true 2091 callLock.Unlock() 2092 2093 return nil 2094 } 2095 2096 ctx := testContext2(t, &ContextOpts{ 2097 Module: m, 2098 Providers: map[string]ResourceProviderFactory{ 2099 "aws": testProviderFuncFixed(p), 2100 }, 2101 }) 2102 2103 if _, err := ctx.Plan(); err != nil { 2104 t.Fatalf("err: %s", err) 2105 } 2106 2107 if _, err := ctx.Apply(); err != nil { 2108 t.Fatalf("err: %s", err) 2109 } 2110 2111 callLock.Lock() 2112 defer callLock.Unlock() 2113 if called != true { 2114 t.Fatalf("err: configure never called") 2115 } 2116 } 2117 2118 // This tests an issue where all the providers in a module but not 2119 // in the root weren't being added to the root properly. In this test 2120 // case: aws is explicitly added to root, but "test" should be added to. 2121 // With the bug, it wasn't. 2122 func TestContext2Apply_moduleOnlyProvider(t *testing.T) { 2123 m := testModule(t, "apply-module-only-provider") 2124 p := testProvider("aws") 2125 p.ApplyFn = testApplyFn 2126 p.DiffFn = testDiffFn 2127 pTest := testProvider("test") 2128 pTest.ApplyFn = testApplyFn 2129 pTest.DiffFn = testDiffFn 2130 2131 ctx := testContext2(t, &ContextOpts{ 2132 Module: m, 2133 Providers: map[string]ResourceProviderFactory{ 2134 "aws": testProviderFuncFixed(p), 2135 "test": testProviderFuncFixed(pTest), 2136 }, 2137 }) 2138 2139 if _, err := ctx.Plan(); err != nil { 2140 t.Fatalf("err: %s", err) 2141 } 2142 2143 state, err := ctx.Apply() 2144 if err != nil { 2145 t.Fatalf("err: %s", err) 2146 } 2147 2148 actual := strings.TrimSpace(state.String()) 2149 expected := strings.TrimSpace(testTerraformApplyModuleOnlyProviderStr) 2150 if actual != expected { 2151 t.Fatalf("bad: \n%s", actual) 2152 } 2153 } 2154 2155 func TestContext2Apply_moduleProviderAlias(t *testing.T) { 2156 m := testModule(t, "apply-module-provider-alias") 2157 p := testProvider("aws") 2158 p.ApplyFn = testApplyFn 2159 p.DiffFn = testDiffFn 2160 ctx := testContext2(t, &ContextOpts{ 2161 Module: m, 2162 Providers: map[string]ResourceProviderFactory{ 2163 "aws": testProviderFuncFixed(p), 2164 }, 2165 }) 2166 2167 if _, err := ctx.Plan(); err != nil { 2168 t.Fatalf("err: %s", err) 2169 } 2170 2171 state, err := ctx.Apply() 2172 if err != nil { 2173 t.Fatalf("err: %s", err) 2174 } 2175 2176 actual := strings.TrimSpace(state.String()) 2177 expected := strings.TrimSpace(testTerraformApplyModuleProviderAliasStr) 2178 if actual != expected { 2179 t.Fatalf("bad: \n%s", actual) 2180 } 2181 } 2182 2183 func TestContext2Apply_moduleProviderAliasTargets(t *testing.T) { 2184 m := testModule(t, "apply-module-provider-alias") 2185 p := testProvider("aws") 2186 p.ApplyFn = testApplyFn 2187 p.DiffFn = testDiffFn 2188 ctx := testContext2(t, &ContextOpts{ 2189 Module: m, 2190 Providers: map[string]ResourceProviderFactory{ 2191 "aws": testProviderFuncFixed(p), 2192 }, 2193 Targets: []string{"no.thing"}, 2194 }) 2195 2196 if _, err := ctx.Plan(); err != nil { 2197 t.Fatalf("err: %s", err) 2198 } 2199 2200 state, err := ctx.Apply() 2201 if err != nil { 2202 t.Fatalf("err: %s", err) 2203 } 2204 2205 actual := strings.TrimSpace(state.String()) 2206 expected := strings.TrimSpace(` 2207 <no state> 2208 `) 2209 if actual != expected { 2210 t.Fatalf("bad: \n%s", actual) 2211 } 2212 } 2213 2214 func TestContext2Apply_moduleProviderCloseNested(t *testing.T) { 2215 m := testModule(t, "apply-module-provider-close-nested") 2216 p := testProvider("aws") 2217 p.ApplyFn = testApplyFn 2218 p.DiffFn = testDiffFn 2219 ctx := testContext2(t, &ContextOpts{ 2220 Module: m, 2221 Providers: map[string]ResourceProviderFactory{ 2222 "aws": testProviderFuncFixed(p), 2223 }, 2224 State: &State{ 2225 Modules: []*ModuleState{ 2226 &ModuleState{ 2227 Path: []string{"root", "child", "subchild"}, 2228 Resources: map[string]*ResourceState{ 2229 "aws_instance.foo": &ResourceState{ 2230 Type: "aws_instance", 2231 Primary: &InstanceState{ 2232 ID: "bar", 2233 }, 2234 }, 2235 }, 2236 }, 2237 }, 2238 }, 2239 Destroy: true, 2240 }) 2241 2242 if _, err := ctx.Plan(); err != nil { 2243 t.Fatalf("err: %s", err) 2244 } 2245 2246 if _, err := ctx.Apply(); err != nil { 2247 t.Fatalf("err: %s", err) 2248 } 2249 } 2250 2251 // Tests that variables used as module vars that reference data that 2252 // already exists in the state and requires no diff works properly. This 2253 // fixes an issue faced where module variables were pruned because they were 2254 // accessing "non-existent" resources (they existed, just not in the graph 2255 // cause they weren't in the diff). 2256 func TestContext2Apply_moduleVarRefExisting(t *testing.T) { 2257 m := testModule(t, "apply-ref-existing") 2258 p := testProvider("aws") 2259 p.ApplyFn = testApplyFn 2260 p.DiffFn = testDiffFn 2261 2262 state := &State{ 2263 Modules: []*ModuleState{ 2264 &ModuleState{ 2265 Path: rootModulePath, 2266 Resources: map[string]*ResourceState{ 2267 "aws_instance.foo": &ResourceState{ 2268 Type: "aws_instance", 2269 Primary: &InstanceState{ 2270 ID: "foo", 2271 Attributes: map[string]string{ 2272 "foo": "bar", 2273 }, 2274 }, 2275 }, 2276 }, 2277 }, 2278 }, 2279 } 2280 2281 ctx := testContext2(t, &ContextOpts{ 2282 Module: m, 2283 Providers: map[string]ResourceProviderFactory{ 2284 "aws": testProviderFuncFixed(p), 2285 }, 2286 State: state, 2287 }) 2288 2289 if _, err := ctx.Plan(); err != nil { 2290 t.Fatalf("err: %s", err) 2291 } 2292 2293 state, err := ctx.Apply() 2294 if err != nil { 2295 t.Fatalf("err: %s", err) 2296 } 2297 2298 actual := strings.TrimSpace(state.String()) 2299 expected := strings.TrimSpace(testTerraformApplyModuleVarRefExistingStr) 2300 if actual != expected { 2301 t.Fatalf("bad: \n%s", actual) 2302 } 2303 } 2304 2305 func TestContext2Apply_moduleVarResourceCount(t *testing.T) { 2306 m := testModule(t, "apply-module-var-resource-count") 2307 p := testProvider("aws") 2308 p.ApplyFn = testApplyFn 2309 p.DiffFn = testDiffFn 2310 ctx := testContext2(t, &ContextOpts{ 2311 Module: m, 2312 Providers: map[string]ResourceProviderFactory{ 2313 "aws": testProviderFuncFixed(p), 2314 }, 2315 Variables: map[string]interface{}{ 2316 "count": "2", 2317 }, 2318 Destroy: true, 2319 }) 2320 2321 if _, err := ctx.Plan(); err != nil { 2322 t.Fatalf("err: %s", err) 2323 } 2324 2325 if _, err := ctx.Apply(); err != nil { 2326 t.Fatalf("err: %s", err) 2327 } 2328 2329 ctx = testContext2(t, &ContextOpts{ 2330 Module: m, 2331 Providers: map[string]ResourceProviderFactory{ 2332 "aws": testProviderFuncFixed(p), 2333 }, 2334 Variables: map[string]interface{}{ 2335 "count": "5", 2336 }, 2337 }) 2338 2339 if _, err := ctx.Plan(); err != nil { 2340 t.Fatalf("err: %s", err) 2341 } 2342 2343 if _, err := ctx.Apply(); err != nil { 2344 t.Fatalf("err: %s", err) 2345 } 2346 } 2347 2348 // GH-819 2349 func TestContext2Apply_moduleBool(t *testing.T) { 2350 m := testModule(t, "apply-module-bool") 2351 p := testProvider("aws") 2352 p.ApplyFn = testApplyFn 2353 p.DiffFn = testDiffFn 2354 ctx := testContext2(t, &ContextOpts{ 2355 Module: m, 2356 Providers: map[string]ResourceProviderFactory{ 2357 "aws": testProviderFuncFixed(p), 2358 }, 2359 }) 2360 2361 if _, err := ctx.Plan(); err != nil { 2362 t.Fatalf("err: %s", err) 2363 } 2364 2365 state, err := ctx.Apply() 2366 if err != nil { 2367 t.Fatalf("err: %s", err) 2368 } 2369 2370 actual := strings.TrimSpace(state.String()) 2371 expected := strings.TrimSpace(testTerraformApplyModuleBoolStr) 2372 if actual != expected { 2373 t.Fatalf("bad: \n%s", actual) 2374 } 2375 } 2376 2377 func TestContext2Apply_multiProvider(t *testing.T) { 2378 m := testModule(t, "apply-multi-provider") 2379 p := testProvider("aws") 2380 p.ApplyFn = testApplyFn 2381 p.DiffFn = testDiffFn 2382 2383 pDO := testProvider("do") 2384 pDO.ApplyFn = testApplyFn 2385 pDO.DiffFn = testDiffFn 2386 2387 ctx := testContext2(t, &ContextOpts{ 2388 Module: m, 2389 Providers: map[string]ResourceProviderFactory{ 2390 "aws": testProviderFuncFixed(p), 2391 "do": testProviderFuncFixed(pDO), 2392 }, 2393 }) 2394 2395 if _, err := ctx.Plan(); err != nil { 2396 t.Fatalf("err: %s", err) 2397 } 2398 2399 state, err := ctx.Apply() 2400 if err != nil { 2401 t.Fatalf("err: %s", err) 2402 } 2403 2404 mod := state.RootModule() 2405 if len(mod.Resources) < 2 { 2406 t.Fatalf("bad: %#v", mod.Resources) 2407 } 2408 2409 actual := strings.TrimSpace(state.String()) 2410 expected := strings.TrimSpace(testTerraformApplyMultiProviderStr) 2411 if actual != expected { 2412 t.Fatalf("bad: \n%s", actual) 2413 } 2414 } 2415 2416 func TestContext2Apply_multiVar(t *testing.T) { 2417 m := testModule(t, "apply-multi-var") 2418 p := testProvider("aws") 2419 p.ApplyFn = testApplyFn 2420 p.DiffFn = testDiffFn 2421 2422 // First, apply with a count of 3 2423 ctx := testContext2(t, &ContextOpts{ 2424 Module: m, 2425 Providers: map[string]ResourceProviderFactory{ 2426 "aws": testProviderFuncFixed(p), 2427 }, 2428 Variables: map[string]interface{}{ 2429 "count": "3", 2430 }, 2431 }) 2432 2433 if _, err := ctx.Plan(); err != nil { 2434 t.Fatalf("err: %s", err) 2435 } 2436 2437 state, err := ctx.Apply() 2438 if err != nil { 2439 t.Fatalf("err: %s", err) 2440 } 2441 2442 actual := state.RootModule().Outputs["output"] 2443 expected := "bar0,bar1,bar2" 2444 if actual == nil || actual.Value != expected { 2445 t.Fatalf("bad: \n%s", actual) 2446 } 2447 2448 t.Logf("Initial state: %s", state.String()) 2449 2450 // Apply again, reduce the count to 1 2451 { 2452 ctx := testContext2(t, &ContextOpts{ 2453 Module: m, 2454 State: state, 2455 Providers: map[string]ResourceProviderFactory{ 2456 "aws": testProviderFuncFixed(p), 2457 }, 2458 Variables: map[string]interface{}{ 2459 "count": "1", 2460 }, 2461 }) 2462 2463 if _, err := ctx.Plan(); err != nil { 2464 t.Fatalf("err: %s", err) 2465 } 2466 2467 state, err := ctx.Apply() 2468 if err != nil { 2469 t.Fatalf("err: %s", err) 2470 } 2471 2472 t.Logf("End state: %s", state.String()) 2473 2474 actual := state.RootModule().Outputs["output"] 2475 if actual == nil { 2476 t.Fatal("missing output") 2477 } 2478 2479 expected := "bar0" 2480 if actual.Value != expected { 2481 t.Fatalf("bad: \n%s", actual) 2482 } 2483 } 2484 } 2485 2486 // Test that multi-var (splat) access is ordered by count, not by 2487 // value. 2488 func TestContext2Apply_multiVarOrder(t *testing.T) { 2489 m := testModule(t, "apply-multi-var-order") 2490 p := testProvider("aws") 2491 p.ApplyFn = testApplyFn 2492 p.DiffFn = testDiffFn 2493 2494 // First, apply with a count of 3 2495 ctx := testContext2(t, &ContextOpts{ 2496 Module: m, 2497 Providers: map[string]ResourceProviderFactory{ 2498 "aws": testProviderFuncFixed(p), 2499 }, 2500 }) 2501 2502 if _, err := ctx.Plan(); err != nil { 2503 t.Fatalf("err: %s", err) 2504 } 2505 2506 state, err := ctx.Apply() 2507 if err != nil { 2508 t.Fatalf("err: %s", err) 2509 } 2510 2511 t.Logf("State: %s", state.String()) 2512 2513 actual := state.RootModule().Outputs["should-be-11"] 2514 expected := "index-11" 2515 if actual == nil || actual.Value != expected { 2516 t.Fatalf("bad: \n%s", actual) 2517 } 2518 } 2519 2520 // Test that multi-var (splat) access is ordered by count, not by 2521 // value, through interpolations. 2522 func TestContext2Apply_multiVarOrderInterp(t *testing.T) { 2523 m := testModule(t, "apply-multi-var-order-interp") 2524 p := testProvider("aws") 2525 p.ApplyFn = testApplyFn 2526 p.DiffFn = testDiffFn 2527 2528 // First, apply with a count of 3 2529 ctx := testContext2(t, &ContextOpts{ 2530 Module: m, 2531 Providers: map[string]ResourceProviderFactory{ 2532 "aws": testProviderFuncFixed(p), 2533 }, 2534 }) 2535 2536 if _, err := ctx.Plan(); err != nil { 2537 t.Fatalf("err: %s", err) 2538 } 2539 2540 state, err := ctx.Apply() 2541 if err != nil { 2542 t.Fatalf("err: %s", err) 2543 } 2544 2545 t.Logf("State: %s", state.String()) 2546 2547 actual := state.RootModule().Outputs["should-be-11"] 2548 expected := "baz-index-11" 2549 if actual == nil || actual.Value != expected { 2550 t.Fatalf("bad: \n%s", actual) 2551 } 2552 } 2553 2554 func TestContext2Apply_nilDiff(t *testing.T) { 2555 m := testModule(t, "apply-good") 2556 p := testProvider("aws") 2557 p.ApplyFn = testApplyFn 2558 p.DiffFn = testDiffFn 2559 ctx := testContext2(t, &ContextOpts{ 2560 Module: m, 2561 Providers: map[string]ResourceProviderFactory{ 2562 "aws": testProviderFuncFixed(p), 2563 }, 2564 }) 2565 2566 if _, err := ctx.Plan(); err != nil { 2567 t.Fatalf("err: %s", err) 2568 } 2569 2570 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 2571 return nil, nil 2572 } 2573 2574 if _, err := ctx.Apply(); err == nil { 2575 t.Fatal("should error") 2576 } 2577 } 2578 2579 func TestContext2Apply_outputDependsOn(t *testing.T) { 2580 m := testModule(t, "apply-output-depends-on") 2581 p := testProvider("aws") 2582 p.DiffFn = testDiffFn 2583 2584 { 2585 // Create a custom apply function that sleeps a bit (to allow parallel 2586 // graph execution) and then returns an error to force a partial state 2587 // return. We then verify the output is NOT there. 2588 p.ApplyFn = func( 2589 info *InstanceInfo, 2590 is *InstanceState, 2591 id *InstanceDiff) (*InstanceState, error) { 2592 2593 // Sleep to allow parallel execution 2594 time.Sleep(50 * time.Millisecond) 2595 2596 // Return error to force partial state 2597 return nil, fmt.Errorf("abcd") 2598 } 2599 2600 ctx := testContext2(t, &ContextOpts{ 2601 Module: m, 2602 Providers: map[string]ResourceProviderFactory{ 2603 "aws": testProviderFuncFixed(p), 2604 }, 2605 }) 2606 2607 if _, err := ctx.Plan(); err != nil { 2608 t.Fatalf("err: %s", err) 2609 } 2610 2611 state, err := ctx.Apply() 2612 if err == nil || !strings.Contains(err.Error(), "abcd") { 2613 t.Fatalf("err: %s", err) 2614 } 2615 2616 checkStateString(t, state, `<no state>`) 2617 } 2618 2619 { 2620 // Create the standard apply function and verify we get the output 2621 p.ApplyFn = testApplyFn 2622 2623 ctx := testContext2(t, &ContextOpts{ 2624 Module: m, 2625 Providers: map[string]ResourceProviderFactory{ 2626 "aws": testProviderFuncFixed(p), 2627 }, 2628 }) 2629 2630 if _, err := ctx.Plan(); err != nil { 2631 t.Fatalf("err: %s", err) 2632 } 2633 2634 state, err := ctx.Apply() 2635 if err != nil { 2636 t.Fatalf("err: %s", err) 2637 } 2638 2639 checkStateString(t, state, ` 2640 aws_instance.foo: 2641 ID = foo 2642 2643 Outputs: 2644 2645 value = result 2646 `) 2647 } 2648 } 2649 2650 func TestContext2Apply_outputOrphan(t *testing.T) { 2651 m := testModule(t, "apply-output-orphan") 2652 p := testProvider("aws") 2653 p.ApplyFn = testApplyFn 2654 p.DiffFn = testDiffFn 2655 2656 state := &State{ 2657 Modules: []*ModuleState{ 2658 &ModuleState{ 2659 Path: rootModulePath, 2660 Outputs: map[string]*OutputState{ 2661 "foo": &OutputState{ 2662 Type: "string", 2663 Sensitive: false, 2664 Value: "bar", 2665 }, 2666 "bar": &OutputState{ 2667 Type: "string", 2668 Sensitive: false, 2669 Value: "baz", 2670 }, 2671 }, 2672 }, 2673 }, 2674 } 2675 2676 ctx := testContext2(t, &ContextOpts{ 2677 Module: m, 2678 Providers: map[string]ResourceProviderFactory{ 2679 "aws": testProviderFuncFixed(p), 2680 }, 2681 State: state, 2682 }) 2683 2684 if _, err := ctx.Plan(); err != nil { 2685 t.Fatalf("err: %s", err) 2686 } 2687 2688 state, err := ctx.Apply() 2689 if err != nil { 2690 t.Fatalf("err: %s", err) 2691 } 2692 2693 actual := strings.TrimSpace(state.String()) 2694 expected := strings.TrimSpace(testTerraformApplyOutputOrphanStr) 2695 if actual != expected { 2696 t.Fatalf("bad: \n%s", actual) 2697 } 2698 } 2699 2700 func TestContext2Apply_outputOrphanModule(t *testing.T) { 2701 m := testModule(t, "apply-output-orphan-module") 2702 p := testProvider("aws") 2703 p.ApplyFn = testApplyFn 2704 p.DiffFn = testDiffFn 2705 2706 state := &State{ 2707 Modules: []*ModuleState{ 2708 &ModuleState{ 2709 Path: []string{"root", "child"}, 2710 Outputs: map[string]*OutputState{ 2711 "foo": &OutputState{ 2712 Type: "string", 2713 Value: "bar", 2714 }, 2715 "bar": &OutputState{ 2716 Type: "string", 2717 Value: "baz", 2718 }, 2719 }, 2720 }, 2721 }, 2722 } 2723 2724 ctx := testContext2(t, &ContextOpts{ 2725 Module: m, 2726 Providers: map[string]ResourceProviderFactory{ 2727 "aws": testProviderFuncFixed(p), 2728 }, 2729 State: state, 2730 }) 2731 2732 if _, err := ctx.Plan(); err != nil { 2733 t.Fatalf("err: %s", err) 2734 } 2735 2736 state, err := ctx.Apply() 2737 if err != nil { 2738 t.Fatalf("err: %s", err) 2739 } 2740 2741 actual := strings.TrimSpace(state.String()) 2742 expected := strings.TrimSpace(testTerraformApplyOutputOrphanModuleStr) 2743 if actual != expected { 2744 t.Fatalf("bad: \n%s", actual) 2745 } 2746 } 2747 2748 func TestContext2Apply_providerComputedVar(t *testing.T) { 2749 m := testModule(t, "apply-provider-computed") 2750 p := testProvider("aws") 2751 p.ApplyFn = testApplyFn 2752 p.DiffFn = testDiffFn 2753 2754 pTest := testProvider("test") 2755 pTest.ApplyFn = testApplyFn 2756 pTest.DiffFn = testDiffFn 2757 2758 ctx := testContext2(t, &ContextOpts{ 2759 Module: m, 2760 Providers: map[string]ResourceProviderFactory{ 2761 "aws": testProviderFuncFixed(p), 2762 "test": testProviderFuncFixed(pTest), 2763 }, 2764 }) 2765 2766 p.ConfigureFn = func(c *ResourceConfig) error { 2767 if c.IsComputed("value") { 2768 return fmt.Errorf("value is computed") 2769 } 2770 2771 v, ok := c.Get("value") 2772 if !ok { 2773 return fmt.Errorf("value is not found") 2774 } 2775 if v != "yes" { 2776 return fmt.Errorf("value is not 'yes': %v", v) 2777 } 2778 2779 return nil 2780 } 2781 2782 if _, err := ctx.Plan(); err != nil { 2783 t.Fatalf("err: %s", err) 2784 } 2785 2786 if _, err := ctx.Apply(); err != nil { 2787 t.Fatalf("err: %s", err) 2788 } 2789 } 2790 2791 func TestContext2Apply_providerConfigureDisabled(t *testing.T) { 2792 m := testModule(t, "apply-provider-configure-disabled") 2793 p := testProvider("aws") 2794 p.ApplyFn = testApplyFn 2795 p.DiffFn = testDiffFn 2796 2797 called := false 2798 p.ConfigureFn = func(c *ResourceConfig) error { 2799 called = true 2800 2801 if _, ok := c.Get("value"); !ok { 2802 return fmt.Errorf("value is not found") 2803 } 2804 2805 return nil 2806 } 2807 2808 ctx := testContext2(t, &ContextOpts{ 2809 Module: m, 2810 Providers: map[string]ResourceProviderFactory{ 2811 "aws": testProviderFuncFixed(p), 2812 }, 2813 }) 2814 2815 if _, err := ctx.Plan(); err != nil { 2816 t.Fatalf("err: %s", err) 2817 } 2818 2819 if _, err := ctx.Apply(); err != nil { 2820 t.Fatalf("err: %s", err) 2821 } 2822 2823 if !called { 2824 t.Fatal("configure never called") 2825 } 2826 } 2827 2828 func TestContext2Apply_provisionerModule(t *testing.T) { 2829 m := testModule(t, "apply-provisioner-module") 2830 p := testProvider("aws") 2831 pr := testProvisioner() 2832 p.ApplyFn = testApplyFn 2833 p.DiffFn = testDiffFn 2834 ctx := testContext2(t, &ContextOpts{ 2835 Module: m, 2836 Providers: map[string]ResourceProviderFactory{ 2837 "aws": testProviderFuncFixed(p), 2838 }, 2839 Provisioners: map[string]ResourceProvisionerFactory{ 2840 "shell": testProvisionerFuncFixed(pr), 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 actual := strings.TrimSpace(state.String()) 2854 expected := strings.TrimSpace(testTerraformApplyProvisionerModuleStr) 2855 if actual != expected { 2856 t.Fatalf("bad: \n%s", actual) 2857 } 2858 2859 // Verify apply was invoked 2860 if !pr.ApplyCalled { 2861 t.Fatalf("provisioner not invoked") 2862 } 2863 } 2864 2865 func TestContext2Apply_Provisioner_compute(t *testing.T) { 2866 m := testModule(t, "apply-provisioner-compute") 2867 p := testProvider("aws") 2868 pr := testProvisioner() 2869 p.ApplyFn = testApplyFn 2870 p.DiffFn = testDiffFn 2871 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 2872 val, ok := c.Config["foo"] 2873 if !ok || val != "computed_dynamical" { 2874 t.Fatalf("bad value for foo: %v %#v", val, c) 2875 } 2876 2877 return nil 2878 } 2879 ctx := testContext2(t, &ContextOpts{ 2880 Module: m, 2881 Providers: map[string]ResourceProviderFactory{ 2882 "aws": testProviderFuncFixed(p), 2883 }, 2884 Provisioners: map[string]ResourceProvisionerFactory{ 2885 "shell": testProvisionerFuncFixed(pr), 2886 }, 2887 Variables: map[string]interface{}{ 2888 "value": "1", 2889 }, 2890 }) 2891 2892 if _, err := ctx.Plan(); err != nil { 2893 t.Fatalf("err: %s", err) 2894 } 2895 2896 state, err := ctx.Apply() 2897 if err != nil { 2898 t.Fatalf("err: %s", err) 2899 } 2900 2901 actual := strings.TrimSpace(state.String()) 2902 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 2903 if actual != expected { 2904 t.Fatalf("bad: \n%s", actual) 2905 } 2906 2907 // Verify apply was invoked 2908 if !pr.ApplyCalled { 2909 t.Fatalf("provisioner not invoked") 2910 } 2911 } 2912 2913 func TestContext2Apply_provisionerCreateFail(t *testing.T) { 2914 m := testModule(t, "apply-provisioner-fail-create") 2915 p := testProvider("aws") 2916 pr := testProvisioner() 2917 p.DiffFn = testDiffFn 2918 2919 p.ApplyFn = func( 2920 info *InstanceInfo, 2921 is *InstanceState, 2922 id *InstanceDiff) (*InstanceState, error) { 2923 is.ID = "foo" 2924 return is, fmt.Errorf("error") 2925 } 2926 2927 ctx := testContext2(t, &ContextOpts{ 2928 Module: m, 2929 Providers: map[string]ResourceProviderFactory{ 2930 "aws": testProviderFuncFixed(p), 2931 }, 2932 Provisioners: map[string]ResourceProvisionerFactory{ 2933 "shell": testProvisionerFuncFixed(pr), 2934 }, 2935 }) 2936 2937 if _, err := ctx.Plan(); err != nil { 2938 t.Fatalf("err: %s", err) 2939 } 2940 2941 state, err := ctx.Apply() 2942 if err == nil { 2943 t.Fatal("should error") 2944 } 2945 2946 actual := strings.TrimSpace(state.String()) 2947 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateStr) 2948 if actual != expected { 2949 t.Fatalf("bad: \n%s", actual) 2950 } 2951 } 2952 2953 func TestContext2Apply_provisionerCreateFailNoId(t *testing.T) { 2954 m := testModule(t, "apply-provisioner-fail-create") 2955 p := testProvider("aws") 2956 pr := testProvisioner() 2957 p.DiffFn = testDiffFn 2958 2959 p.ApplyFn = func( 2960 info *InstanceInfo, 2961 is *InstanceState, 2962 id *InstanceDiff) (*InstanceState, error) { 2963 return nil, fmt.Errorf("error") 2964 } 2965 2966 ctx := testContext2(t, &ContextOpts{ 2967 Module: m, 2968 Providers: map[string]ResourceProviderFactory{ 2969 "aws": testProviderFuncFixed(p), 2970 }, 2971 Provisioners: map[string]ResourceProvisionerFactory{ 2972 "shell": testProvisionerFuncFixed(pr), 2973 }, 2974 }) 2975 2976 if _, err := ctx.Plan(); err != nil { 2977 t.Fatalf("err: %s", err) 2978 } 2979 2980 state, err := ctx.Apply() 2981 if err == nil { 2982 t.Fatal("should error") 2983 } 2984 2985 actual := strings.TrimSpace(state.String()) 2986 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateNoIdStr) 2987 if actual != expected { 2988 t.Fatalf("bad: \n%s", actual) 2989 } 2990 } 2991 2992 func TestContext2Apply_provisionerFail(t *testing.T) { 2993 m := testModule(t, "apply-provisioner-fail") 2994 p := testProvider("aws") 2995 pr := testProvisioner() 2996 p.ApplyFn = testApplyFn 2997 p.DiffFn = testDiffFn 2998 2999 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 3000 return fmt.Errorf("EXPLOSION") 3001 } 3002 3003 ctx := testContext2(t, &ContextOpts{ 3004 Module: m, 3005 Providers: map[string]ResourceProviderFactory{ 3006 "aws": testProviderFuncFixed(p), 3007 }, 3008 Provisioners: map[string]ResourceProvisionerFactory{ 3009 "shell": testProvisionerFuncFixed(pr), 3010 }, 3011 Variables: map[string]interface{}{ 3012 "value": "1", 3013 }, 3014 }) 3015 3016 if _, err := ctx.Plan(); err != nil { 3017 t.Fatalf("err: %s", err) 3018 } 3019 3020 state, err := ctx.Apply() 3021 if err == nil { 3022 t.Fatal("should error") 3023 } 3024 3025 actual := strings.TrimSpace(state.String()) 3026 expected := strings.TrimSpace(testTerraformApplyProvisionerFailStr) 3027 if actual != expected { 3028 t.Fatalf("bad: \n%s", actual) 3029 } 3030 } 3031 3032 func TestContext2Apply_provisionerFail_createBeforeDestroy(t *testing.T) { 3033 m := testModule(t, "apply-provisioner-fail-create-before") 3034 p := testProvider("aws") 3035 pr := testProvisioner() 3036 p.ApplyFn = testApplyFn 3037 p.DiffFn = testDiffFn 3038 pr.ApplyFn = func(*InstanceState, *ResourceConfig) error { 3039 return fmt.Errorf("EXPLOSION") 3040 } 3041 3042 state := &State{ 3043 Modules: []*ModuleState{ 3044 &ModuleState{ 3045 Path: rootModulePath, 3046 Resources: map[string]*ResourceState{ 3047 "aws_instance.bar": &ResourceState{ 3048 Type: "aws_instance", 3049 Primary: &InstanceState{ 3050 ID: "bar", 3051 Attributes: map[string]string{ 3052 "require_new": "abc", 3053 }, 3054 }, 3055 }, 3056 }, 3057 }, 3058 }, 3059 } 3060 ctx := testContext2(t, &ContextOpts{ 3061 Module: m, 3062 Providers: map[string]ResourceProviderFactory{ 3063 "aws": testProviderFuncFixed(p), 3064 }, 3065 Provisioners: map[string]ResourceProvisionerFactory{ 3066 "shell": testProvisionerFuncFixed(pr), 3067 }, 3068 State: state, 3069 }) 3070 3071 if _, err := ctx.Plan(); err != nil { 3072 t.Fatalf("err: %s", err) 3073 } 3074 3075 state, err := ctx.Apply() 3076 if err == nil { 3077 t.Fatal("should error") 3078 } 3079 3080 actual := strings.TrimSpace(state.String()) 3081 expected := strings.TrimSpace(testTerraformApplyProvisionerFailCreateBeforeDestroyStr) 3082 if actual != expected { 3083 t.Fatalf("bad: \n%s", actual) 3084 } 3085 } 3086 3087 func TestContext2Apply_error_createBeforeDestroy(t *testing.T) { 3088 m := testModule(t, "apply-error-create-before") 3089 p := testProvider("aws") 3090 state := &State{ 3091 Modules: []*ModuleState{ 3092 &ModuleState{ 3093 Path: rootModulePath, 3094 Resources: map[string]*ResourceState{ 3095 "aws_instance.bar": &ResourceState{ 3096 Type: "aws_instance", 3097 Primary: &InstanceState{ 3098 ID: "bar", 3099 Attributes: map[string]string{ 3100 "require_new": "abc", 3101 }, 3102 }, 3103 }, 3104 }, 3105 }, 3106 }, 3107 } 3108 ctx := testContext2(t, &ContextOpts{ 3109 Module: m, 3110 Providers: map[string]ResourceProviderFactory{ 3111 "aws": testProviderFuncFixed(p), 3112 }, 3113 State: state, 3114 }) 3115 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 3116 return nil, fmt.Errorf("error") 3117 } 3118 p.DiffFn = testDiffFn 3119 3120 if _, err := ctx.Plan(); err != nil { 3121 t.Fatalf("err: %s", err) 3122 } 3123 3124 state, err := ctx.Apply() 3125 if err == nil { 3126 t.Fatal("should have error") 3127 } 3128 3129 actual := strings.TrimSpace(state.String()) 3130 expected := strings.TrimSpace(testTerraformApplyErrorCreateBeforeDestroyStr) 3131 if actual != expected { 3132 t.Fatalf("bad: \n%s\n\nExpected:\n\n%s", actual, expected) 3133 } 3134 } 3135 3136 func TestContext2Apply_errorDestroy_createBeforeDestroy(t *testing.T) { 3137 m := testModule(t, "apply-error-create-before") 3138 p := testProvider("aws") 3139 state := &State{ 3140 Modules: []*ModuleState{ 3141 &ModuleState{ 3142 Path: rootModulePath, 3143 Resources: map[string]*ResourceState{ 3144 "aws_instance.bar": &ResourceState{ 3145 Type: "aws_instance", 3146 Primary: &InstanceState{ 3147 ID: "bar", 3148 Attributes: map[string]string{ 3149 "require_new": "abc", 3150 }, 3151 }, 3152 }, 3153 }, 3154 }, 3155 }, 3156 } 3157 ctx := testContext2(t, &ContextOpts{ 3158 Module: m, 3159 Providers: map[string]ResourceProviderFactory{ 3160 "aws": testProviderFuncFixed(p), 3161 }, 3162 State: state, 3163 }) 3164 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 3165 // Fail the destroy! 3166 if id.Destroy { 3167 return is, fmt.Errorf("error") 3168 } 3169 3170 // Create should work 3171 is = &InstanceState{ 3172 ID: "foo", 3173 } 3174 return is, nil 3175 } 3176 p.DiffFn = testDiffFn 3177 3178 if _, err := ctx.Plan(); err != nil { 3179 t.Fatalf("err: %s", err) 3180 } 3181 3182 state, err := ctx.Apply() 3183 if err == nil { 3184 t.Fatal("should have error") 3185 } 3186 3187 actual := strings.TrimSpace(state.String()) 3188 expected := strings.TrimSpace(testTerraformApplyErrorDestroyCreateBeforeDestroyStr) 3189 if actual != expected { 3190 t.Fatalf("bad: actual:\n%s\n\nexpected:\n%s", actual, expected) 3191 } 3192 } 3193 3194 func TestContext2Apply_multiDepose_createBeforeDestroy(t *testing.T) { 3195 m := testModule(t, "apply-multi-depose-create-before-destroy") 3196 p := testProvider("aws") 3197 p.DiffFn = testDiffFn 3198 ps := map[string]ResourceProviderFactory{"aws": testProviderFuncFixed(p)} 3199 state := &State{ 3200 Modules: []*ModuleState{ 3201 &ModuleState{ 3202 Path: rootModulePath, 3203 Resources: map[string]*ResourceState{ 3204 "aws_instance.web": &ResourceState{ 3205 Type: "aws_instance", 3206 Primary: &InstanceState{ID: "foo"}, 3207 }, 3208 }, 3209 }, 3210 }, 3211 } 3212 3213 ctx := testContext2(t, &ContextOpts{ 3214 Module: m, 3215 Providers: ps, 3216 State: state, 3217 }) 3218 createdInstanceId := "bar" 3219 // Create works 3220 createFunc := func(is *InstanceState) (*InstanceState, error) { 3221 return &InstanceState{ID: createdInstanceId}, nil 3222 } 3223 // Destroy starts broken 3224 destroyFunc := func(is *InstanceState) (*InstanceState, error) { 3225 return is, fmt.Errorf("destroy failed") 3226 } 3227 p.ApplyFn = func(info *InstanceInfo, is *InstanceState, id *InstanceDiff) (*InstanceState, error) { 3228 if id.Destroy { 3229 return destroyFunc(is) 3230 } else { 3231 return createFunc(is) 3232 } 3233 } 3234 3235 if _, err := ctx.Plan(); err != nil { 3236 t.Fatalf("err: %s", err) 3237 } 3238 3239 // Destroy is broken, so even though CBD successfully replaces the instance, 3240 // we'll have to save the Deposed instance to destroy later 3241 state, err := ctx.Apply() 3242 if err == nil { 3243 t.Fatal("should have error") 3244 } 3245 3246 checkStateString(t, state, ` 3247 aws_instance.web: (1 deposed) 3248 ID = bar 3249 Deposed ID 1 = foo 3250 `) 3251 3252 createdInstanceId = "baz" 3253 ctx = testContext2(t, &ContextOpts{ 3254 Module: m, 3255 Providers: ps, 3256 State: state, 3257 }) 3258 3259 if _, err := ctx.Plan(); err != nil { 3260 t.Fatalf("err: %s", err) 3261 } 3262 3263 // We're replacing the primary instance once again. Destroy is _still_ 3264 // broken, so the Deposed list gets longer 3265 state, err = ctx.Apply() 3266 if err == nil { 3267 t.Fatal("should have error") 3268 } 3269 3270 checkStateString(t, state, ` 3271 aws_instance.web: (2 deposed) 3272 ID = baz 3273 Deposed ID 1 = foo 3274 Deposed ID 2 = bar 3275 `) 3276 3277 // Destroy partially fixed! 3278 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 3279 if is.ID == "foo" || is.ID == "baz" { 3280 return nil, nil 3281 } else { 3282 return is, fmt.Errorf("destroy partially failed") 3283 } 3284 } 3285 3286 createdInstanceId = "qux" 3287 if _, err := ctx.Plan(); err != nil { 3288 t.Fatalf("err: %s", err) 3289 } 3290 state, err = ctx.Apply() 3291 // Expect error because 1/2 of Deposed destroys failed 3292 if err == nil { 3293 t.Fatal("should have error") 3294 } 3295 3296 // foo and baz are now gone, bar sticks around 3297 checkStateString(t, state, ` 3298 aws_instance.web: (1 deposed) 3299 ID = qux 3300 Deposed ID 1 = bar 3301 `) 3302 3303 // Destroy working fully! 3304 destroyFunc = func(is *InstanceState) (*InstanceState, error) { 3305 return nil, nil 3306 } 3307 3308 createdInstanceId = "quux" 3309 if _, err := ctx.Plan(); err != nil { 3310 t.Fatalf("err: %s", err) 3311 } 3312 state, err = ctx.Apply() 3313 if err != nil { 3314 t.Fatal("should not have error:", err) 3315 } 3316 3317 // And finally the state is clean 3318 checkStateString(t, state, ` 3319 aws_instance.web: 3320 ID = quux 3321 `) 3322 } 3323 3324 func TestContext2Apply_provisionerResourceRef(t *testing.T) { 3325 m := testModule(t, "apply-provisioner-resource-ref") 3326 p := testProvider("aws") 3327 pr := testProvisioner() 3328 p.ApplyFn = testApplyFn 3329 p.DiffFn = testDiffFn 3330 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3331 val, ok := c.Config["foo"] 3332 if !ok || val != "2" { 3333 t.Fatalf("bad value for foo: %v %#v", val, c) 3334 } 3335 3336 return nil 3337 } 3338 3339 ctx := testContext2(t, &ContextOpts{ 3340 Module: m, 3341 Providers: map[string]ResourceProviderFactory{ 3342 "aws": testProviderFuncFixed(p), 3343 }, 3344 Provisioners: map[string]ResourceProvisionerFactory{ 3345 "shell": testProvisionerFuncFixed(pr), 3346 }, 3347 }) 3348 3349 if _, err := ctx.Plan(); err != nil { 3350 t.Fatalf("err: %s", err) 3351 } 3352 3353 state, err := ctx.Apply() 3354 if err != nil { 3355 t.Fatalf("err: %s", err) 3356 } 3357 3358 actual := strings.TrimSpace(state.String()) 3359 expected := strings.TrimSpace(testTerraformApplyProvisionerResourceRefStr) 3360 if actual != expected { 3361 t.Fatalf("bad: \n%s", actual) 3362 } 3363 3364 // Verify apply was invoked 3365 if !pr.ApplyCalled { 3366 t.Fatalf("provisioner not invoked") 3367 } 3368 } 3369 3370 func TestContext2Apply_provisionerSelfRef(t *testing.T) { 3371 m := testModule(t, "apply-provisioner-self-ref") 3372 p := testProvider("aws") 3373 pr := testProvisioner() 3374 p.ApplyFn = testApplyFn 3375 p.DiffFn = testDiffFn 3376 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3377 val, ok := c.Config["command"] 3378 if !ok || val != "bar" { 3379 t.Fatalf("bad value for command: %v %#v", val, c) 3380 } 3381 3382 return nil 3383 } 3384 3385 ctx := testContext2(t, &ContextOpts{ 3386 Module: m, 3387 Providers: map[string]ResourceProviderFactory{ 3388 "aws": testProviderFuncFixed(p), 3389 }, 3390 Provisioners: map[string]ResourceProvisionerFactory{ 3391 "shell": testProvisionerFuncFixed(pr), 3392 }, 3393 }) 3394 3395 if _, err := ctx.Plan(); err != nil { 3396 t.Fatalf("err: %s", err) 3397 } 3398 3399 state, err := ctx.Apply() 3400 if err != nil { 3401 t.Fatalf("err: %s", err) 3402 } 3403 3404 actual := strings.TrimSpace(state.String()) 3405 expected := strings.TrimSpace(testTerraformApplyProvisionerSelfRefStr) 3406 if actual != expected { 3407 t.Fatalf("bad: \n%s", actual) 3408 } 3409 3410 // Verify apply was invoked 3411 if !pr.ApplyCalled { 3412 t.Fatalf("provisioner not invoked") 3413 } 3414 } 3415 3416 func TestContext2Apply_provisionerMultiSelfRef(t *testing.T) { 3417 var lock sync.Mutex 3418 commands := make([]string, 0, 5) 3419 3420 m := testModule(t, "apply-provisioner-multi-self-ref") 3421 p := testProvider("aws") 3422 pr := testProvisioner() 3423 p.ApplyFn = testApplyFn 3424 p.DiffFn = testDiffFn 3425 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3426 lock.Lock() 3427 defer lock.Unlock() 3428 3429 val, ok := c.Config["command"] 3430 if !ok { 3431 t.Fatalf("bad value for command: %v %#v", val, c) 3432 } 3433 3434 commands = append(commands, val.(string)) 3435 return nil 3436 } 3437 3438 ctx := testContext2(t, &ContextOpts{ 3439 Module: m, 3440 Providers: map[string]ResourceProviderFactory{ 3441 "aws": testProviderFuncFixed(p), 3442 }, 3443 Provisioners: map[string]ResourceProvisionerFactory{ 3444 "shell": testProvisionerFuncFixed(pr), 3445 }, 3446 }) 3447 3448 if _, err := ctx.Plan(); err != nil { 3449 t.Fatalf("err: %s", err) 3450 } 3451 3452 state, err := ctx.Apply() 3453 if err != nil { 3454 t.Fatalf("err: %s", err) 3455 } 3456 3457 actual := strings.TrimSpace(state.String()) 3458 expected := strings.TrimSpace(testTerraformApplyProvisionerMultiSelfRefStr) 3459 if actual != expected { 3460 t.Fatalf("bad: \n%s", actual) 3461 } 3462 3463 // Verify apply was invoked 3464 if !pr.ApplyCalled { 3465 t.Fatalf("provisioner not invoked") 3466 } 3467 3468 // Verify our result 3469 sort.Strings(commands) 3470 expectedCommands := []string{"number 0", "number 1", "number 2"} 3471 if !reflect.DeepEqual(commands, expectedCommands) { 3472 t.Fatalf("bad: %#v", commands) 3473 } 3474 } 3475 3476 func TestContext2Apply_provisionerMultiSelfRefCount(t *testing.T) { 3477 var lock sync.Mutex 3478 commands := make([]string, 0, 5) 3479 3480 m := testModule(t, "apply-provisioner-multi-self-ref-count") 3481 p := testProvider("aws") 3482 pr := testProvisioner() 3483 p.ApplyFn = testApplyFn 3484 p.DiffFn = testDiffFn 3485 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3486 lock.Lock() 3487 defer lock.Unlock() 3488 3489 val, ok := c.Config["command"] 3490 if !ok { 3491 t.Fatalf("bad value for command: %v %#v", val, c) 3492 } 3493 3494 commands = append(commands, val.(string)) 3495 return nil 3496 } 3497 3498 ctx := testContext2(t, &ContextOpts{ 3499 Module: m, 3500 Providers: map[string]ResourceProviderFactory{ 3501 "aws": testProviderFuncFixed(p), 3502 }, 3503 Provisioners: map[string]ResourceProvisionerFactory{ 3504 "shell": testProvisionerFuncFixed(pr), 3505 }, 3506 }) 3507 3508 if _, err := ctx.Plan(); err != nil { 3509 t.Fatalf("err: %s", err) 3510 } 3511 3512 if _, err := ctx.Apply(); err != nil { 3513 t.Fatalf("err: %s", err) 3514 } 3515 3516 // Verify apply was invoked 3517 if !pr.ApplyCalled { 3518 t.Fatalf("provisioner not invoked") 3519 } 3520 3521 // Verify our result 3522 sort.Strings(commands) 3523 expectedCommands := []string{"3", "3", "3"} 3524 if !reflect.DeepEqual(commands, expectedCommands) { 3525 t.Fatalf("bad: %#v", commands) 3526 } 3527 } 3528 3529 func TestContext2Apply_provisionerExplicitSelfRef(t *testing.T) { 3530 m := testModule(t, "apply-provisioner-explicit-self-ref") 3531 p := testProvider("aws") 3532 pr := testProvisioner() 3533 p.ApplyFn = testApplyFn 3534 p.DiffFn = testDiffFn 3535 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3536 val, ok := c.Config["command"] 3537 if !ok || val != "bar" { 3538 t.Fatalf("bad value for command: %v %#v", val, c) 3539 } 3540 3541 return nil 3542 } 3543 3544 var state *State 3545 { 3546 ctx := testContext2(t, &ContextOpts{ 3547 Module: m, 3548 Providers: map[string]ResourceProviderFactory{ 3549 "aws": testProviderFuncFixed(p), 3550 }, 3551 Provisioners: map[string]ResourceProvisionerFactory{ 3552 "shell": testProvisionerFuncFixed(pr), 3553 }, 3554 }) 3555 3556 _, err := ctx.Plan() 3557 if err != nil { 3558 t.Fatalf("err: %s", err) 3559 } 3560 3561 state, err = ctx.Apply() 3562 if err != nil { 3563 t.Fatalf("err: %s", err) 3564 } 3565 3566 // Verify apply was invoked 3567 if !pr.ApplyCalled { 3568 t.Fatalf("provisioner not invoked") 3569 } 3570 } 3571 3572 { 3573 ctx := testContext2(t, &ContextOpts{ 3574 Module: m, 3575 Destroy: true, 3576 State: state, 3577 Providers: map[string]ResourceProviderFactory{ 3578 "aws": testProviderFuncFixed(p), 3579 }, 3580 Provisioners: map[string]ResourceProvisionerFactory{ 3581 "shell": testProvisionerFuncFixed(pr), 3582 }, 3583 }) 3584 3585 _, err := ctx.Plan() 3586 if err != nil { 3587 t.Fatalf("err: %s", err) 3588 } 3589 3590 state, err = ctx.Apply() 3591 if err != nil { 3592 t.Fatalf("err: %s", err) 3593 } 3594 3595 checkStateString(t, state, `<no state>`) 3596 } 3597 } 3598 3599 // Provisioner should NOT run on a diff, only create 3600 func TestContext2Apply_Provisioner_Diff(t *testing.T) { 3601 m := testModule(t, "apply-provisioner-diff") 3602 p := testProvider("aws") 3603 pr := testProvisioner() 3604 p.ApplyFn = testApplyFn 3605 p.DiffFn = testDiffFn 3606 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3607 return nil 3608 } 3609 ctx := testContext2(t, &ContextOpts{ 3610 Module: m, 3611 Providers: map[string]ResourceProviderFactory{ 3612 "aws": testProviderFuncFixed(p), 3613 }, 3614 Provisioners: map[string]ResourceProvisionerFactory{ 3615 "shell": testProvisionerFuncFixed(pr), 3616 }, 3617 }) 3618 3619 if _, err := ctx.Plan(); err != nil { 3620 t.Fatalf("err: %s", err) 3621 } 3622 3623 state, err := ctx.Apply() 3624 if err != nil { 3625 t.Fatalf("err: %s", err) 3626 } 3627 3628 actual := strings.TrimSpace(state.String()) 3629 expected := strings.TrimSpace(testTerraformApplyProvisionerDiffStr) 3630 if actual != expected { 3631 t.Fatalf("bad: \n%s", actual) 3632 } 3633 3634 // Verify apply was invoked 3635 if !pr.ApplyCalled { 3636 t.Fatalf("provisioner not invoked") 3637 } 3638 pr.ApplyCalled = false 3639 3640 // Change the state to force a diff 3641 mod := state.RootModule() 3642 mod.Resources["aws_instance.bar"].Primary.Attributes["foo"] = "baz" 3643 3644 // Re-create context with state 3645 ctx = testContext2(t, &ContextOpts{ 3646 Module: m, 3647 Providers: map[string]ResourceProviderFactory{ 3648 "aws": testProviderFuncFixed(p), 3649 }, 3650 Provisioners: map[string]ResourceProvisionerFactory{ 3651 "shell": testProvisionerFuncFixed(pr), 3652 }, 3653 State: state, 3654 }) 3655 3656 if _, err := ctx.Plan(); err != nil { 3657 t.Fatalf("err: %s", err) 3658 } 3659 3660 state2, err := ctx.Apply() 3661 if err != nil { 3662 t.Fatalf("err: %s", err) 3663 } 3664 3665 actual = strings.TrimSpace(state2.String()) 3666 if actual != expected { 3667 t.Fatalf("bad: \n%s", actual) 3668 } 3669 3670 // Verify apply was NOT invoked 3671 if pr.ApplyCalled { 3672 t.Fatalf("provisioner invoked") 3673 } 3674 } 3675 3676 func TestContext2Apply_outputDiffVars(t *testing.T) { 3677 m := testModule(t, "apply-good") 3678 p := testProvider("aws") 3679 s := &State{ 3680 Modules: []*ModuleState{ 3681 &ModuleState{ 3682 Path: rootModulePath, 3683 Resources: map[string]*ResourceState{ 3684 "aws_instance.baz": &ResourceState{ 3685 Type: "aws_instance", 3686 Primary: &InstanceState{ 3687 ID: "bar", 3688 }, 3689 }, 3690 }, 3691 }, 3692 }, 3693 } 3694 ctx := testContext2(t, &ContextOpts{ 3695 Module: m, 3696 Providers: map[string]ResourceProviderFactory{ 3697 "aws": testProviderFuncFixed(p), 3698 }, 3699 State: s, 3700 }) 3701 3702 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3703 for k, ad := range d.Attributes { 3704 if ad.NewComputed { 3705 return nil, fmt.Errorf("%s: computed", k) 3706 } 3707 } 3708 3709 result := s.MergeDiff(d) 3710 result.ID = "foo" 3711 return result, nil 3712 } 3713 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 3714 return &InstanceDiff{ 3715 Attributes: map[string]*ResourceAttrDiff{ 3716 "foo": &ResourceAttrDiff{ 3717 NewComputed: true, 3718 Type: DiffAttrOutput, 3719 }, 3720 "bar": &ResourceAttrDiff{ 3721 New: "baz", 3722 }, 3723 }, 3724 }, nil 3725 } 3726 3727 if _, err := ctx.Plan(); err != nil { 3728 t.Fatalf("err: %s", err) 3729 } 3730 if _, err := ctx.Apply(); err != nil { 3731 t.Fatalf("err: %s", err) 3732 } 3733 } 3734 3735 func TestContext2Apply_Provisioner_ConnInfo(t *testing.T) { 3736 m := testModule(t, "apply-provisioner-conninfo") 3737 p := testProvider("aws") 3738 pr := testProvisioner() 3739 3740 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 3741 if s.Ephemeral.ConnInfo == nil { 3742 t.Fatalf("ConnInfo not initialized") 3743 } 3744 3745 result, _ := testApplyFn(info, s, d) 3746 result.Ephemeral.ConnInfo = map[string]string{ 3747 "type": "ssh", 3748 "host": "127.0.0.1", 3749 "port": "22", 3750 } 3751 return result, nil 3752 } 3753 p.DiffFn = testDiffFn 3754 3755 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 3756 conn := rs.Ephemeral.ConnInfo 3757 if conn["type"] != "telnet" { 3758 t.Fatalf("Bad: %#v", conn) 3759 } 3760 if conn["host"] != "127.0.0.1" { 3761 t.Fatalf("Bad: %#v", conn) 3762 } 3763 if conn["port"] != "2222" { 3764 t.Fatalf("Bad: %#v", conn) 3765 } 3766 if conn["user"] != "superuser" { 3767 t.Fatalf("Bad: %#v", conn) 3768 } 3769 if conn["pass"] != "test" { 3770 t.Fatalf("Bad: %#v", conn) 3771 } 3772 3773 return nil 3774 } 3775 3776 ctx := testContext2(t, &ContextOpts{ 3777 Module: m, 3778 Providers: map[string]ResourceProviderFactory{ 3779 "aws": testProviderFuncFixed(p), 3780 }, 3781 Provisioners: map[string]ResourceProvisionerFactory{ 3782 "shell": testProvisionerFuncFixed(pr), 3783 }, 3784 Variables: map[string]interface{}{ 3785 "value": "1", 3786 "pass": "test", 3787 }, 3788 }) 3789 3790 if _, err := ctx.Plan(); err != nil { 3791 t.Fatalf("err: %s", err) 3792 } 3793 3794 state, err := ctx.Apply() 3795 if err != nil { 3796 t.Fatalf("err: %s", err) 3797 } 3798 3799 actual := strings.TrimSpace(state.String()) 3800 expected := strings.TrimSpace(testTerraformApplyProvisionerStr) 3801 if actual != expected { 3802 t.Fatalf("bad: \n%s", actual) 3803 } 3804 3805 // Verify apply was invoked 3806 if !pr.ApplyCalled { 3807 t.Fatalf("provisioner not invoked") 3808 } 3809 } 3810 3811 func TestContext2Apply_destroyX(t *testing.T) { 3812 m := testModule(t, "apply-destroy") 3813 h := new(HookRecordApplyOrder) 3814 p := testProvider("aws") 3815 p.ApplyFn = testApplyFn 3816 p.DiffFn = testDiffFn 3817 ctx := testContext2(t, &ContextOpts{ 3818 Module: m, 3819 Hooks: []Hook{h}, 3820 Providers: map[string]ResourceProviderFactory{ 3821 "aws": testProviderFuncFixed(p), 3822 }, 3823 }) 3824 3825 // First plan and apply a create operation 3826 if _, err := ctx.Plan(); err != nil { 3827 t.Fatalf("err: %s", err) 3828 } 3829 3830 state, err := ctx.Apply() 3831 if err != nil { 3832 t.Fatalf("err: %s", err) 3833 } 3834 3835 // Next, plan and apply a destroy operation 3836 h.Active = true 3837 ctx = testContext2(t, &ContextOpts{ 3838 Destroy: true, 3839 State: state, 3840 Module: m, 3841 Hooks: []Hook{h}, 3842 Providers: map[string]ResourceProviderFactory{ 3843 "aws": testProviderFuncFixed(p), 3844 }, 3845 }) 3846 3847 if _, err := ctx.Plan(); err != nil { 3848 t.Fatalf("err: %s", err) 3849 } 3850 3851 state, err = ctx.Apply() 3852 if err != nil { 3853 t.Fatalf("err: %s", err) 3854 } 3855 3856 // Test that things were destroyed 3857 actual := strings.TrimSpace(state.String()) 3858 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 3859 if actual != expected { 3860 t.Fatalf("bad: \n%s", actual) 3861 } 3862 3863 // Test that things were destroyed _in the right order_ 3864 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 3865 actual2 := h.IDs 3866 if !reflect.DeepEqual(actual2, expected2) { 3867 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 3868 } 3869 } 3870 3871 func TestContext2Apply_destroyOrder(t *testing.T) { 3872 m := testModule(t, "apply-destroy") 3873 h := new(HookRecordApplyOrder) 3874 p := testProvider("aws") 3875 p.ApplyFn = testApplyFn 3876 p.DiffFn = testDiffFn 3877 ctx := testContext2(t, &ContextOpts{ 3878 Module: m, 3879 Hooks: []Hook{h}, 3880 Providers: map[string]ResourceProviderFactory{ 3881 "aws": testProviderFuncFixed(p), 3882 }, 3883 }) 3884 3885 // First plan and apply a create operation 3886 if _, err := ctx.Plan(); err != nil { 3887 t.Fatalf("err: %s", err) 3888 } 3889 3890 state, err := ctx.Apply() 3891 if err != nil { 3892 t.Fatalf("err: %s", err) 3893 } 3894 3895 t.Logf("State 1: %s", state) 3896 3897 // Next, plan and apply config-less to force a destroy with "apply" 3898 h.Active = true 3899 ctx = testContext2(t, &ContextOpts{ 3900 State: state, 3901 Module: module.NewEmptyTree(), 3902 Hooks: []Hook{h}, 3903 Providers: map[string]ResourceProviderFactory{ 3904 "aws": testProviderFuncFixed(p), 3905 }, 3906 }) 3907 3908 if _, err := ctx.Plan(); err != nil { 3909 t.Fatalf("err: %s", err) 3910 } 3911 3912 state, err = ctx.Apply() 3913 if err != nil { 3914 t.Fatalf("err: %s", err) 3915 } 3916 3917 // Test that things were destroyed 3918 actual := strings.TrimSpace(state.String()) 3919 expected := strings.TrimSpace(testTerraformApplyDestroyStr) 3920 if actual != expected { 3921 t.Fatalf("bad: \n%s", actual) 3922 } 3923 3924 // Test that things were destroyed _in the right order_ 3925 expected2 := []string{"aws_instance.bar", "aws_instance.foo"} 3926 actual2 := h.IDs 3927 if !reflect.DeepEqual(actual2, expected2) { 3928 t.Fatalf("expected: %#v\n\ngot:%#v", expected2, actual2) 3929 } 3930 } 3931 3932 // https://github.com/hashicorp/terraform/issues/2767 3933 func TestContext2Apply_destroyModulePrefix(t *testing.T) { 3934 m := testModule(t, "apply-destroy-module-resource-prefix") 3935 h := new(MockHook) 3936 p := testProvider("aws") 3937 p.ApplyFn = testApplyFn 3938 p.DiffFn = testDiffFn 3939 ctx := testContext2(t, &ContextOpts{ 3940 Module: m, 3941 Hooks: []Hook{h}, 3942 Providers: map[string]ResourceProviderFactory{ 3943 "aws": testProviderFuncFixed(p), 3944 }, 3945 }) 3946 3947 // First plan and apply a create operation 3948 if _, err := ctx.Plan(); err != nil { 3949 t.Fatalf("err: %s", err) 3950 } 3951 3952 state, err := ctx.Apply() 3953 if err != nil { 3954 t.Fatalf("err: %s", err) 3955 } 3956 3957 // Verify that we got the apply info correct 3958 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 3959 t.Fatalf("bad: %s", v) 3960 } 3961 3962 // Next, plan and apply a destroy operation and reset the hook 3963 h = new(MockHook) 3964 ctx = testContext2(t, &ContextOpts{ 3965 Destroy: true, 3966 State: state, 3967 Module: m, 3968 Hooks: []Hook{h}, 3969 Providers: map[string]ResourceProviderFactory{ 3970 "aws": testProviderFuncFixed(p), 3971 }, 3972 }) 3973 3974 if _, err := ctx.Plan(); err != nil { 3975 t.Fatalf("err: %s", err) 3976 } 3977 3978 state, err = ctx.Apply() 3979 if err != nil { 3980 t.Fatalf("err: %s", err) 3981 } 3982 3983 // Test that things were destroyed 3984 if v := h.PreApplyInfo.HumanId(); v != "module.child.aws_instance.foo" { 3985 t.Fatalf("bad: %s", v) 3986 } 3987 } 3988 3989 func TestContext2Apply_destroyNestedModule(t *testing.T) { 3990 m := testModule(t, "apply-destroy-nested-module") 3991 p := testProvider("aws") 3992 p.ApplyFn = testApplyFn 3993 p.DiffFn = testDiffFn 3994 3995 s := &State{ 3996 Modules: []*ModuleState{ 3997 &ModuleState{ 3998 Path: []string{"root", "child", "subchild"}, 3999 Resources: map[string]*ResourceState{ 4000 "aws_instance.bar": &ResourceState{ 4001 Type: "aws_instance", 4002 Primary: &InstanceState{ 4003 ID: "bar", 4004 }, 4005 }, 4006 }, 4007 }, 4008 }, 4009 } 4010 4011 ctx := testContext2(t, &ContextOpts{ 4012 Module: m, 4013 Providers: map[string]ResourceProviderFactory{ 4014 "aws": testProviderFuncFixed(p), 4015 }, 4016 State: s, 4017 }) 4018 4019 // First plan and apply a create operation 4020 if _, err := ctx.Plan(); err != nil { 4021 t.Fatalf("err: %s", err) 4022 } 4023 4024 state, err := ctx.Apply() 4025 if err != nil { 4026 t.Fatalf("err: %s", err) 4027 } 4028 4029 // Test that things were destroyed 4030 actual := strings.TrimSpace(state.String()) 4031 expected := strings.TrimSpace(testTerraformApplyDestroyNestedModuleStr) 4032 if actual != expected { 4033 t.Fatalf("bad: \n%s", actual) 4034 } 4035 } 4036 4037 func TestContext2Apply_destroyDeeplyNestedModule(t *testing.T) { 4038 m := testModule(t, "apply-destroy-deeply-nested-module") 4039 p := testProvider("aws") 4040 p.ApplyFn = testApplyFn 4041 p.DiffFn = testDiffFn 4042 4043 s := &State{ 4044 Modules: []*ModuleState{ 4045 &ModuleState{ 4046 Path: []string{"root", "child", "subchild", "subsubchild"}, 4047 Resources: map[string]*ResourceState{ 4048 "aws_instance.bar": &ResourceState{ 4049 Type: "aws_instance", 4050 Primary: &InstanceState{ 4051 ID: "bar", 4052 }, 4053 }, 4054 }, 4055 }, 4056 }, 4057 } 4058 4059 ctx := testContext2(t, &ContextOpts{ 4060 Module: m, 4061 Providers: map[string]ResourceProviderFactory{ 4062 "aws": testProviderFuncFixed(p), 4063 }, 4064 State: s, 4065 }) 4066 4067 // First plan and apply a create operation 4068 if _, err := ctx.Plan(); err != nil { 4069 t.Fatalf("err: %s", err) 4070 } 4071 4072 state, err := ctx.Apply() 4073 if err != nil { 4074 t.Fatalf("err: %s", err) 4075 } 4076 4077 // Test that things were destroyed 4078 actual := strings.TrimSpace(state.String()) 4079 expected := strings.TrimSpace(` 4080 module.child.subchild.subsubchild: 4081 <no state> 4082 `) 4083 if actual != expected { 4084 t.Fatalf("bad: \n%s", actual) 4085 } 4086 } 4087 4088 // https://github.com/hashicorp/terraform/issues/5440 4089 func TestContext2Apply_destroyModuleWithAttrsReferencingResource(t *testing.T) { 4090 m := testModule(t, "apply-destroy-module-with-attrs") 4091 p := testProvider("aws") 4092 p.ApplyFn = testApplyFn 4093 p.DiffFn = testDiffFn 4094 4095 var state *State 4096 var err error 4097 { 4098 ctx := testContext2(t, &ContextOpts{ 4099 Module: m, 4100 Providers: map[string]ResourceProviderFactory{ 4101 "aws": testProviderFuncFixed(p), 4102 }, 4103 }) 4104 4105 // First plan and apply a create operation 4106 if p, err := ctx.Plan(); err != nil { 4107 t.Fatalf("plan err: %s", err) 4108 } else { 4109 t.Logf("Step 1 plan: %s", p) 4110 } 4111 4112 state, err = ctx.Apply() 4113 if err != nil { 4114 t.Fatalf("apply err: %s", err) 4115 } 4116 4117 t.Logf("Step 1 state: %s", state) 4118 } 4119 4120 h := new(HookRecordApplyOrder) 4121 h.Active = true 4122 4123 { 4124 ctx := testContext2(t, &ContextOpts{ 4125 Destroy: true, 4126 Module: m, 4127 State: state, 4128 Hooks: []Hook{h}, 4129 Providers: map[string]ResourceProviderFactory{ 4130 "aws": testProviderFuncFixed(p), 4131 }, 4132 Variables: map[string]interface{}{ 4133 "key_name": "foobarkey", 4134 }, 4135 }) 4136 4137 // First plan and apply a create operation 4138 plan, err := ctx.Plan() 4139 if err != nil { 4140 t.Fatalf("destroy plan err: %s", err) 4141 } 4142 4143 t.Logf("Step 2 plan: %s", plan) 4144 4145 var buf bytes.Buffer 4146 if err := WritePlan(plan, &buf); err != nil { 4147 t.Fatalf("plan write err: %s", err) 4148 } 4149 4150 planFromFile, err := ReadPlan(&buf) 4151 if err != nil { 4152 t.Fatalf("plan read err: %s", err) 4153 } 4154 4155 ctx, err = planFromFile.Context(&ContextOpts{ 4156 Providers: map[string]ResourceProviderFactory{ 4157 "aws": testProviderFuncFixed(p), 4158 }, 4159 }) 4160 if err != nil { 4161 t.Fatalf("err: %s", err) 4162 } 4163 4164 state, err = ctx.Apply() 4165 if err != nil { 4166 t.Fatalf("destroy apply err: %s", err) 4167 } 4168 4169 t.Logf("Step 2 state: %s", state) 4170 } 4171 4172 //Test that things were destroyed 4173 actual := strings.TrimSpace(state.String()) 4174 expected := strings.TrimSpace(` 4175 <no state> 4176 module.child: 4177 <no state> 4178 `) 4179 if actual != expected { 4180 t.Fatalf("expected:\n\n%s\n\nactual:\n\n%s", expected, actual) 4181 } 4182 } 4183 4184 func TestContext2Apply_destroyWithModuleVariableAndCount(t *testing.T) { 4185 m := testModule(t, "apply-destroy-mod-var-and-count") 4186 p := testProvider("aws") 4187 p.ApplyFn = testApplyFn 4188 p.DiffFn = testDiffFn 4189 4190 var state *State 4191 var err error 4192 { 4193 ctx := testContext2(t, &ContextOpts{ 4194 Module: m, 4195 Providers: map[string]ResourceProviderFactory{ 4196 "aws": testProviderFuncFixed(p), 4197 }, 4198 }) 4199 4200 // First plan and apply a create operation 4201 if _, err := ctx.Plan(); err != nil { 4202 t.Fatalf("plan err: %s", err) 4203 } 4204 4205 state, err = ctx.Apply() 4206 if err != nil { 4207 t.Fatalf("apply err: %s", err) 4208 } 4209 } 4210 4211 h := new(HookRecordApplyOrder) 4212 h.Active = true 4213 4214 { 4215 ctx := testContext2(t, &ContextOpts{ 4216 Destroy: true, 4217 Module: m, 4218 State: state, 4219 Hooks: []Hook{h}, 4220 Providers: map[string]ResourceProviderFactory{ 4221 "aws": testProviderFuncFixed(p), 4222 }, 4223 }) 4224 4225 // First plan and apply a create operation 4226 plan, err := ctx.Plan() 4227 if err != nil { 4228 t.Fatalf("destroy plan err: %s", err) 4229 } 4230 4231 var buf bytes.Buffer 4232 if err := WritePlan(plan, &buf); err != nil { 4233 t.Fatalf("plan write err: %s", err) 4234 } 4235 4236 planFromFile, err := ReadPlan(&buf) 4237 if err != nil { 4238 t.Fatalf("plan read err: %s", err) 4239 } 4240 4241 ctx, err = planFromFile.Context(&ContextOpts{ 4242 Providers: map[string]ResourceProviderFactory{ 4243 "aws": testProviderFuncFixed(p), 4244 }, 4245 }) 4246 if err != nil { 4247 t.Fatalf("err: %s", err) 4248 } 4249 4250 state, err = ctx.Apply() 4251 if err != nil { 4252 t.Fatalf("destroy apply err: %s", err) 4253 } 4254 } 4255 4256 //Test that things were destroyed 4257 actual := strings.TrimSpace(state.String()) 4258 expected := strings.TrimSpace(` 4259 <no state> 4260 module.child: 4261 <no state> 4262 `) 4263 if actual != expected { 4264 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 4265 } 4266 } 4267 4268 func TestContext2Apply_destroyTargetWithModuleVariableAndCount(t *testing.T) { 4269 m := testModule(t, "apply-destroy-mod-var-and-count") 4270 p := testProvider("aws") 4271 p.ApplyFn = testApplyFn 4272 p.DiffFn = testDiffFn 4273 4274 var state *State 4275 var err error 4276 { 4277 ctx := testContext2(t, &ContextOpts{ 4278 Module: m, 4279 Providers: map[string]ResourceProviderFactory{ 4280 "aws": testProviderFuncFixed(p), 4281 }, 4282 }) 4283 4284 // First plan and apply a create operation 4285 if _, err := ctx.Plan(); err != nil { 4286 t.Fatalf("plan err: %s", err) 4287 } 4288 4289 state, err = ctx.Apply() 4290 if err != nil { 4291 t.Fatalf("apply err: %s", err) 4292 } 4293 } 4294 4295 { 4296 ctx := testContext2(t, &ContextOpts{ 4297 Destroy: true, 4298 Module: m, 4299 State: state, 4300 Providers: map[string]ResourceProviderFactory{ 4301 "aws": testProviderFuncFixed(p), 4302 }, 4303 Targets: []string{"module.child"}, 4304 }) 4305 4306 _, err := ctx.Plan() 4307 if err != nil { 4308 t.Fatalf("plan err: %s", err) 4309 } 4310 4311 // Destroy, targeting the module explicitly 4312 state, err = ctx.Apply() 4313 if err != nil { 4314 t.Fatalf("destroy apply err: %s", err) 4315 } 4316 } 4317 4318 //Test that things were destroyed 4319 actual := strings.TrimSpace(state.String()) 4320 expected := strings.TrimSpace(` 4321 <no state> 4322 module.child: 4323 <no state> 4324 `) 4325 if actual != expected { 4326 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 4327 } 4328 } 4329 4330 func TestContext2Apply_destroyWithModuleVariableAndCountNested(t *testing.T) { 4331 m := testModule(t, "apply-destroy-mod-var-and-count-nested") 4332 p := testProvider("aws") 4333 p.ApplyFn = testApplyFn 4334 p.DiffFn = testDiffFn 4335 4336 var state *State 4337 var err error 4338 { 4339 ctx := testContext2(t, &ContextOpts{ 4340 Module: m, 4341 Providers: map[string]ResourceProviderFactory{ 4342 "aws": testProviderFuncFixed(p), 4343 }, 4344 }) 4345 4346 // First plan and apply a create operation 4347 if _, err := ctx.Plan(); err != nil { 4348 t.Fatalf("plan err: %s", err) 4349 } 4350 4351 state, err = ctx.Apply() 4352 if err != nil { 4353 t.Fatalf("apply err: %s", err) 4354 } 4355 } 4356 4357 h := new(HookRecordApplyOrder) 4358 h.Active = true 4359 4360 { 4361 ctx := testContext2(t, &ContextOpts{ 4362 Destroy: true, 4363 Module: m, 4364 State: state, 4365 Hooks: []Hook{h}, 4366 Providers: map[string]ResourceProviderFactory{ 4367 "aws": testProviderFuncFixed(p), 4368 }, 4369 }) 4370 4371 // First plan and apply a create operation 4372 plan, err := ctx.Plan() 4373 if err != nil { 4374 t.Fatalf("destroy plan err: %s", err) 4375 } 4376 4377 var buf bytes.Buffer 4378 if err := WritePlan(plan, &buf); err != nil { 4379 t.Fatalf("plan write err: %s", err) 4380 } 4381 4382 planFromFile, err := ReadPlan(&buf) 4383 if err != nil { 4384 t.Fatalf("plan read err: %s", err) 4385 } 4386 4387 ctx, err = planFromFile.Context(&ContextOpts{ 4388 Providers: map[string]ResourceProviderFactory{ 4389 "aws": testProviderFuncFixed(p), 4390 }, 4391 }) 4392 if err != nil { 4393 t.Fatalf("err: %s", err) 4394 } 4395 4396 state, err = ctx.Apply() 4397 if err != nil { 4398 t.Fatalf("destroy apply err: %s", err) 4399 } 4400 } 4401 4402 //Test that things were destroyed 4403 actual := strings.TrimSpace(state.String()) 4404 expected := strings.TrimSpace(` 4405 <no state> 4406 module.child: 4407 <no state> 4408 module.child.child2: 4409 <no state> 4410 `) 4411 if actual != expected { 4412 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 4413 } 4414 } 4415 4416 func TestContext2Apply_destroyOutputs(t *testing.T) { 4417 m := testModule(t, "apply-destroy-outputs") 4418 h := new(HookRecordApplyOrder) 4419 p := testProvider("aws") 4420 p.ApplyFn = testApplyFn 4421 p.DiffFn = testDiffFn 4422 ctx := testContext2(t, &ContextOpts{ 4423 Module: m, 4424 Hooks: []Hook{h}, 4425 Providers: map[string]ResourceProviderFactory{ 4426 "aws": testProviderFuncFixed(p), 4427 }, 4428 }) 4429 4430 // First plan and apply a create operation 4431 if _, err := ctx.Plan(); err != nil { 4432 t.Fatalf("err: %s", err) 4433 } 4434 4435 state, err := ctx.Apply() 4436 4437 if err != nil { 4438 t.Fatalf("err: %s", err) 4439 } 4440 4441 // Next, plan and apply a destroy operation 4442 h.Active = true 4443 ctx = testContext2(t, &ContextOpts{ 4444 Destroy: true, 4445 State: state, 4446 Module: m, 4447 Hooks: []Hook{h}, 4448 Providers: map[string]ResourceProviderFactory{ 4449 "aws": testProviderFuncFixed(p), 4450 }, 4451 }) 4452 4453 if _, err := ctx.Plan(); err != nil { 4454 t.Fatalf("err: %s", err) 4455 } 4456 4457 state, err = ctx.Apply() 4458 if err != nil { 4459 t.Fatalf("err: %s", err) 4460 } 4461 4462 mod := state.RootModule() 4463 if len(mod.Resources) > 0 { 4464 t.Fatalf("bad: %#v", mod) 4465 } 4466 } 4467 4468 func TestContext2Apply_destroyOrphan(t *testing.T) { 4469 m := testModule(t, "apply-error") 4470 p := testProvider("aws") 4471 s := &State{ 4472 Modules: []*ModuleState{ 4473 &ModuleState{ 4474 Path: rootModulePath, 4475 Resources: map[string]*ResourceState{ 4476 "aws_instance.baz": &ResourceState{ 4477 Type: "aws_instance", 4478 Primary: &InstanceState{ 4479 ID: "bar", 4480 }, 4481 }, 4482 }, 4483 }, 4484 }, 4485 } 4486 ctx := testContext2(t, &ContextOpts{ 4487 Module: m, 4488 Providers: map[string]ResourceProviderFactory{ 4489 "aws": testProviderFuncFixed(p), 4490 }, 4491 State: s, 4492 }) 4493 4494 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4495 if d.Destroy { 4496 return nil, nil 4497 } 4498 4499 result := s.MergeDiff(d) 4500 result.ID = "foo" 4501 return result, nil 4502 } 4503 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4504 return &InstanceDiff{ 4505 Attributes: map[string]*ResourceAttrDiff{ 4506 "num": &ResourceAttrDiff{ 4507 New: "bar", 4508 }, 4509 }, 4510 }, nil 4511 } 4512 4513 if _, err := ctx.Plan(); err != nil { 4514 t.Fatalf("err: %s", err) 4515 } 4516 4517 state, err := ctx.Apply() 4518 if err != nil { 4519 t.Fatalf("err: %s", err) 4520 } 4521 4522 mod := state.RootModule() 4523 if _, ok := mod.Resources["aws_instance.baz"]; ok { 4524 t.Fatalf("bad: %#v", mod.Resources) 4525 } 4526 } 4527 4528 func TestContext2Apply_destroyTaintedProvisioner(t *testing.T) { 4529 m := testModule(t, "apply-destroy-provisioner") 4530 p := testProvider("aws") 4531 pr := testProvisioner() 4532 p.ApplyFn = testApplyFn 4533 p.DiffFn = testDiffFn 4534 4535 called := false 4536 pr.ApplyFn = func(rs *InstanceState, c *ResourceConfig) error { 4537 called = true 4538 return nil 4539 } 4540 4541 s := &State{ 4542 Modules: []*ModuleState{ 4543 &ModuleState{ 4544 Path: rootModulePath, 4545 Resources: map[string]*ResourceState{ 4546 "aws_instance.foo": &ResourceState{ 4547 Type: "aws_instance", 4548 Primary: &InstanceState{ 4549 ID: "bar", 4550 Attributes: map[string]string{ 4551 "id": "bar", 4552 }, 4553 Tainted: true, 4554 }, 4555 }, 4556 }, 4557 }, 4558 }, 4559 } 4560 4561 ctx := testContext2(t, &ContextOpts{ 4562 Module: m, 4563 Providers: map[string]ResourceProviderFactory{ 4564 "aws": testProviderFuncFixed(p), 4565 }, 4566 Provisioners: map[string]ResourceProvisionerFactory{ 4567 "shell": testProvisionerFuncFixed(pr), 4568 }, 4569 State: s, 4570 Destroy: true, 4571 }) 4572 4573 if _, err := ctx.Plan(); err != nil { 4574 t.Fatalf("err: %s", err) 4575 } 4576 4577 state, err := ctx.Apply() 4578 if err != nil { 4579 t.Fatalf("err: %s", err) 4580 } 4581 4582 if called { 4583 t.Fatal("provisioner should not be called") 4584 } 4585 4586 actual := strings.TrimSpace(state.String()) 4587 expected := strings.TrimSpace("<no state>") 4588 if actual != expected { 4589 t.Fatalf("bad: \n%s", actual) 4590 } 4591 } 4592 4593 func TestContext2Apply_error(t *testing.T) { 4594 errored := false 4595 4596 m := testModule(t, "apply-error") 4597 p := testProvider("aws") 4598 ctx := testContext2(t, &ContextOpts{ 4599 Module: m, 4600 Providers: map[string]ResourceProviderFactory{ 4601 "aws": testProviderFuncFixed(p), 4602 }, 4603 }) 4604 4605 p.ApplyFn = func(*InstanceInfo, *InstanceState, *InstanceDiff) (*InstanceState, error) { 4606 if errored { 4607 state := &InstanceState{ 4608 ID: "bar", 4609 } 4610 return state, fmt.Errorf("error") 4611 } 4612 errored = true 4613 4614 return &InstanceState{ 4615 ID: "foo", 4616 Attributes: map[string]string{ 4617 "num": "2", 4618 }, 4619 }, nil 4620 } 4621 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4622 return &InstanceDiff{ 4623 Attributes: map[string]*ResourceAttrDiff{ 4624 "num": &ResourceAttrDiff{ 4625 New: "bar", 4626 }, 4627 }, 4628 }, nil 4629 } 4630 4631 if _, err := ctx.Plan(); err != nil { 4632 t.Fatalf("err: %s", err) 4633 } 4634 4635 state, err := ctx.Apply() 4636 if err == nil { 4637 t.Fatal("should have error") 4638 } 4639 4640 actual := strings.TrimSpace(state.String()) 4641 expected := strings.TrimSpace(testTerraformApplyErrorStr) 4642 if actual != expected { 4643 t.Fatalf("bad: \n%s", actual) 4644 } 4645 } 4646 4647 func TestContext2Apply_errorPartial(t *testing.T) { 4648 errored := false 4649 4650 m := testModule(t, "apply-error") 4651 p := testProvider("aws") 4652 s := &State{ 4653 Modules: []*ModuleState{ 4654 &ModuleState{ 4655 Path: rootModulePath, 4656 Resources: map[string]*ResourceState{ 4657 "aws_instance.bar": &ResourceState{ 4658 Type: "aws_instance", 4659 Primary: &InstanceState{ 4660 ID: "bar", 4661 }, 4662 }, 4663 }, 4664 }, 4665 }, 4666 } 4667 ctx := testContext2(t, &ContextOpts{ 4668 Module: m, 4669 Providers: map[string]ResourceProviderFactory{ 4670 "aws": testProviderFuncFixed(p), 4671 }, 4672 State: s, 4673 }) 4674 4675 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4676 if errored { 4677 return s, fmt.Errorf("error") 4678 } 4679 errored = true 4680 4681 return &InstanceState{ 4682 ID: "foo", 4683 Attributes: map[string]string{ 4684 "num": "2", 4685 }, 4686 }, nil 4687 } 4688 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4689 return &InstanceDiff{ 4690 Attributes: map[string]*ResourceAttrDiff{ 4691 "num": &ResourceAttrDiff{ 4692 New: "bar", 4693 }, 4694 }, 4695 }, nil 4696 } 4697 4698 if _, err := ctx.Plan(); err != nil { 4699 t.Fatalf("err: %s", err) 4700 } 4701 4702 state, err := ctx.Apply() 4703 if err == nil { 4704 t.Fatal("should have error") 4705 } 4706 4707 mod := state.RootModule() 4708 if len(mod.Resources) != 2 { 4709 t.Fatalf("bad: %#v", mod.Resources) 4710 } 4711 4712 actual := strings.TrimSpace(state.String()) 4713 expected := strings.TrimSpace(testTerraformApplyErrorPartialStr) 4714 if actual != expected { 4715 t.Fatalf("bad: \n%s", actual) 4716 } 4717 } 4718 4719 func TestContext2Apply_hook(t *testing.T) { 4720 m := testModule(t, "apply-good") 4721 h := new(MockHook) 4722 p := testProvider("aws") 4723 p.ApplyFn = testApplyFn 4724 p.DiffFn = testDiffFn 4725 ctx := testContext2(t, &ContextOpts{ 4726 Module: m, 4727 Hooks: []Hook{h}, 4728 Providers: map[string]ResourceProviderFactory{ 4729 "aws": testProviderFuncFixed(p), 4730 }, 4731 }) 4732 4733 if _, err := ctx.Plan(); err != nil { 4734 t.Fatalf("err: %s", err) 4735 } 4736 4737 if _, err := ctx.Apply(); err != nil { 4738 t.Fatalf("err: %s", err) 4739 } 4740 4741 if !h.PreApplyCalled { 4742 t.Fatal("should be called") 4743 } 4744 if !h.PostApplyCalled { 4745 t.Fatal("should be called") 4746 } 4747 if !h.PostStateUpdateCalled { 4748 t.Fatalf("should call post state update") 4749 } 4750 } 4751 4752 func TestContext2Apply_hookOrphan(t *testing.T) { 4753 m := testModule(t, "apply-blank") 4754 h := new(MockHook) 4755 p := testProvider("aws") 4756 p.ApplyFn = testApplyFn 4757 p.DiffFn = testDiffFn 4758 4759 state := &State{ 4760 Modules: []*ModuleState{ 4761 &ModuleState{ 4762 Path: rootModulePath, 4763 Resources: map[string]*ResourceState{ 4764 "aws_instance.bar": &ResourceState{ 4765 Type: "aws_instance", 4766 Primary: &InstanceState{ 4767 ID: "bar", 4768 }, 4769 }, 4770 }, 4771 }, 4772 }, 4773 } 4774 4775 ctx := testContext2(t, &ContextOpts{ 4776 Module: m, 4777 State: state, 4778 Hooks: []Hook{h}, 4779 Providers: map[string]ResourceProviderFactory{ 4780 "aws": testProviderFuncFixed(p), 4781 }, 4782 }) 4783 4784 if _, err := ctx.Plan(); err != nil { 4785 t.Fatalf("err: %s", err) 4786 } 4787 4788 if _, err := ctx.Apply(); err != nil { 4789 t.Fatalf("err: %s", err) 4790 } 4791 4792 if !h.PreApplyCalled { 4793 t.Fatal("should be called") 4794 } 4795 if !h.PostApplyCalled { 4796 t.Fatal("should be called") 4797 } 4798 if !h.PostStateUpdateCalled { 4799 t.Fatalf("should call post state update") 4800 } 4801 } 4802 4803 func TestContext2Apply_idAttr(t *testing.T) { 4804 m := testModule(t, "apply-idattr") 4805 p := testProvider("aws") 4806 ctx := testContext2(t, &ContextOpts{ 4807 Module: m, 4808 Providers: map[string]ResourceProviderFactory{ 4809 "aws": testProviderFuncFixed(p), 4810 }, 4811 }) 4812 4813 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 4814 result := s.MergeDiff(d) 4815 result.ID = "foo" 4816 result.Attributes = map[string]string{ 4817 "id": "bar", 4818 } 4819 4820 return result, nil 4821 } 4822 p.DiffFn = func(*InstanceInfo, *InstanceState, *ResourceConfig) (*InstanceDiff, error) { 4823 return &InstanceDiff{ 4824 Attributes: map[string]*ResourceAttrDiff{ 4825 "num": &ResourceAttrDiff{ 4826 New: "bar", 4827 }, 4828 }, 4829 }, nil 4830 } 4831 4832 if _, err := ctx.Plan(); err != nil { 4833 t.Fatalf("err: %s", err) 4834 } 4835 4836 state, err := ctx.Apply() 4837 if err != nil { 4838 t.Fatalf("err: %s", err) 4839 } 4840 4841 mod := state.RootModule() 4842 rs, ok := mod.Resources["aws_instance.foo"] 4843 if !ok { 4844 t.Fatal("not in state") 4845 } 4846 if rs.Primary.ID != "foo" { 4847 t.Fatalf("bad: %#v", rs.Primary.ID) 4848 } 4849 if rs.Primary.Attributes["id"] != "foo" { 4850 t.Fatalf("bad: %#v", rs.Primary.Attributes) 4851 } 4852 } 4853 4854 func TestContext2Apply_outputBasic(t *testing.T) { 4855 m := testModule(t, "apply-output") 4856 p := testProvider("aws") 4857 p.ApplyFn = testApplyFn 4858 p.DiffFn = testDiffFn 4859 ctx := testContext2(t, &ContextOpts{ 4860 Module: m, 4861 Providers: map[string]ResourceProviderFactory{ 4862 "aws": testProviderFuncFixed(p), 4863 }, 4864 }) 4865 4866 if _, err := ctx.Plan(); err != nil { 4867 t.Fatalf("err: %s", err) 4868 } 4869 4870 state, err := ctx.Apply() 4871 if err != nil { 4872 t.Fatalf("err: %s", err) 4873 } 4874 4875 actual := strings.TrimSpace(state.String()) 4876 expected := strings.TrimSpace(testTerraformApplyOutputStr) 4877 if actual != expected { 4878 t.Fatalf("bad: \n%s", actual) 4879 } 4880 } 4881 4882 func TestContext2Apply_outputInvalid(t *testing.T) { 4883 m := testModule(t, "apply-output-invalid") 4884 p := testProvider("aws") 4885 p.ApplyFn = testApplyFn 4886 p.DiffFn = testDiffFn 4887 ctx := testContext2(t, &ContextOpts{ 4888 Module: m, 4889 Providers: map[string]ResourceProviderFactory{ 4890 "aws": testProviderFuncFixed(p), 4891 }, 4892 }) 4893 4894 _, err := ctx.Plan() 4895 if err == nil { 4896 t.Fatalf("err: %s", err) 4897 } 4898 if !strings.Contains(err.Error(), "is not a valid type") { 4899 t.Fatalf("err: %s", err) 4900 } 4901 } 4902 4903 func TestContext2Apply_outputAdd(t *testing.T) { 4904 m1 := testModule(t, "apply-output-add-before") 4905 p1 := testProvider("aws") 4906 p1.ApplyFn = testApplyFn 4907 p1.DiffFn = testDiffFn 4908 ctx1 := testContext2(t, &ContextOpts{ 4909 Module: m1, 4910 Providers: map[string]ResourceProviderFactory{ 4911 "aws": testProviderFuncFixed(p1), 4912 }, 4913 }) 4914 4915 if _, err := ctx1.Plan(); err != nil { 4916 t.Fatalf("err: %s", err) 4917 } 4918 4919 state1, err := ctx1.Apply() 4920 if err != nil { 4921 t.Fatalf("err: %s", err) 4922 } 4923 4924 m2 := testModule(t, "apply-output-add-after") 4925 p2 := testProvider("aws") 4926 p2.ApplyFn = testApplyFn 4927 p2.DiffFn = testDiffFn 4928 ctx2 := testContext2(t, &ContextOpts{ 4929 Module: m2, 4930 Providers: map[string]ResourceProviderFactory{ 4931 "aws": testProviderFuncFixed(p2), 4932 }, 4933 State: state1, 4934 }) 4935 4936 if _, err := ctx2.Plan(); err != nil { 4937 t.Fatalf("err: %s", err) 4938 } 4939 4940 state2, err := ctx2.Apply() 4941 if err != nil { 4942 t.Fatalf("err: %s", err) 4943 } 4944 4945 actual := strings.TrimSpace(state2.String()) 4946 expected := strings.TrimSpace(testTerraformApplyOutputAddStr) 4947 if actual != expected { 4948 t.Fatalf("bad: \n%s", actual) 4949 } 4950 } 4951 4952 func TestContext2Apply_outputList(t *testing.T) { 4953 m := testModule(t, "apply-output-list") 4954 p := testProvider("aws") 4955 p.ApplyFn = testApplyFn 4956 p.DiffFn = testDiffFn 4957 ctx := testContext2(t, &ContextOpts{ 4958 Module: m, 4959 Providers: map[string]ResourceProviderFactory{ 4960 "aws": testProviderFuncFixed(p), 4961 }, 4962 }) 4963 4964 if _, err := ctx.Plan(); err != nil { 4965 t.Fatalf("err: %s", err) 4966 } 4967 4968 state, err := ctx.Apply() 4969 if err != nil { 4970 t.Fatalf("err: %s", err) 4971 } 4972 4973 actual := strings.TrimSpace(state.String()) 4974 expected := strings.TrimSpace(testTerraformApplyOutputListStr) 4975 if actual != expected { 4976 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 4977 } 4978 } 4979 4980 func TestContext2Apply_outputMulti(t *testing.T) { 4981 m := testModule(t, "apply-output-multi") 4982 p := testProvider("aws") 4983 p.ApplyFn = testApplyFn 4984 p.DiffFn = testDiffFn 4985 ctx := testContext2(t, &ContextOpts{ 4986 Module: m, 4987 Providers: map[string]ResourceProviderFactory{ 4988 "aws": testProviderFuncFixed(p), 4989 }, 4990 }) 4991 4992 if _, err := ctx.Plan(); err != nil { 4993 t.Fatalf("err: %s", err) 4994 } 4995 4996 state, err := ctx.Apply() 4997 if err != nil { 4998 t.Fatalf("err: %s", err) 4999 } 5000 5001 actual := strings.TrimSpace(state.String()) 5002 expected := strings.TrimSpace(testTerraformApplyOutputMultiStr) 5003 if actual != expected { 5004 t.Fatalf("bad: \n%s", actual) 5005 } 5006 } 5007 5008 func TestContext2Apply_outputMultiIndex(t *testing.T) { 5009 m := testModule(t, "apply-output-multi-index") 5010 p := testProvider("aws") 5011 p.ApplyFn = testApplyFn 5012 p.DiffFn = testDiffFn 5013 ctx := testContext2(t, &ContextOpts{ 5014 Module: m, 5015 Providers: map[string]ResourceProviderFactory{ 5016 "aws": testProviderFuncFixed(p), 5017 }, 5018 }) 5019 5020 if _, err := ctx.Plan(); err != nil { 5021 t.Fatalf("err: %s", err) 5022 } 5023 5024 state, err := ctx.Apply() 5025 if err != nil { 5026 t.Fatalf("err: %s", err) 5027 } 5028 5029 actual := strings.TrimSpace(state.String()) 5030 expected := strings.TrimSpace(testTerraformApplyOutputMultiIndexStr) 5031 if actual != expected { 5032 t.Fatalf("bad: \n%s", actual) 5033 } 5034 } 5035 5036 func TestContext2Apply_taintX(t *testing.T) { 5037 m := testModule(t, "apply-taint") 5038 p := testProvider("aws") 5039 5040 // destroyCount tests against regression of 5041 // https://github.com/hashicorp/terraform/issues/1056 5042 var destroyCount = int32(0) 5043 var once sync.Once 5044 simulateProviderDelay := func() { 5045 time.Sleep(10 * time.Millisecond) 5046 } 5047 5048 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5049 once.Do(simulateProviderDelay) 5050 if d.Destroy { 5051 atomic.AddInt32(&destroyCount, 1) 5052 } 5053 return testApplyFn(info, s, d) 5054 } 5055 p.DiffFn = testDiffFn 5056 s := &State{ 5057 Modules: []*ModuleState{ 5058 &ModuleState{ 5059 Path: rootModulePath, 5060 Resources: map[string]*ResourceState{ 5061 "aws_instance.bar": &ResourceState{ 5062 Type: "aws_instance", 5063 Primary: &InstanceState{ 5064 ID: "baz", 5065 Attributes: map[string]string{ 5066 "num": "2", 5067 "type": "aws_instance", 5068 }, 5069 Tainted: true, 5070 }, 5071 }, 5072 }, 5073 }, 5074 }, 5075 } 5076 ctx := testContext2(t, &ContextOpts{ 5077 Module: m, 5078 Providers: map[string]ResourceProviderFactory{ 5079 "aws": testProviderFuncFixed(p), 5080 }, 5081 State: s, 5082 }) 5083 5084 if p, err := ctx.Plan(); err != nil { 5085 t.Fatalf("err: %s", err) 5086 } else { 5087 t.Logf("plan: %s", p) 5088 } 5089 5090 state, err := ctx.Apply() 5091 if err != nil { 5092 t.Fatalf("err: %s", err) 5093 } 5094 5095 actual := strings.TrimSpace(state.String()) 5096 expected := strings.TrimSpace(testTerraformApplyTaintStr) 5097 if actual != expected { 5098 t.Fatalf("bad:\n%s", actual) 5099 } 5100 5101 if destroyCount != 1 { 5102 t.Fatalf("Expected 1 destroy, got %d", destroyCount) 5103 } 5104 } 5105 5106 func TestContext2Apply_taintDep(t *testing.T) { 5107 m := testModule(t, "apply-taint-dep") 5108 p := testProvider("aws") 5109 p.ApplyFn = testApplyFn 5110 p.DiffFn = testDiffFn 5111 s := &State{ 5112 Modules: []*ModuleState{ 5113 &ModuleState{ 5114 Path: rootModulePath, 5115 Resources: map[string]*ResourceState{ 5116 "aws_instance.foo": &ResourceState{ 5117 Type: "aws_instance", 5118 Primary: &InstanceState{ 5119 ID: "baz", 5120 Attributes: map[string]string{ 5121 "num": "2", 5122 "type": "aws_instance", 5123 }, 5124 Tainted: true, 5125 }, 5126 }, 5127 "aws_instance.bar": &ResourceState{ 5128 Type: "aws_instance", 5129 Primary: &InstanceState{ 5130 ID: "bar", 5131 Attributes: map[string]string{ 5132 "foo": "baz", 5133 "num": "2", 5134 "type": "aws_instance", 5135 }, 5136 }, 5137 }, 5138 }, 5139 }, 5140 }, 5141 } 5142 ctx := testContext2(t, &ContextOpts{ 5143 Module: m, 5144 Providers: map[string]ResourceProviderFactory{ 5145 "aws": testProviderFuncFixed(p), 5146 }, 5147 State: s, 5148 }) 5149 5150 if p, err := ctx.Plan(); err != nil { 5151 t.Fatalf("err: %s", err) 5152 } else { 5153 t.Logf("plan: %s", p) 5154 } 5155 5156 state, err := ctx.Apply() 5157 if err != nil { 5158 t.Fatalf("err: %s", err) 5159 } 5160 5161 actual := strings.TrimSpace(state.String()) 5162 expected := strings.TrimSpace(testTerraformApplyTaintDepStr) 5163 if actual != expected { 5164 t.Fatalf("bad:\n%s", actual) 5165 } 5166 } 5167 5168 func TestContext2Apply_taintDepRequiresNew(t *testing.T) { 5169 m := testModule(t, "apply-taint-dep-requires-new") 5170 p := testProvider("aws") 5171 p.ApplyFn = testApplyFn 5172 p.DiffFn = testDiffFn 5173 s := &State{ 5174 Modules: []*ModuleState{ 5175 &ModuleState{ 5176 Path: rootModulePath, 5177 Resources: map[string]*ResourceState{ 5178 "aws_instance.foo": &ResourceState{ 5179 Type: "aws_instance", 5180 Primary: &InstanceState{ 5181 ID: "baz", 5182 Attributes: map[string]string{ 5183 "num": "2", 5184 "type": "aws_instance", 5185 }, 5186 Tainted: true, 5187 }, 5188 }, 5189 "aws_instance.bar": &ResourceState{ 5190 Type: "aws_instance", 5191 Primary: &InstanceState{ 5192 ID: "bar", 5193 Attributes: map[string]string{ 5194 "foo": "baz", 5195 "num": "2", 5196 "type": "aws_instance", 5197 }, 5198 }, 5199 }, 5200 }, 5201 }, 5202 }, 5203 } 5204 ctx := testContext2(t, &ContextOpts{ 5205 Module: m, 5206 Providers: map[string]ResourceProviderFactory{ 5207 "aws": testProviderFuncFixed(p), 5208 }, 5209 State: s, 5210 }) 5211 5212 if p, err := ctx.Plan(); err != nil { 5213 t.Fatalf("err: %s", err) 5214 } else { 5215 t.Logf("plan: %s", p) 5216 } 5217 5218 state, err := ctx.Apply() 5219 if err != nil { 5220 t.Fatalf("err: %s", err) 5221 } 5222 5223 actual := strings.TrimSpace(state.String()) 5224 expected := strings.TrimSpace(testTerraformApplyTaintDepRequireNewStr) 5225 if actual != expected { 5226 t.Fatalf("bad:\n%s", actual) 5227 } 5228 } 5229 5230 func TestContext2Apply_targeted(t *testing.T) { 5231 m := testModule(t, "apply-targeted") 5232 p := testProvider("aws") 5233 p.ApplyFn = testApplyFn 5234 p.DiffFn = testDiffFn 5235 ctx := testContext2(t, &ContextOpts{ 5236 Module: m, 5237 Providers: map[string]ResourceProviderFactory{ 5238 "aws": testProviderFuncFixed(p), 5239 }, 5240 Targets: []string{"aws_instance.foo"}, 5241 }) 5242 5243 if _, err := ctx.Plan(); err != nil { 5244 t.Fatalf("err: %s", err) 5245 } 5246 5247 state, err := ctx.Apply() 5248 if err != nil { 5249 t.Fatalf("err: %s", err) 5250 } 5251 5252 mod := state.RootModule() 5253 if len(mod.Resources) != 1 { 5254 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 5255 } 5256 5257 checkStateString(t, state, ` 5258 aws_instance.foo: 5259 ID = foo 5260 num = 2 5261 type = aws_instance 5262 `) 5263 } 5264 5265 func TestContext2Apply_targetedCount(t *testing.T) { 5266 m := testModule(t, "apply-targeted-count") 5267 p := testProvider("aws") 5268 p.ApplyFn = testApplyFn 5269 p.DiffFn = testDiffFn 5270 ctx := testContext2(t, &ContextOpts{ 5271 Module: m, 5272 Providers: map[string]ResourceProviderFactory{ 5273 "aws": testProviderFuncFixed(p), 5274 }, 5275 Targets: []string{"aws_instance.foo"}, 5276 }) 5277 5278 if _, err := ctx.Plan(); err != nil { 5279 t.Fatalf("err: %s", err) 5280 } 5281 5282 state, err := ctx.Apply() 5283 if err != nil { 5284 t.Fatalf("err: %s", err) 5285 } 5286 5287 checkStateString(t, state, ` 5288 aws_instance.foo.0: 5289 ID = foo 5290 aws_instance.foo.1: 5291 ID = foo 5292 aws_instance.foo.2: 5293 ID = foo 5294 `) 5295 } 5296 5297 func TestContext2Apply_targetedCountIndex(t *testing.T) { 5298 m := testModule(t, "apply-targeted-count") 5299 p := testProvider("aws") 5300 p.ApplyFn = testApplyFn 5301 p.DiffFn = testDiffFn 5302 ctx := testContext2(t, &ContextOpts{ 5303 Module: m, 5304 Providers: map[string]ResourceProviderFactory{ 5305 "aws": testProviderFuncFixed(p), 5306 }, 5307 Targets: []string{"aws_instance.foo[1]"}, 5308 }) 5309 5310 if _, err := ctx.Plan(); err != nil { 5311 t.Fatalf("err: %s", err) 5312 } 5313 5314 state, err := ctx.Apply() 5315 if err != nil { 5316 t.Fatalf("err: %s", err) 5317 } 5318 5319 checkStateString(t, state, ` 5320 aws_instance.foo.1: 5321 ID = foo 5322 `) 5323 } 5324 5325 func TestContext2Apply_targetedDestroy(t *testing.T) { 5326 m := testModule(t, "apply-targeted") 5327 p := testProvider("aws") 5328 p.ApplyFn = testApplyFn 5329 p.DiffFn = testDiffFn 5330 ctx := testContext2(t, &ContextOpts{ 5331 Module: m, 5332 Providers: map[string]ResourceProviderFactory{ 5333 "aws": testProviderFuncFixed(p), 5334 }, 5335 State: &State{ 5336 Modules: []*ModuleState{ 5337 &ModuleState{ 5338 Path: rootModulePath, 5339 Resources: map[string]*ResourceState{ 5340 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 5341 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 5342 }, 5343 }, 5344 }, 5345 }, 5346 Targets: []string{"aws_instance.foo"}, 5347 Destroy: true, 5348 }) 5349 5350 if _, err := ctx.Plan(); err != nil { 5351 t.Fatalf("err: %s", err) 5352 } 5353 5354 state, err := ctx.Apply() 5355 if err != nil { 5356 t.Fatalf("err: %s", err) 5357 } 5358 5359 mod := state.RootModule() 5360 if len(mod.Resources) != 1 { 5361 t.Fatalf("expected 1 resource, got: %#v", mod.Resources) 5362 } 5363 5364 checkStateString(t, state, ` 5365 aws_instance.bar: 5366 ID = i-abc123 5367 `) 5368 } 5369 5370 func TestContext2Apply_targetedDestroyCountDeps(t *testing.T) { 5371 m := testModule(t, "apply-destroy-targeted-count") 5372 p := testProvider("aws") 5373 p.ApplyFn = testApplyFn 5374 p.DiffFn = testDiffFn 5375 ctx := testContext2(t, &ContextOpts{ 5376 Module: m, 5377 Providers: map[string]ResourceProviderFactory{ 5378 "aws": testProviderFuncFixed(p), 5379 }, 5380 State: &State{ 5381 Modules: []*ModuleState{ 5382 &ModuleState{ 5383 Path: rootModulePath, 5384 Resources: map[string]*ResourceState{ 5385 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 5386 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 5387 }, 5388 }, 5389 }, 5390 }, 5391 Targets: []string{"aws_instance.foo"}, 5392 Destroy: true, 5393 }) 5394 5395 if _, err := ctx.Plan(); err != nil { 5396 t.Fatalf("err: %s", err) 5397 } 5398 5399 state, err := ctx.Apply() 5400 if err != nil { 5401 t.Fatalf("err: %s", err) 5402 } 5403 5404 checkStateString(t, state, `<no state>`) 5405 } 5406 5407 // https://github.com/hashicorp/terraform/issues/4462 5408 func TestContext2Apply_targetedDestroyModule(t *testing.T) { 5409 m := testModule(t, "apply-targeted-module") 5410 p := testProvider("aws") 5411 p.ApplyFn = testApplyFn 5412 p.DiffFn = testDiffFn 5413 ctx := testContext2(t, &ContextOpts{ 5414 Module: m, 5415 Providers: map[string]ResourceProviderFactory{ 5416 "aws": testProviderFuncFixed(p), 5417 }, 5418 State: &State{ 5419 Modules: []*ModuleState{ 5420 &ModuleState{ 5421 Path: rootModulePath, 5422 Resources: map[string]*ResourceState{ 5423 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 5424 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 5425 }, 5426 }, 5427 &ModuleState{ 5428 Path: []string{"root", "child"}, 5429 Resources: map[string]*ResourceState{ 5430 "aws_instance.foo": resourceState("aws_instance", "i-bcd345"), 5431 "aws_instance.bar": resourceState("aws_instance", "i-abc123"), 5432 }, 5433 }, 5434 }, 5435 }, 5436 Targets: []string{"module.child.aws_instance.foo"}, 5437 Destroy: true, 5438 }) 5439 5440 if _, err := ctx.Plan(); err != nil { 5441 t.Fatalf("err: %s", err) 5442 } 5443 5444 state, err := ctx.Apply() 5445 if err != nil { 5446 t.Fatalf("err: %s", err) 5447 } 5448 5449 checkStateString(t, state, ` 5450 aws_instance.bar: 5451 ID = i-abc123 5452 aws_instance.foo: 5453 ID = i-bcd345 5454 5455 module.child: 5456 aws_instance.bar: 5457 ID = i-abc123 5458 `) 5459 } 5460 5461 func TestContext2Apply_targetedDestroyCountIndex(t *testing.T) { 5462 m := testModule(t, "apply-targeted-count") 5463 p := testProvider("aws") 5464 p.ApplyFn = testApplyFn 5465 p.DiffFn = testDiffFn 5466 ctx := testContext2(t, &ContextOpts{ 5467 Module: m, 5468 Providers: map[string]ResourceProviderFactory{ 5469 "aws": testProviderFuncFixed(p), 5470 }, 5471 State: &State{ 5472 Modules: []*ModuleState{ 5473 &ModuleState{ 5474 Path: rootModulePath, 5475 Resources: map[string]*ResourceState{ 5476 "aws_instance.foo.0": resourceState("aws_instance", "i-bcd345"), 5477 "aws_instance.foo.1": resourceState("aws_instance", "i-bcd345"), 5478 "aws_instance.foo.2": resourceState("aws_instance", "i-bcd345"), 5479 "aws_instance.bar.0": resourceState("aws_instance", "i-abc123"), 5480 "aws_instance.bar.1": resourceState("aws_instance", "i-abc123"), 5481 "aws_instance.bar.2": resourceState("aws_instance", "i-abc123"), 5482 }, 5483 }, 5484 }, 5485 }, 5486 Targets: []string{ 5487 "aws_instance.foo[2]", 5488 "aws_instance.bar[1]", 5489 }, 5490 Destroy: true, 5491 }) 5492 5493 if _, err := ctx.Plan(); err != nil { 5494 t.Fatalf("err: %s", err) 5495 } 5496 5497 state, err := ctx.Apply() 5498 if err != nil { 5499 t.Fatalf("err: %s", err) 5500 } 5501 5502 checkStateString(t, state, ` 5503 aws_instance.bar.0: 5504 ID = i-abc123 5505 aws_instance.bar.2: 5506 ID = i-abc123 5507 aws_instance.foo.0: 5508 ID = i-bcd345 5509 aws_instance.foo.1: 5510 ID = i-bcd345 5511 `) 5512 } 5513 5514 func TestContext2Apply_targetedModule(t *testing.T) { 5515 m := testModule(t, "apply-targeted-module") 5516 p := testProvider("aws") 5517 p.ApplyFn = testApplyFn 5518 p.DiffFn = testDiffFn 5519 ctx := testContext2(t, &ContextOpts{ 5520 Module: m, 5521 Providers: map[string]ResourceProviderFactory{ 5522 "aws": testProviderFuncFixed(p), 5523 }, 5524 Targets: []string{"module.child"}, 5525 }) 5526 5527 if _, err := ctx.Plan(); err != nil { 5528 t.Fatalf("err: %s", err) 5529 } 5530 5531 state, err := ctx.Apply() 5532 if err != nil { 5533 t.Fatalf("err: %s", err) 5534 } 5535 5536 mod := state.ModuleByPath([]string{"root", "child"}) 5537 if mod == nil { 5538 t.Fatalf("no child module found in the state!\n\n%#v", state) 5539 } 5540 if len(mod.Resources) != 2 { 5541 t.Fatalf("expected 2 resources, got: %#v", mod.Resources) 5542 } 5543 5544 checkStateString(t, state, ` 5545 <no state> 5546 module.child: 5547 aws_instance.bar: 5548 ID = foo 5549 num = 2 5550 type = aws_instance 5551 aws_instance.foo: 5552 ID = foo 5553 num = 2 5554 type = aws_instance 5555 `) 5556 } 5557 5558 // GH-1858 5559 func TestContext2Apply_targetedModuleDep(t *testing.T) { 5560 m := testModule(t, "apply-targeted-module-dep") 5561 p := testProvider("aws") 5562 p.ApplyFn = testApplyFn 5563 p.DiffFn = testDiffFn 5564 ctx := testContext2(t, &ContextOpts{ 5565 Module: m, 5566 Providers: map[string]ResourceProviderFactory{ 5567 "aws": testProviderFuncFixed(p), 5568 }, 5569 Targets: []string{"aws_instance.foo"}, 5570 }) 5571 5572 if p, err := ctx.Plan(); err != nil { 5573 t.Fatalf("err: %s", err) 5574 } else { 5575 t.Logf("Diff: %s", p) 5576 } 5577 5578 state, err := ctx.Apply() 5579 if err != nil { 5580 t.Fatalf("err: %s", err) 5581 } 5582 5583 checkStateString(t, state, ` 5584 aws_instance.foo: 5585 ID = foo 5586 foo = foo 5587 type = aws_instance 5588 5589 Dependencies: 5590 module.child 5591 5592 module.child: 5593 aws_instance.mod: 5594 ID = foo 5595 5596 Outputs: 5597 5598 output = foo 5599 `) 5600 } 5601 5602 func TestContext2Apply_targetedModuleResource(t *testing.T) { 5603 m := testModule(t, "apply-targeted-module-resource") 5604 p := testProvider("aws") 5605 p.ApplyFn = testApplyFn 5606 p.DiffFn = testDiffFn 5607 ctx := testContext2(t, &ContextOpts{ 5608 Module: m, 5609 Providers: map[string]ResourceProviderFactory{ 5610 "aws": testProviderFuncFixed(p), 5611 }, 5612 Targets: []string{"module.child.aws_instance.foo"}, 5613 }) 5614 5615 if _, err := ctx.Plan(); err != nil { 5616 t.Fatalf("err: %s", err) 5617 } 5618 5619 state, err := ctx.Apply() 5620 if err != nil { 5621 t.Fatalf("err: %s", err) 5622 } 5623 5624 mod := state.ModuleByPath([]string{"root", "child"}) 5625 if mod == nil || len(mod.Resources) != 1 { 5626 t.Fatalf("expected 1 resource, got: %#v", mod) 5627 } 5628 5629 checkStateString(t, state, ` 5630 <no state> 5631 module.child: 5632 aws_instance.foo: 5633 ID = foo 5634 num = 2 5635 type = aws_instance 5636 `) 5637 } 5638 5639 func TestContext2Apply_unknownAttribute(t *testing.T) { 5640 m := testModule(t, "apply-unknown") 5641 p := testProvider("aws") 5642 p.ApplyFn = testApplyFn 5643 p.DiffFn = testDiffFn 5644 ctx := testContext2(t, &ContextOpts{ 5645 Module: m, 5646 Providers: map[string]ResourceProviderFactory{ 5647 "aws": testProviderFuncFixed(p), 5648 }, 5649 }) 5650 5651 if _, err := ctx.Plan(); err != nil { 5652 t.Fatalf("err: %s", err) 5653 } 5654 5655 state, err := ctx.Apply() 5656 if err == nil { 5657 t.Fatal("should error") 5658 } 5659 5660 actual := strings.TrimSpace(state.String()) 5661 expected := strings.TrimSpace(testTerraformApplyUnknownAttrStr) 5662 if actual != expected { 5663 t.Fatalf("bad: \n%s", actual) 5664 } 5665 } 5666 5667 func TestContext2Apply_unknownAttributeInterpolate(t *testing.T) { 5668 m := testModule(t, "apply-unknown-interpolate") 5669 p := testProvider("aws") 5670 p.ApplyFn = testApplyFn 5671 p.DiffFn = testDiffFn 5672 ctx := testContext2(t, &ContextOpts{ 5673 Module: m, 5674 Providers: map[string]ResourceProviderFactory{ 5675 "aws": testProviderFuncFixed(p), 5676 }, 5677 }) 5678 5679 if _, err := ctx.Plan(); err == nil { 5680 t.Fatal("should error") 5681 } 5682 } 5683 5684 func TestContext2Apply_vars(t *testing.T) { 5685 m := testModule(t, "apply-vars") 5686 p := testProvider("aws") 5687 p.ApplyFn = testApplyFn 5688 p.DiffFn = testDiffFn 5689 ctx := testContext2(t, &ContextOpts{ 5690 Module: m, 5691 Providers: map[string]ResourceProviderFactory{ 5692 "aws": testProviderFuncFixed(p), 5693 }, 5694 Variables: map[string]interface{}{ 5695 "foo": "us-west-2", 5696 "test_list": []interface{}{"Hello", "World"}, 5697 "test_map": map[string]interface{}{ 5698 "Hello": "World", 5699 "Foo": "Bar", 5700 "Baz": "Foo", 5701 }, 5702 "amis": []map[string]interface{}{ 5703 map[string]interface{}{ 5704 "us-east-1": "override", 5705 }, 5706 }, 5707 }, 5708 }) 5709 5710 w, e := ctx.Validate() 5711 if len(w) > 0 { 5712 t.Fatalf("bad: %#v", w) 5713 } 5714 if len(e) > 0 { 5715 t.Fatalf("bad: %s", e) 5716 } 5717 5718 if _, err := ctx.Plan(); err != nil { 5719 t.Fatalf("err: %s", err) 5720 } 5721 5722 state, err := ctx.Apply() 5723 if err != nil { 5724 t.Fatalf("err: %s", err) 5725 } 5726 5727 actual := strings.TrimSpace(state.String()) 5728 expected := strings.TrimSpace(testTerraformApplyVarsStr) 5729 if actual != expected { 5730 t.Fatalf("expected: %s\n got:\n%s", expected, actual) 5731 } 5732 } 5733 5734 func TestContext2Apply_varsEnv(t *testing.T) { 5735 // Set the env var 5736 defer tempEnv(t, "TF_VAR_ami", "baz")() 5737 defer tempEnv(t, "TF_VAR_list", `["Hello", "World"]`)() 5738 defer tempEnv(t, "TF_VAR_map", `{"Hello" = "World", "Foo" = "Bar", "Baz" = "Foo"}`)() 5739 5740 m := testModule(t, "apply-vars-env") 5741 p := testProvider("aws") 5742 p.ApplyFn = testApplyFn 5743 p.DiffFn = testDiffFn 5744 ctx := testContext2(t, &ContextOpts{ 5745 Module: m, 5746 Providers: map[string]ResourceProviderFactory{ 5747 "aws": testProviderFuncFixed(p), 5748 }, 5749 }) 5750 5751 w, e := ctx.Validate() 5752 if len(w) > 0 { 5753 t.Fatalf("bad: %#v", w) 5754 } 5755 if len(e) > 0 { 5756 t.Fatalf("bad: %s", e) 5757 } 5758 5759 if _, err := ctx.Plan(); err != nil { 5760 t.Fatalf("err: %s", err) 5761 } 5762 5763 state, err := ctx.Apply() 5764 if err != nil { 5765 t.Fatalf("err: %s", err) 5766 } 5767 5768 actual := strings.TrimSpace(state.String()) 5769 expected := strings.TrimSpace(testTerraformApplyVarsEnvStr) 5770 if actual != expected { 5771 t.Fatalf("bad: \n%s", actual) 5772 } 5773 } 5774 5775 func TestContext2Apply_createBefore_depends(t *testing.T) { 5776 m := testModule(t, "apply-depends-create-before") 5777 h := new(HookRecordApplyOrder) 5778 p := testProvider("aws") 5779 p.ApplyFn = testApplyFn 5780 p.DiffFn = testDiffFn 5781 state := &State{ 5782 Modules: []*ModuleState{ 5783 &ModuleState{ 5784 Path: rootModulePath, 5785 Resources: map[string]*ResourceState{ 5786 "aws_instance.web": &ResourceState{ 5787 Type: "aws_instance", 5788 Primary: &InstanceState{ 5789 ID: "bar", 5790 Attributes: map[string]string{ 5791 "require_new": "ami-old", 5792 }, 5793 }, 5794 }, 5795 "aws_instance.lb": &ResourceState{ 5796 Type: "aws_instance", 5797 Primary: &InstanceState{ 5798 ID: "baz", 5799 Attributes: map[string]string{ 5800 "instance": "bar", 5801 }, 5802 }, 5803 }, 5804 }, 5805 }, 5806 }, 5807 } 5808 ctx := testContext2(t, &ContextOpts{ 5809 Module: m, 5810 Hooks: []Hook{h}, 5811 Providers: map[string]ResourceProviderFactory{ 5812 "aws": testProviderFuncFixed(p), 5813 }, 5814 State: state, 5815 }) 5816 5817 if p, err := ctx.Plan(); err != nil { 5818 t.Fatalf("err: %s", err) 5819 } else { 5820 t.Logf("plan: %s", p) 5821 } 5822 5823 h.Active = true 5824 state, err := ctx.Apply() 5825 if err != nil { 5826 t.Fatalf("err: %s", err) 5827 } 5828 5829 mod := state.RootModule() 5830 if len(mod.Resources) < 2 { 5831 t.Fatalf("bad: %#v", mod.Resources) 5832 } 5833 5834 actual := strings.TrimSpace(state.String()) 5835 expected := strings.TrimSpace(testTerraformApplyDependsCreateBeforeStr) 5836 if actual != expected { 5837 t.Fatalf("bad: \n%s\n\n%s", actual, expected) 5838 } 5839 5840 // Test that things were managed _in the right order_ 5841 order := h.States 5842 diffs := h.Diffs 5843 if order[0].ID != "" || diffs[0].Destroy { 5844 t.Fatalf("should create new instance first: %#v", order) 5845 } 5846 5847 if order[1].ID != "baz" { 5848 t.Fatalf("update must happen after create: %#v", order) 5849 } 5850 5851 if order[2].ID != "bar" || !diffs[2].Destroy { 5852 t.Fatalf("destroy must happen after update: %#v", order) 5853 } 5854 } 5855 5856 func TestContext2Apply_singleDestroy(t *testing.T) { 5857 m := testModule(t, "apply-depends-create-before") 5858 h := new(HookRecordApplyOrder) 5859 p := testProvider("aws") 5860 5861 invokeCount := 0 5862 p.ApplyFn = func(info *InstanceInfo, s *InstanceState, d *InstanceDiff) (*InstanceState, error) { 5863 invokeCount++ 5864 switch invokeCount { 5865 case 1: 5866 if d.Destroy { 5867 t.Fatalf("should not destroy") 5868 } 5869 if s.ID != "" { 5870 t.Fatalf("should not have ID") 5871 } 5872 case 2: 5873 if d.Destroy { 5874 t.Fatalf("should not destroy") 5875 } 5876 if s.ID != "baz" { 5877 t.Fatalf("should have id") 5878 } 5879 case 3: 5880 if !d.Destroy { 5881 t.Fatalf("should destroy") 5882 } 5883 if s.ID == "" { 5884 t.Fatalf("should have ID") 5885 } 5886 default: 5887 t.Fatalf("bad invoke count %d", invokeCount) 5888 } 5889 return testApplyFn(info, s, d) 5890 } 5891 p.DiffFn = testDiffFn 5892 state := &State{ 5893 Modules: []*ModuleState{ 5894 &ModuleState{ 5895 Path: rootModulePath, 5896 Resources: map[string]*ResourceState{ 5897 "aws_instance.web": &ResourceState{ 5898 Type: "aws_instance", 5899 Primary: &InstanceState{ 5900 ID: "bar", 5901 Attributes: map[string]string{ 5902 "require_new": "ami-old", 5903 }, 5904 }, 5905 }, 5906 "aws_instance.lb": &ResourceState{ 5907 Type: "aws_instance", 5908 Primary: &InstanceState{ 5909 ID: "baz", 5910 Attributes: map[string]string{ 5911 "instance": "bar", 5912 }, 5913 }, 5914 }, 5915 }, 5916 }, 5917 }, 5918 } 5919 ctx := testContext2(t, &ContextOpts{ 5920 Module: m, 5921 Hooks: []Hook{h}, 5922 Providers: map[string]ResourceProviderFactory{ 5923 "aws": testProviderFuncFixed(p), 5924 }, 5925 State: state, 5926 }) 5927 5928 if _, err := ctx.Plan(); err != nil { 5929 t.Fatalf("err: %s", err) 5930 } 5931 5932 h.Active = true 5933 state, err := ctx.Apply() 5934 if err != nil { 5935 t.Fatalf("err: %s", err) 5936 } 5937 5938 if invokeCount != 3 { 5939 t.Fatalf("bad: %d", invokeCount) 5940 } 5941 } 5942 5943 // GH-7824 5944 func TestContext2Apply_issue7824(t *testing.T) { 5945 p := testProvider("template") 5946 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 5947 Name: "template_file", 5948 }) 5949 5950 p.ApplyFn = testApplyFn 5951 p.DiffFn = testDiffFn 5952 5953 // Apply cleanly step 0 5954 ctx := testContext2(t, &ContextOpts{ 5955 Module: testModule(t, "issue-7824"), 5956 Providers: map[string]ResourceProviderFactory{ 5957 "template": testProviderFuncFixed(p), 5958 }, 5959 }) 5960 5961 plan, err := ctx.Plan() 5962 if err != nil { 5963 t.Fatalf("err: %s", err) 5964 } 5965 5966 // Write / Read plan to simulate running it through a Plan file 5967 var buf bytes.Buffer 5968 if err := WritePlan(plan, &buf); err != nil { 5969 t.Fatalf("err: %s", err) 5970 } 5971 5972 planFromFile, err := ReadPlan(&buf) 5973 if err != nil { 5974 t.Fatalf("err: %s", err) 5975 } 5976 5977 ctx, err = planFromFile.Context(&ContextOpts{ 5978 Providers: map[string]ResourceProviderFactory{ 5979 "template": testProviderFuncFixed(p), 5980 }, 5981 }) 5982 if err != nil { 5983 t.Fatalf("err: %s", err) 5984 } 5985 5986 _, err = ctx.Apply() 5987 if err != nil { 5988 t.Fatalf("err: %s", err) 5989 } 5990 } 5991 5992 // GH-5254 5993 func TestContext2Apply_issue5254(t *testing.T) { 5994 // Create a provider. We use "template" here just to match the repro 5995 // we got from the issue itself. 5996 p := testProvider("template") 5997 p.ResourcesReturn = append(p.ResourcesReturn, ResourceType{ 5998 Name: "template_file", 5999 }) 6000 6001 p.ApplyFn = testApplyFn 6002 p.DiffFn = testDiffFn 6003 6004 // Apply cleanly step 0 6005 ctx := testContext2(t, &ContextOpts{ 6006 Module: testModule(t, "issue-5254/step-0"), 6007 Providers: map[string]ResourceProviderFactory{ 6008 "template": testProviderFuncFixed(p), 6009 }, 6010 }) 6011 6012 plan, err := ctx.Plan() 6013 if err != nil { 6014 t.Fatalf("err: %s", err) 6015 } 6016 6017 state, err := ctx.Apply() 6018 if err != nil { 6019 t.Fatalf("err: %s", err) 6020 } 6021 6022 // Application success. Now make the modification and store a plan 6023 ctx = testContext2(t, &ContextOpts{ 6024 Module: testModule(t, "issue-5254/step-1"), 6025 State: state, 6026 Providers: map[string]ResourceProviderFactory{ 6027 "template": testProviderFuncFixed(p), 6028 }, 6029 }) 6030 6031 plan, err = ctx.Plan() 6032 if err != nil { 6033 t.Fatalf("err: %s", err) 6034 } 6035 6036 // Write / Read plan to simulate running it through a Plan file 6037 var buf bytes.Buffer 6038 if err := WritePlan(plan, &buf); err != nil { 6039 t.Fatalf("err: %s", err) 6040 } 6041 6042 planFromFile, err := ReadPlan(&buf) 6043 if err != nil { 6044 t.Fatalf("err: %s", err) 6045 } 6046 6047 ctx, err = planFromFile.Context(&ContextOpts{ 6048 Providers: map[string]ResourceProviderFactory{ 6049 "template": testProviderFuncFixed(p), 6050 }, 6051 }) 6052 if err != nil { 6053 t.Fatalf("err: %s", err) 6054 } 6055 6056 state, err = ctx.Apply() 6057 if err != nil { 6058 t.Fatalf("err: %s", err) 6059 } 6060 6061 actual := strings.TrimSpace(state.String()) 6062 expected := strings.TrimSpace(` 6063 template_file.child: 6064 ID = foo 6065 template = Hi 6066 type = template_file 6067 6068 Dependencies: 6069 template_file.parent 6070 template_file.parent: 6071 ID = foo 6072 template = Hi 6073 type = template_file 6074 `) 6075 if actual != expected { 6076 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 6077 } 6078 } 6079 6080 func TestContext2Apply_targetedWithTaintedInState(t *testing.T) { 6081 p := testProvider("aws") 6082 p.DiffFn = testDiffFn 6083 p.ApplyFn = testApplyFn 6084 ctx := testContext2(t, &ContextOpts{ 6085 Module: testModule(t, "apply-tainted-targets"), 6086 Providers: map[string]ResourceProviderFactory{ 6087 "aws": testProviderFuncFixed(p), 6088 }, 6089 Targets: []string{"aws_instance.iambeingadded"}, 6090 State: &State{ 6091 Modules: []*ModuleState{ 6092 &ModuleState{ 6093 Path: rootModulePath, 6094 Resources: map[string]*ResourceState{ 6095 "aws_instance.ifailedprovisioners": &ResourceState{ 6096 Primary: &InstanceState{ 6097 ID: "ifailedprovisioners", 6098 Tainted: true, 6099 }, 6100 }, 6101 }, 6102 }, 6103 }, 6104 }, 6105 }) 6106 6107 plan, err := ctx.Plan() 6108 if err != nil { 6109 t.Fatalf("err: %s", err) 6110 } 6111 6112 // Write / Read plan to simulate running it through a Plan file 6113 var buf bytes.Buffer 6114 if err := WritePlan(plan, &buf); err != nil { 6115 t.Fatalf("err: %s", err) 6116 } 6117 6118 planFromFile, err := ReadPlan(&buf) 6119 if err != nil { 6120 t.Fatalf("err: %s", err) 6121 } 6122 6123 ctx, err = planFromFile.Context(&ContextOpts{ 6124 Module: testModule(t, "apply-tainted-targets"), 6125 Providers: map[string]ResourceProviderFactory{ 6126 "aws": testProviderFuncFixed(p), 6127 }, 6128 }) 6129 if err != nil { 6130 t.Fatalf("err: %s", err) 6131 } 6132 6133 state, err := ctx.Apply() 6134 if err != nil { 6135 t.Fatalf("err: %s", err) 6136 } 6137 6138 actual := strings.TrimSpace(state.String()) 6139 expected := strings.TrimSpace(` 6140 aws_instance.iambeingadded: 6141 ID = foo 6142 aws_instance.ifailedprovisioners: (tainted) 6143 ID = ifailedprovisioners 6144 `) 6145 if actual != expected { 6146 t.Fatalf("expected state: \n%s\ngot: \n%s", expected, actual) 6147 } 6148 } 6149 6150 // Higher level test exposing the bug this covers in 6151 // TestResource_ignoreChangesRequired 6152 func TestContext2Apply_ignoreChangesCreate(t *testing.T) { 6153 m := testModule(t, "apply-ignore-changes-create") 6154 p := testProvider("aws") 6155 p.ApplyFn = testApplyFn 6156 p.DiffFn = testDiffFn 6157 ctx := testContext2(t, &ContextOpts{ 6158 Module: m, 6159 Providers: map[string]ResourceProviderFactory{ 6160 "aws": testProviderFuncFixed(p), 6161 }, 6162 }) 6163 6164 if p, err := ctx.Plan(); err != nil { 6165 t.Fatalf("err: %s", err) 6166 } else { 6167 t.Logf(p.String()) 6168 } 6169 6170 state, err := ctx.Apply() 6171 if err != nil { 6172 t.Fatalf("err: %s", err) 6173 } 6174 6175 mod := state.RootModule() 6176 if len(mod.Resources) != 1 { 6177 t.Fatalf("bad: %s", state) 6178 } 6179 6180 actual := strings.TrimSpace(state.String()) 6181 // Expect no changes from original state 6182 expected := strings.TrimSpace(` 6183 aws_instance.foo: 6184 ID = foo 6185 required_field = set 6186 type = aws_instance 6187 `) 6188 if actual != expected { 6189 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 6190 } 6191 } 6192 6193 func TestContext2Apply_ignoreChangesWithDep(t *testing.T) { 6194 m := testModule(t, "apply-ignore-changes-dep") 6195 p := testProvider("aws") 6196 p.ApplyFn = testApplyFn 6197 p.DiffFn = func(i *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) { 6198 switch i.Type { 6199 case "aws_instance": 6200 newAmi, _ := c.Get("ami") 6201 return &InstanceDiff{ 6202 Attributes: map[string]*ResourceAttrDiff{ 6203 "ami": &ResourceAttrDiff{ 6204 Old: s.Attributes["ami"], 6205 New: newAmi.(string), 6206 RequiresNew: true, 6207 }, 6208 }, 6209 }, nil 6210 case "aws_eip": 6211 return testDiffFn(i, s, c) 6212 default: 6213 t.Fatalf("Unexpected type: %s", i.Type) 6214 return nil, nil 6215 } 6216 } 6217 s := &State{ 6218 Modules: []*ModuleState{ 6219 &ModuleState{ 6220 Path: rootModulePath, 6221 Resources: map[string]*ResourceState{ 6222 "aws_instance.foo.0": &ResourceState{ 6223 Primary: &InstanceState{ 6224 ID: "i-abc123", 6225 Attributes: map[string]string{ 6226 "ami": "ami-abcd1234", 6227 "id": "i-abc123", 6228 }, 6229 }, 6230 }, 6231 "aws_instance.foo.1": &ResourceState{ 6232 Primary: &InstanceState{ 6233 ID: "i-bcd234", 6234 Attributes: map[string]string{ 6235 "ami": "ami-abcd1234", 6236 "id": "i-bcd234", 6237 }, 6238 }, 6239 }, 6240 "aws_eip.foo.0": &ResourceState{ 6241 Primary: &InstanceState{ 6242 ID: "eip-abc123", 6243 Attributes: map[string]string{ 6244 "id": "eip-abc123", 6245 "instance": "i-abc123", 6246 }, 6247 }, 6248 }, 6249 "aws_eip.foo.1": &ResourceState{ 6250 Primary: &InstanceState{ 6251 ID: "eip-bcd234", 6252 Attributes: map[string]string{ 6253 "id": "eip-bcd234", 6254 "instance": "i-bcd234", 6255 }, 6256 }, 6257 }, 6258 }, 6259 }, 6260 }, 6261 } 6262 ctx := testContext2(t, &ContextOpts{ 6263 Module: m, 6264 Providers: map[string]ResourceProviderFactory{ 6265 "aws": testProviderFuncFixed(p), 6266 }, 6267 State: s, 6268 }) 6269 6270 if p, err := ctx.Plan(); err != nil { 6271 t.Fatalf("err: %s", err) 6272 } else { 6273 t.Logf(p.String()) 6274 } 6275 6276 state, err := ctx.Apply() 6277 if err != nil { 6278 t.Fatalf("err: %s", err) 6279 } 6280 6281 actual := strings.TrimSpace(state.String()) 6282 expected := strings.TrimSpace(s.String()) 6283 if actual != expected { 6284 t.Fatalf("bad: \n%s", actual) 6285 } 6286 } 6287 6288 func TestContext2Apply_ignoreChangesWildcard(t *testing.T) { 6289 m := testModule(t, "apply-ignore-changes-wildcard") 6290 p := testProvider("aws") 6291 p.ApplyFn = testApplyFn 6292 p.DiffFn = testDiffFn 6293 ctx := testContext2(t, &ContextOpts{ 6294 Module: m, 6295 Providers: map[string]ResourceProviderFactory{ 6296 "aws": testProviderFuncFixed(p), 6297 }, 6298 }) 6299 6300 if p, err := ctx.Plan(); err != nil { 6301 t.Fatalf("err: %s", err) 6302 } else { 6303 t.Logf(p.String()) 6304 } 6305 6306 state, err := ctx.Apply() 6307 if err != nil { 6308 t.Fatalf("err: %s", err) 6309 } 6310 6311 mod := state.RootModule() 6312 if len(mod.Resources) != 1 { 6313 t.Fatalf("bad: %s", state) 6314 } 6315 6316 actual := strings.TrimSpace(state.String()) 6317 // Expect no changes from original state 6318 expected := strings.TrimSpace(` 6319 aws_instance.foo: 6320 ID = foo 6321 required_field = set 6322 type = aws_instance 6323 `) 6324 if actual != expected { 6325 t.Fatalf("expected:\n%s\ngot:\n%s", expected, actual) 6326 } 6327 } 6328 6329 // https://github.com/hashicorp/terraform/issues/7378 6330 func TestContext2Apply_destroyNestedModuleWithAttrsReferencingResource(t *testing.T) { 6331 m := testModule(t, "apply-destroy-nested-module-with-attrs") 6332 p := testProvider("null") 6333 p.ApplyFn = testApplyFn 6334 p.DiffFn = testDiffFn 6335 6336 var state *State 6337 var err error 6338 { 6339 ctx := testContext2(t, &ContextOpts{ 6340 Module: m, 6341 Providers: map[string]ResourceProviderFactory{ 6342 "null": testProviderFuncFixed(p), 6343 }, 6344 }) 6345 6346 // First plan and apply a create operation 6347 if _, err := ctx.Plan(); err != nil { 6348 t.Fatalf("plan err: %s", err) 6349 } 6350 6351 state, err = ctx.Apply() 6352 if err != nil { 6353 t.Fatalf("apply err: %s", err) 6354 } 6355 } 6356 6357 { 6358 ctx := testContext2(t, &ContextOpts{ 6359 Destroy: true, 6360 Module: m, 6361 State: state, 6362 Providers: map[string]ResourceProviderFactory{ 6363 "null": testProviderFuncFixed(p), 6364 }, 6365 }) 6366 6367 plan, err := ctx.Plan() 6368 if err != nil { 6369 t.Fatalf("destroy plan err: %s", err) 6370 } 6371 6372 var buf bytes.Buffer 6373 if err := WritePlan(plan, &buf); err != nil { 6374 t.Fatalf("plan write err: %s", err) 6375 } 6376 6377 planFromFile, err := ReadPlan(&buf) 6378 if err != nil { 6379 t.Fatalf("plan read err: %s", err) 6380 } 6381 6382 ctx, err = planFromFile.Context(&ContextOpts{ 6383 Providers: map[string]ResourceProviderFactory{ 6384 "null": testProviderFuncFixed(p), 6385 }, 6386 }) 6387 if err != nil { 6388 t.Fatalf("err: %s", err) 6389 } 6390 6391 state, err = ctx.Apply() 6392 if err != nil { 6393 t.Fatalf("destroy apply err: %s", err) 6394 } 6395 } 6396 6397 //Test that things were destroyed 6398 actual := strings.TrimSpace(state.String()) 6399 expected := strings.TrimSpace(` 6400 <no state> 6401 module.middle: 6402 <no state> 6403 module.middle.bottom: 6404 <no state> 6405 `) 6406 if actual != expected { 6407 t.Fatalf("expected: \n%s\n\nbad: \n%s", expected, actual) 6408 } 6409 }