github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/command/import_test.go (about) 1 package command 2 3 import ( 4 "fmt" 5 "log" 6 "os" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/mitchellh/cli" 12 "github.com/zclconf/go-cty/cty" 13 14 "github.com/hashicorp/terraform/internal/configs/configschema" 15 "github.com/hashicorp/terraform/internal/copy" 16 "github.com/hashicorp/terraform/internal/providers" 17 "github.com/hashicorp/terraform/internal/tfdiags" 18 ) 19 20 func TestImport(t *testing.T) { 21 defer testChdir(t, testFixturePath("import-provider-implicit"))() 22 23 statePath := testTempFile(t) 24 25 p := testProvider() 26 ui := new(cli.MockUi) 27 view, _ := testView(t) 28 c := &ImportCommand{ 29 Meta: Meta{ 30 testingOverrides: metaOverridesForProvider(p), 31 Ui: ui, 32 View: view, 33 }, 34 } 35 36 p.ImportResourceStateFn = nil 37 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 38 ImportedResources: []providers.ImportedResource{ 39 { 40 TypeName: "test_instance", 41 State: cty.ObjectVal(map[string]cty.Value{ 42 "id": cty.StringVal("yay"), 43 }), 44 }, 45 }, 46 } 47 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 48 ResourceTypes: map[string]providers.Schema{ 49 "test_instance": { 50 Block: &configschema.Block{ 51 Attributes: map[string]*configschema.Attribute{ 52 "id": {Type: cty.String, Optional: true, Computed: true}, 53 }, 54 }, 55 }, 56 }, 57 } 58 59 args := []string{ 60 "-state", statePath, 61 "test_instance.foo", 62 "bar", 63 } 64 if code := c.Run(args); code != 0 { 65 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 66 } 67 68 if !p.ImportResourceStateCalled { 69 t.Fatal("ImportResourceState should be called") 70 } 71 72 testStateOutput(t, statePath, testImportStr) 73 } 74 75 func TestImport_providerConfig(t *testing.T) { 76 defer testChdir(t, testFixturePath("import-provider"))() 77 78 statePath := testTempFile(t) 79 80 p := testProvider() 81 ui := new(cli.MockUi) 82 view, _ := testView(t) 83 c := &ImportCommand{ 84 Meta: Meta{ 85 testingOverrides: metaOverridesForProvider(p), 86 Ui: ui, 87 View: view, 88 }, 89 } 90 91 p.ImportResourceStateFn = nil 92 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 93 ImportedResources: []providers.ImportedResource{ 94 { 95 TypeName: "test_instance", 96 State: cty.ObjectVal(map[string]cty.Value{ 97 "id": cty.StringVal("yay"), 98 }), 99 }, 100 }, 101 } 102 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 103 Provider: providers.Schema{ 104 Block: &configschema.Block{ 105 Attributes: map[string]*configschema.Attribute{ 106 "foo": {Type: cty.String, Optional: true}, 107 }, 108 }, 109 }, 110 ResourceTypes: map[string]providers.Schema{ 111 "test_instance": { 112 Block: &configschema.Block{ 113 Attributes: map[string]*configschema.Attribute{ 114 "id": {Type: cty.String, Optional: true, Computed: true}, 115 }, 116 }, 117 }, 118 }, 119 } 120 121 configured := false 122 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse { 123 configured = true 124 125 cfg := req.Config 126 if !cfg.Type().HasAttribute("foo") { 127 return providers.ConfigureProviderResponse{ 128 Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("configuration has no foo argument")), 129 } 130 } 131 if got, want := cfg.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) { 132 return providers.ConfigureProviderResponse{ 133 Diagnostics: tfdiags.Diagnostics{}.Append(fmt.Errorf("foo argument is %#v, but want %#v", got, want)), 134 } 135 } 136 137 return providers.ConfigureProviderResponse{} 138 } 139 140 args := []string{ 141 "-state", statePath, 142 "test_instance.foo", 143 "bar", 144 } 145 if code := c.Run(args); code != 0 { 146 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 147 } 148 149 // Verify that we were called 150 if !configured { 151 t.Fatal("Configure should be called") 152 } 153 154 if !p.ImportResourceStateCalled { 155 t.Fatal("ImportResourceState should be called") 156 } 157 158 testStateOutput(t, statePath, testImportStr) 159 } 160 161 // "remote" state provided by the "local" backend 162 func TestImport_remoteState(t *testing.T) { 163 td := t.TempDir() 164 testCopyDir(t, testFixturePath("import-provider-remote-state"), td) 165 defer testChdir(t, td)() 166 167 statePath := "imported.tfstate" 168 169 providerSource, close := newMockProviderSource(t, map[string][]string{ 170 "test": []string{"1.2.3"}, 171 }) 172 defer close() 173 174 // init our backend 175 ui := cli.NewMockUi() 176 view, _ := testView(t) 177 m := Meta{ 178 testingOverrides: metaOverridesForProvider(testProvider()), 179 Ui: ui, 180 View: view, 181 ProviderSource: providerSource, 182 } 183 184 ic := &InitCommand{ 185 Meta: m, 186 } 187 188 // (Using log here rather than t.Log so that these messages interleave with other trace logs) 189 log.Print("[TRACE] TestImport_remoteState running: terraform init") 190 if code := ic.Run([]string{}); code != 0 { 191 t.Fatalf("init failed\n%s", ui.ErrorWriter) 192 } 193 194 p := testProvider() 195 ui = new(cli.MockUi) 196 c := &ImportCommand{ 197 Meta: Meta{ 198 testingOverrides: metaOverridesForProvider(p), 199 Ui: ui, 200 View: view, 201 }, 202 } 203 204 p.ImportResourceStateFn = nil 205 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 206 ImportedResources: []providers.ImportedResource{ 207 { 208 TypeName: "test_instance", 209 State: cty.ObjectVal(map[string]cty.Value{ 210 "id": cty.StringVal("yay"), 211 }), 212 }, 213 }, 214 } 215 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 216 Provider: providers.Schema{ 217 Block: &configschema.Block{ 218 Attributes: map[string]*configschema.Attribute{ 219 "foo": {Type: cty.String, Optional: true}, 220 }, 221 }, 222 }, 223 ResourceTypes: map[string]providers.Schema{ 224 "test_instance": { 225 Block: &configschema.Block{ 226 Attributes: map[string]*configschema.Attribute{ 227 "id": {Type: cty.String, Optional: true, Computed: true}, 228 }, 229 }, 230 }, 231 }, 232 } 233 234 configured := false 235 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse { 236 var diags tfdiags.Diagnostics 237 configured = true 238 if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) { 239 diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want)) 240 } 241 return providers.ConfigureProviderResponse{ 242 Diagnostics: diags, 243 } 244 } 245 246 args := []string{ 247 "test_instance.foo", 248 "bar", 249 } 250 log.Printf("[TRACE] TestImport_remoteState running: terraform import %s %s", args[0], args[1]) 251 if code := c.Run(args); code != 0 { 252 fmt.Println(ui.OutputWriter) 253 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 254 } 255 256 // verify that the local state was unlocked after import 257 if _, err := os.Stat(filepath.Join(td, fmt.Sprintf(".%s.lock.info", statePath))); !os.IsNotExist(err) { 258 t.Fatal("state left locked after import") 259 } 260 261 // Verify that we were called 262 if !configured { 263 t.Fatal("Configure should be called") 264 } 265 266 if !p.ImportResourceStateCalled { 267 t.Fatal("ImportResourceState should be called") 268 } 269 270 testStateOutput(t, statePath, testImportStr) 271 } 272 273 // early failure on import should not leave stale lock 274 func TestImport_initializationErrorShouldUnlock(t *testing.T) { 275 td := t.TempDir() 276 testCopyDir(t, testFixturePath("import-provider-remote-state"), td) 277 defer testChdir(t, td)() 278 279 statePath := "imported.tfstate" 280 281 providerSource, close := newMockProviderSource(t, map[string][]string{ 282 "test": []string{"1.2.3"}, 283 }) 284 defer close() 285 286 // init our backend 287 ui := cli.NewMockUi() 288 view, _ := testView(t) 289 m := Meta{ 290 testingOverrides: metaOverridesForProvider(testProvider()), 291 Ui: ui, 292 View: view, 293 ProviderSource: providerSource, 294 } 295 296 ic := &InitCommand{ 297 Meta: m, 298 } 299 300 // (Using log here rather than t.Log so that these messages interleave with other trace logs) 301 log.Print("[TRACE] TestImport_initializationErrorShouldUnlock running: terraform init") 302 if code := ic.Run([]string{}); code != 0 { 303 t.Fatalf("init failed\n%s", ui.ErrorWriter) 304 } 305 306 // overwrite the config with one including a resource from an invalid provider 307 copy.CopyFile(filepath.Join(testFixturePath("import-provider-invalid"), "main.tf"), filepath.Join(td, "main.tf")) 308 309 p := testProvider() 310 ui = new(cli.MockUi) 311 c := &ImportCommand{ 312 Meta: Meta{ 313 testingOverrides: metaOverridesForProvider(p), 314 Ui: ui, 315 View: view, 316 }, 317 } 318 319 args := []string{ 320 "unknown_instance.baz", 321 "bar", 322 } 323 log.Printf("[TRACE] TestImport_initializationErrorShouldUnlock running: terraform import %s %s", args[0], args[1]) 324 325 // this should fail 326 if code := c.Run(args); code != 1 { 327 fmt.Println(ui.OutputWriter) 328 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 329 } 330 331 // specifically, it should fail due to a missing provider 332 msg := strings.ReplaceAll(ui.ErrorWriter.String(), "\n", " ") 333 if want := `provider registry.terraform.io/hashicorp/unknown: required by this configuration but no version is selected`; !strings.Contains(msg, want) { 334 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 335 } 336 337 // verify that the local state was unlocked after initialization error 338 if _, err := os.Stat(filepath.Join(td, fmt.Sprintf(".%s.lock.info", statePath))); !os.IsNotExist(err) { 339 t.Fatal("state left locked after import") 340 } 341 } 342 343 func TestImport_providerConfigWithVar(t *testing.T) { 344 defer testChdir(t, testFixturePath("import-provider-var"))() 345 346 statePath := testTempFile(t) 347 348 p := testProvider() 349 ui := new(cli.MockUi) 350 view, _ := testView(t) 351 c := &ImportCommand{ 352 Meta: Meta{ 353 testingOverrides: metaOverridesForProvider(p), 354 Ui: ui, 355 View: view, 356 }, 357 } 358 359 p.ImportResourceStateFn = nil 360 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 361 ImportedResources: []providers.ImportedResource{ 362 { 363 TypeName: "test_instance", 364 State: cty.ObjectVal(map[string]cty.Value{ 365 "id": cty.StringVal("yay"), 366 }), 367 }, 368 }, 369 } 370 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 371 Provider: providers.Schema{ 372 Block: &configschema.Block{ 373 Attributes: map[string]*configschema.Attribute{ 374 "foo": {Type: cty.String, Optional: true}, 375 }, 376 }, 377 }, 378 ResourceTypes: map[string]providers.Schema{ 379 "test_instance": { 380 Block: &configschema.Block{ 381 Attributes: map[string]*configschema.Attribute{ 382 "id": {Type: cty.String, Optional: true, Computed: true}, 383 }, 384 }, 385 }, 386 }, 387 } 388 389 configured := false 390 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse { 391 var diags tfdiags.Diagnostics 392 configured = true 393 if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) { 394 diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want)) 395 } 396 return providers.ConfigureProviderResponse{ 397 Diagnostics: diags, 398 } 399 } 400 401 args := []string{ 402 "-state", statePath, 403 "-var", "foo=bar", 404 "test_instance.foo", 405 "bar", 406 } 407 if code := c.Run(args); code != 0 { 408 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 409 } 410 411 // Verify that we were called 412 if !configured { 413 t.Fatal("Configure should be called") 414 } 415 416 if !p.ImportResourceStateCalled { 417 t.Fatal("ImportResourceState should be called") 418 } 419 420 testStateOutput(t, statePath, testImportStr) 421 } 422 423 func TestImport_providerConfigWithDataSource(t *testing.T) { 424 defer testChdir(t, testFixturePath("import-provider-datasource"))() 425 426 statePath := testTempFile(t) 427 428 p := testProvider() 429 ui := new(cli.MockUi) 430 view, _ := testView(t) 431 c := &ImportCommand{ 432 Meta: Meta{ 433 testingOverrides: metaOverridesForProvider(p), 434 Ui: ui, 435 View: view, 436 }, 437 } 438 439 p.ImportResourceStateFn = nil 440 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 441 ImportedResources: []providers.ImportedResource{ 442 { 443 TypeName: "test_instance", 444 State: cty.ObjectVal(map[string]cty.Value{ 445 "id": cty.StringVal("yay"), 446 }), 447 }, 448 }, 449 } 450 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 451 Provider: providers.Schema{ 452 Block: &configschema.Block{ 453 Attributes: map[string]*configschema.Attribute{ 454 "foo": {Type: cty.String, Optional: true}, 455 }, 456 }, 457 }, 458 ResourceTypes: map[string]providers.Schema{ 459 "test_instance": { 460 Block: &configschema.Block{ 461 Attributes: map[string]*configschema.Attribute{ 462 "id": {Type: cty.String, Optional: true, Computed: true}, 463 }, 464 }, 465 }, 466 }, 467 DataSources: map[string]providers.Schema{ 468 "test_data": { 469 Block: &configschema.Block{ 470 Attributes: map[string]*configschema.Attribute{ 471 "foo": {Type: cty.String, Optional: true}, 472 }, 473 }, 474 }, 475 }, 476 } 477 478 args := []string{ 479 "-state", statePath, 480 "test_instance.foo", 481 "bar", 482 } 483 if code := c.Run(args); code != 1 { 484 t.Fatalf("bad, wanted error: %d\n\n%s", code, ui.ErrorWriter.String()) 485 } 486 } 487 488 func TestImport_providerConfigWithVarDefault(t *testing.T) { 489 defer testChdir(t, testFixturePath("import-provider-var-default"))() 490 491 statePath := testTempFile(t) 492 493 p := testProvider() 494 ui := new(cli.MockUi) 495 view, _ := testView(t) 496 c := &ImportCommand{ 497 Meta: Meta{ 498 testingOverrides: metaOverridesForProvider(p), 499 Ui: ui, 500 View: view, 501 }, 502 } 503 504 p.ImportResourceStateFn = nil 505 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 506 ImportedResources: []providers.ImportedResource{ 507 { 508 TypeName: "test_instance", 509 State: cty.ObjectVal(map[string]cty.Value{ 510 "id": cty.StringVal("yay"), 511 }), 512 }, 513 }, 514 } 515 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 516 Provider: providers.Schema{ 517 Block: &configschema.Block{ 518 Attributes: map[string]*configschema.Attribute{ 519 "foo": {Type: cty.String, Optional: true}, 520 }, 521 }, 522 }, 523 ResourceTypes: map[string]providers.Schema{ 524 "test_instance": { 525 Block: &configschema.Block{ 526 Attributes: map[string]*configschema.Attribute{ 527 "id": {Type: cty.String, Optional: true, Computed: true}, 528 }, 529 }, 530 }, 531 }, 532 } 533 534 configured := false 535 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse { 536 var diags tfdiags.Diagnostics 537 configured = true 538 if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) { 539 diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want)) 540 } 541 return providers.ConfigureProviderResponse{ 542 Diagnostics: diags, 543 } 544 } 545 546 args := []string{ 547 "-state", statePath, 548 "test_instance.foo", 549 "bar", 550 } 551 if code := c.Run(args); code != 0 { 552 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 553 } 554 555 // Verify that we were called 556 if !configured { 557 t.Fatal("Configure should be called") 558 } 559 560 if !p.ImportResourceStateCalled { 561 t.Fatal("ImportResourceState should be called") 562 } 563 564 testStateOutput(t, statePath, testImportStr) 565 } 566 567 func TestImport_providerConfigWithVarFile(t *testing.T) { 568 defer testChdir(t, testFixturePath("import-provider-var-file"))() 569 570 statePath := testTempFile(t) 571 572 p := testProvider() 573 ui := new(cli.MockUi) 574 view, _ := testView(t) 575 c := &ImportCommand{ 576 Meta: Meta{ 577 testingOverrides: metaOverridesForProvider(p), 578 Ui: ui, 579 View: view, 580 }, 581 } 582 583 p.ImportResourceStateFn = nil 584 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 585 ImportedResources: []providers.ImportedResource{ 586 { 587 TypeName: "test_instance", 588 State: cty.ObjectVal(map[string]cty.Value{ 589 "id": cty.StringVal("yay"), 590 }), 591 }, 592 }, 593 } 594 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 595 Provider: providers.Schema{ 596 Block: &configschema.Block{ 597 Attributes: map[string]*configschema.Attribute{ 598 "foo": {Type: cty.String, Optional: true}, 599 }, 600 }, 601 }, 602 ResourceTypes: map[string]providers.Schema{ 603 "test_instance": { 604 Block: &configschema.Block{ 605 Attributes: map[string]*configschema.Attribute{ 606 "id": {Type: cty.String, Optional: true, Computed: true}, 607 }, 608 }, 609 }, 610 }, 611 } 612 613 configured := false 614 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) providers.ConfigureProviderResponse { 615 var diags tfdiags.Diagnostics 616 configured = true 617 if got, want := req.Config.GetAttr("foo"), cty.StringVal("bar"); !want.RawEquals(got) { 618 diags = diags.Append(fmt.Errorf("wrong \"foo\" value %#v; want %#v", got, want)) 619 } 620 return providers.ConfigureProviderResponse{ 621 Diagnostics: diags, 622 } 623 } 624 625 args := []string{ 626 "-state", statePath, 627 "-var-file", "blah.tfvars", 628 "test_instance.foo", 629 "bar", 630 } 631 if code := c.Run(args); code != 0 { 632 t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String()) 633 } 634 635 // Verify that we were called 636 if !configured { 637 t.Fatal("Configure should be called") 638 } 639 640 if !p.ImportResourceStateCalled { 641 t.Fatal("ImportResourceState should be called") 642 } 643 644 testStateOutput(t, statePath, testImportStr) 645 } 646 647 func TestImport_emptyConfig(t *testing.T) { 648 defer testChdir(t, testFixturePath("empty"))() 649 650 statePath := testTempFile(t) 651 652 p := testProvider() 653 ui := new(cli.MockUi) 654 view, _ := testView(t) 655 c := &ImportCommand{ 656 Meta: Meta{ 657 testingOverrides: metaOverridesForProvider(p), 658 Ui: ui, 659 View: view, 660 }, 661 } 662 663 args := []string{ 664 "-state", statePath, 665 "test_instance.foo", 666 "bar", 667 } 668 code := c.Run(args) 669 if code != 1 { 670 t.Fatalf("import succeeded; expected failure") 671 } 672 673 msg := ui.ErrorWriter.String() 674 if want := `No Terraform configuration files`; !strings.Contains(msg, want) { 675 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 676 } 677 } 678 679 func TestImport_missingResourceConfig(t *testing.T) { 680 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 681 682 statePath := testTempFile(t) 683 684 p := testProvider() 685 ui := new(cli.MockUi) 686 view, _ := testView(t) 687 c := &ImportCommand{ 688 Meta: Meta{ 689 testingOverrides: metaOverridesForProvider(p), 690 Ui: ui, 691 View: view, 692 }, 693 } 694 695 args := []string{ 696 "-state", statePath, 697 "test_instance.foo", 698 "bar", 699 } 700 code := c.Run(args) 701 if code != 1 { 702 t.Fatalf("import succeeded; expected failure") 703 } 704 705 msg := ui.ErrorWriter.String() 706 if want := `resource address "test_instance.foo" does not exist`; !strings.Contains(msg, want) { 707 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 708 } 709 } 710 711 func TestImport_missingModuleConfig(t *testing.T) { 712 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 713 714 statePath := testTempFile(t) 715 716 p := testProvider() 717 ui := new(cli.MockUi) 718 view, _ := testView(t) 719 c := &ImportCommand{ 720 Meta: Meta{ 721 testingOverrides: metaOverridesForProvider(p), 722 Ui: ui, 723 View: view, 724 }, 725 } 726 727 args := []string{ 728 "-state", statePath, 729 "module.baz.test_instance.foo", 730 "bar", 731 } 732 code := c.Run(args) 733 if code != 1 { 734 t.Fatalf("import succeeded; expected failure") 735 } 736 737 msg := ui.ErrorWriter.String() 738 if want := `module.baz is not defined in the configuration`; !strings.Contains(msg, want) { 739 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 740 } 741 } 742 743 func TestImportModuleVarFile(t *testing.T) { 744 td := t.TempDir() 745 testCopyDir(t, testFixturePath("import-module-var-file"), td) 746 defer testChdir(t, td)() 747 748 statePath := testTempFile(t) 749 750 p := testProvider() 751 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 752 ResourceTypes: map[string]providers.Schema{ 753 "test_instance": { 754 Block: &configschema.Block{ 755 Attributes: map[string]*configschema.Attribute{ 756 "foo": {Type: cty.String, Optional: true}, 757 }, 758 }, 759 }, 760 }, 761 } 762 763 providerSource, close := newMockProviderSource(t, map[string][]string{ 764 "test": []string{"1.2.3"}, 765 }) 766 defer close() 767 768 // init to install the module 769 ui := new(cli.MockUi) 770 view, _ := testView(t) 771 m := Meta{ 772 testingOverrides: metaOverridesForProvider(testProvider()), 773 Ui: ui, 774 View: view, 775 ProviderSource: providerSource, 776 } 777 778 ic := &InitCommand{ 779 Meta: m, 780 } 781 if code := ic.Run([]string{}); code != 0 { 782 t.Fatalf("init failed\n%s", ui.ErrorWriter) 783 } 784 785 // import 786 ui = new(cli.MockUi) 787 c := &ImportCommand{ 788 Meta: Meta{ 789 testingOverrides: metaOverridesForProvider(p), 790 Ui: ui, 791 View: view, 792 }, 793 } 794 args := []string{ 795 "-state", statePath, 796 "module.child.test_instance.foo", 797 "bar", 798 } 799 code := c.Run(args) 800 if code != 0 { 801 t.Fatalf("import failed; expected success") 802 } 803 } 804 805 // This test covers an edge case where a module with a complex input variable 806 // of nested objects has an invalid default which is overridden by the calling 807 // context, and is used in locals. If we don't evaluate module call variables 808 // for the import walk, this results in an error. 809 // 810 // The specific example has a variable "foo" which is a nested object: 811 // 812 // foo = { bar = { baz = true } } 813 // 814 // This is used as foo = var.foo in the call to the child module, which then 815 // uses the traversal foo.bar.baz in a local. A default value in the child 816 // module of {} causes this local evaluation to error, breaking import. 817 func TestImportModuleInputVariableEvaluation(t *testing.T) { 818 td := t.TempDir() 819 testCopyDir(t, testFixturePath("import-module-input-variable"), td) 820 defer testChdir(t, td)() 821 822 statePath := testTempFile(t) 823 824 p := testProvider() 825 p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{ 826 ResourceTypes: map[string]providers.Schema{ 827 "test_instance": { 828 Block: &configschema.Block{ 829 Attributes: map[string]*configschema.Attribute{ 830 "foo": {Type: cty.String, Optional: true}, 831 }, 832 }, 833 }, 834 }, 835 } 836 837 providerSource, close := newMockProviderSource(t, map[string][]string{ 838 "test": {"1.2.3"}, 839 }) 840 defer close() 841 842 // init to install the module 843 ui := new(cli.MockUi) 844 view, _ := testView(t) 845 m := Meta{ 846 testingOverrides: metaOverridesForProvider(testProvider()), 847 Ui: ui, 848 View: view, 849 ProviderSource: providerSource, 850 } 851 852 ic := &InitCommand{ 853 Meta: m, 854 } 855 if code := ic.Run([]string{}); code != 0 { 856 t.Fatalf("init failed\n%s", ui.ErrorWriter) 857 } 858 859 // import 860 ui = new(cli.MockUi) 861 c := &ImportCommand{ 862 Meta: Meta{ 863 testingOverrides: metaOverridesForProvider(p), 864 Ui: ui, 865 View: view, 866 }, 867 } 868 args := []string{ 869 "-state", statePath, 870 "module.child.test_instance.foo", 871 "bar", 872 } 873 code := c.Run(args) 874 if code != 0 { 875 t.Fatalf("import failed; expected success") 876 } 877 } 878 879 func TestImport_dataResource(t *testing.T) { 880 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 881 882 statePath := testTempFile(t) 883 884 p := testProvider() 885 ui := new(cli.MockUi) 886 view, _ := testView(t) 887 c := &ImportCommand{ 888 Meta: Meta{ 889 testingOverrides: metaOverridesForProvider(p), 890 Ui: ui, 891 View: view, 892 }, 893 } 894 895 args := []string{ 896 "-state", statePath, 897 "data.test_data_source.foo", 898 "bar", 899 } 900 code := c.Run(args) 901 if code != 1 { 902 t.Fatalf("import succeeded; expected failure") 903 } 904 905 msg := ui.ErrorWriter.String() 906 if want := `A managed resource address is required`; !strings.Contains(msg, want) { 907 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 908 } 909 } 910 911 func TestImport_invalidResourceAddr(t *testing.T) { 912 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 913 914 statePath := testTempFile(t) 915 916 p := testProvider() 917 ui := new(cli.MockUi) 918 view, _ := testView(t) 919 c := &ImportCommand{ 920 Meta: Meta{ 921 testingOverrides: metaOverridesForProvider(p), 922 Ui: ui, 923 View: view, 924 }, 925 } 926 927 args := []string{ 928 "-state", statePath, 929 "bananas", 930 "bar", 931 } 932 code := c.Run(args) 933 if code != 1 { 934 t.Fatalf("import succeeded; expected failure") 935 } 936 937 msg := ui.ErrorWriter.String() 938 if want := `Error: Invalid address`; !strings.Contains(msg, want) { 939 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 940 } 941 } 942 943 func TestImport_targetIsModule(t *testing.T) { 944 defer testChdir(t, testFixturePath("import-missing-resource-config"))() 945 946 statePath := testTempFile(t) 947 948 p := testProvider() 949 ui := new(cli.MockUi) 950 view, _ := testView(t) 951 c := &ImportCommand{ 952 Meta: Meta{ 953 testingOverrides: metaOverridesForProvider(p), 954 Ui: ui, 955 View: view, 956 }, 957 } 958 959 args := []string{ 960 "-state", statePath, 961 "module.foo", 962 "bar", 963 } 964 code := c.Run(args) 965 if code != 1 { 966 t.Fatalf("import succeeded; expected failure") 967 } 968 969 msg := ui.ErrorWriter.String() 970 if want := `Error: Invalid address`; !strings.Contains(msg, want) { 971 t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg) 972 } 973 } 974 975 const testImportStr = ` 976 test_instance.foo: 977 ID = yay 978 provider = provider["registry.terraform.io/hashicorp/test"] 979 `