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