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