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