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