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