github.com/opentofu/opentofu@v1.7.1/internal/tofu/context_import_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package tofu 7 8 import ( 9 "errors" 10 "strings" 11 "testing" 12 13 "github.com/google/go-cmp/cmp" 14 "github.com/zclconf/go-cty/cty" 15 16 "github.com/opentofu/opentofu/internal/addrs" 17 "github.com/opentofu/opentofu/internal/configs/configschema" 18 "github.com/opentofu/opentofu/internal/providers" 19 "github.com/opentofu/opentofu/internal/states" 20 ) 21 22 func TestContextImport_basic(t *testing.T) { 23 p := testProvider("aws") 24 m := testModule(t, "import-provider") 25 ctx := testContext2(t, &ContextOpts{ 26 Providers: map[addrs.Provider]providers.Factory{ 27 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 28 }, 29 }) 30 31 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 32 ImportedResources: []providers.ImportedResource{ 33 { 34 TypeName: "aws_instance", 35 State: cty.ObjectVal(map[string]cty.Value{ 36 "id": cty.StringVal("foo"), 37 }), 38 }, 39 }, 40 } 41 42 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 43 Targets: []*ImportTarget{ 44 { 45 CommandLineImportTarget: &CommandLineImportTarget{ 46 Addr: addrs.RootModuleInstance.ResourceInstance( 47 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 48 ), 49 ID: "bar", 50 }, 51 }, 52 }, 53 }) 54 if diags.HasErrors() { 55 t.Fatalf("unexpected errors: %s", diags.Err()) 56 } 57 actual := strings.TrimSpace(state.String()) 58 expected := strings.TrimSpace(testImportStr) 59 if actual != expected { 60 t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", actual, expected) 61 } 62 } 63 64 // import 1 of count instances in the configuration 65 func TestContextImport_countIndex(t *testing.T) { 66 p := testProvider("aws") 67 m := testModuleInline(t, map[string]string{ 68 "main.tf": ` 69 provider "aws" { 70 foo = "bar" 71 } 72 73 resource "aws_instance" "foo" { 74 count = 2 75 } 76 `}) 77 78 ctx := testContext2(t, &ContextOpts{ 79 Providers: map[addrs.Provider]providers.Factory{ 80 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 81 }, 82 }) 83 84 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 85 ImportedResources: []providers.ImportedResource{ 86 { 87 TypeName: "aws_instance", 88 State: cty.ObjectVal(map[string]cty.Value{ 89 "id": cty.StringVal("foo"), 90 }), 91 }, 92 }, 93 } 94 95 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 96 Targets: []*ImportTarget{ 97 { 98 CommandLineImportTarget: &CommandLineImportTarget{ 99 Addr: addrs.RootModuleInstance.ResourceInstance( 100 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(0), 101 ), 102 ID: "bar", 103 }, 104 }, 105 }, 106 }) 107 if diags.HasErrors() { 108 t.Fatalf("unexpected errors: %s", diags.Err()) 109 } 110 111 actual := strings.TrimSpace(state.String()) 112 expected := strings.TrimSpace(testImportCountIndexStr) 113 if actual != expected { 114 t.Fatalf("bad: \n%s", actual) 115 } 116 } 117 118 func TestContextImport_importResourceWithSensitiveDataSource(t *testing.T) { 119 p := testProvider("aws") 120 m := testModuleInline(t, map[string]string{ 121 "main.tf": ` 122 provider "aws" { 123 foo = "bar" 124 } 125 126 data "aws_sensitive_data_source" "source" { 127 id = "source_id" 128 } 129 130 resource "aws_instance" "foo" { 131 id = "bar" 132 var = data.aws_sensitive_data_source.source.value 133 } 134 `}) 135 136 ctx := testContext2(t, &ContextOpts{ 137 Providers: map[addrs.Provider]providers.Factory{ 138 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 139 }, 140 }) 141 142 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 143 ImportedResources: []providers.ImportedResource{ 144 { 145 TypeName: "aws_instance", 146 State: cty.ObjectVal(map[string]cty.Value{ 147 "id": cty.StringVal("bar"), 148 }), 149 }, 150 }, 151 } 152 153 p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ 154 State: cty.ObjectVal(map[string]cty.Value{ 155 "id": cty.StringVal("source_id"), 156 "value": cty.StringVal("pass"), 157 }), 158 } 159 160 p.ReadResourceResponse = &providers.ReadResourceResponse{ 161 NewState: cty.ObjectVal(map[string]cty.Value{ 162 "id": cty.StringVal("bar"), 163 "var": cty.StringVal("pass"), 164 }), 165 } 166 167 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 168 Targets: []*ImportTarget{ 169 { 170 CommandLineImportTarget: &CommandLineImportTarget{ 171 Addr: addrs.RootModuleInstance.ResourceInstance( 172 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 173 ), 174 ID: "bar", 175 }, 176 }, 177 }, 178 }) 179 if diags.HasErrors() { 180 t.Fatalf("unexpected errors: %s", diags.Err()) 181 } 182 183 actual := strings.TrimSpace(state.String()) 184 expected := strings.TrimSpace(testImportResourceWithSensitiveDataSource) 185 if actual != expected { 186 t.Fatalf("bad: \n%s", actual) 187 } 188 189 obj := state.ResourceInstance(mustResourceInstanceAddr("aws_instance.foo")) 190 if len(obj.Current.AttrSensitivePaths) != 1 { 191 t.Fatalf("Expected 1 sensitive mark for aws_instance.foo, got %#v\n", obj.Current.AttrSensitivePaths) 192 } 193 } 194 195 func TestContextImport_collision(t *testing.T) { 196 p := testProvider("aws") 197 m := testModule(t, "import-provider") 198 ctx := testContext2(t, &ContextOpts{ 199 Providers: map[addrs.Provider]providers.Factory{ 200 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 201 }, 202 }) 203 204 state := states.BuildState(func(s *states.SyncState) { 205 s.SetResourceInstanceCurrent( 206 addrs.Resource{ 207 Mode: addrs.ManagedResourceMode, 208 Type: "aws_instance", 209 Name: "foo", 210 }.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance), 211 &states.ResourceInstanceObjectSrc{ 212 AttrsFlat: map[string]string{ 213 "id": "bar", 214 }, 215 Status: states.ObjectReady, 216 }, 217 addrs.AbsProviderConfig{ 218 Provider: addrs.NewDefaultProvider("aws"), 219 Module: addrs.RootModule, 220 }, 221 ) 222 }) 223 224 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 225 ImportedResources: []providers.ImportedResource{ 226 { 227 TypeName: "aws_instance", 228 State: cty.ObjectVal(map[string]cty.Value{ 229 "id": cty.StringVal("foo"), 230 }), 231 }, 232 }, 233 } 234 235 state, diags := ctx.Import(m, state, &ImportOpts{ 236 Targets: []*ImportTarget{ 237 { 238 CommandLineImportTarget: &CommandLineImportTarget{ 239 Addr: addrs.RootModuleInstance.ResourceInstance( 240 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 241 ), 242 ID: "bar", 243 }, 244 }, 245 }, 246 }) 247 if !diags.HasErrors() { 248 t.Fatalf("succeeded; want an error indicating that the resource already exists in state") 249 } 250 251 actual := strings.TrimSpace(state.String()) 252 expected := `aws_instance.foo: 253 ID = bar 254 provider = provider["registry.opentofu.org/hashicorp/aws"]` 255 256 if actual != expected { 257 t.Fatalf("bad: \n%s", actual) 258 } 259 } 260 261 func TestContextImport_missingType(t *testing.T) { 262 p := testProvider("aws") 263 m := testModule(t, "import-provider") 264 265 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 266 ImportedResources: []providers.ImportedResource{ 267 { 268 State: cty.ObjectVal(map[string]cty.Value{ 269 "id": cty.StringVal("foo"), 270 }), 271 }, 272 }, 273 } 274 275 ctx := testContext2(t, &ContextOpts{ 276 Providers: map[addrs.Provider]providers.Factory{ 277 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 278 }, 279 }) 280 281 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 282 Targets: []*ImportTarget{ 283 { 284 CommandLineImportTarget: &CommandLineImportTarget{ 285 Addr: addrs.RootModuleInstance.ResourceInstance( 286 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 287 ), 288 ID: "bar", 289 }, 290 }, 291 }, 292 }) 293 if !diags.HasErrors() { 294 t.Fatal("should error") 295 } 296 297 actual := strings.TrimSpace(state.String()) 298 expected := "<no state>" 299 if actual != expected { 300 t.Fatalf("bad: \n%s", actual) 301 } 302 } 303 304 func TestContextImport_moduleProvider(t *testing.T) { 305 p := testProvider("aws") 306 307 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 308 ImportedResources: []providers.ImportedResource{ 309 { 310 TypeName: "aws_instance", 311 State: cty.ObjectVal(map[string]cty.Value{ 312 "id": cty.StringVal("foo"), 313 }), 314 }, 315 }, 316 } 317 318 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { 319 foo := req.Config.GetAttr("foo").AsString() 320 if foo != "bar" { 321 resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar")) 322 } 323 324 return 325 } 326 327 m := testModule(t, "import-provider") 328 ctx := testContext2(t, &ContextOpts{ 329 Providers: map[addrs.Provider]providers.Factory{ 330 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 331 }, 332 }) 333 334 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 335 Targets: []*ImportTarget{ 336 { 337 CommandLineImportTarget: &CommandLineImportTarget{ 338 Addr: addrs.RootModuleInstance.ResourceInstance( 339 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 340 ), 341 ID: "bar", 342 }, 343 }, 344 }, 345 }) 346 if diags.HasErrors() { 347 t.Fatalf("unexpected errors: %s", diags.Err()) 348 } 349 350 if !p.ConfigureProviderCalled { 351 t.Fatal("didn't configure provider") 352 } 353 354 actual := strings.TrimSpace(state.String()) 355 expected := strings.TrimSpace(testImportStr) 356 if actual != expected { 357 t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual) 358 } 359 } 360 361 // Importing into a module requires a provider config in that module. 362 func TestContextImport_providerModule(t *testing.T) { 363 p := testProvider("aws") 364 m := testModule(t, "import-module") 365 ctx := testContext2(t, &ContextOpts{ 366 Providers: map[addrs.Provider]providers.Factory{ 367 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 368 }, 369 }) 370 371 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 372 ImportedResources: []providers.ImportedResource{ 373 { 374 TypeName: "aws_instance", 375 State: cty.ObjectVal(map[string]cty.Value{ 376 "id": cty.StringVal("foo"), 377 }), 378 }, 379 }, 380 } 381 382 p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) { 383 foo := req.Config.GetAttr("foo").AsString() 384 if foo != "bar" { 385 resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar")) 386 } 387 388 return 389 } 390 391 _, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 392 Targets: []*ImportTarget{ 393 { 394 CommandLineImportTarget: &CommandLineImportTarget{ 395 Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).ResourceInstance( 396 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 397 ), 398 ID: "bar", 399 }, 400 }, 401 }, 402 }) 403 if diags.HasErrors() { 404 t.Fatalf("unexpected errors: %s", diags.Err()) 405 } 406 407 if !p.ConfigureProviderCalled { 408 t.Fatal("didn't configure provider") 409 } 410 } 411 412 // Test that import will interpolate provider configuration and use 413 // that configuration for import. 414 func TestContextImport_providerConfig(t *testing.T) { 415 testCases := map[string]struct { 416 module string 417 value string 418 }{ 419 "variables": { 420 module: "import-provider-vars", 421 value: "bar", 422 }, 423 "locals": { 424 module: "import-provider-locals", 425 value: "baz-bar", 426 }, 427 } 428 for name, test := range testCases { 429 t.Run(name, func(t *testing.T) { 430 p := testProvider("aws") 431 m := testModule(t, test.module) 432 ctx := testContext2(t, &ContextOpts{ 433 Providers: map[addrs.Provider]providers.Factory{ 434 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 435 }, 436 }) 437 438 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 439 ImportedResources: []providers.ImportedResource{ 440 { 441 TypeName: "aws_instance", 442 State: cty.ObjectVal(map[string]cty.Value{ 443 "id": cty.StringVal("foo"), 444 }), 445 }, 446 }, 447 } 448 449 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 450 Targets: []*ImportTarget{ 451 { 452 CommandLineImportTarget: &CommandLineImportTarget{ 453 Addr: addrs.RootModuleInstance.ResourceInstance( 454 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 455 ), 456 ID: "bar", 457 }, 458 }, 459 }, 460 SetVariables: InputValues{ 461 "foo": &InputValue{ 462 Value: cty.StringVal("bar"), 463 SourceType: ValueFromCaller, 464 }, 465 }, 466 }) 467 if diags.HasErrors() { 468 t.Fatalf("unexpected errors: %s", diags.Err()) 469 } 470 471 if !p.ConfigureProviderCalled { 472 t.Fatal("didn't configure provider") 473 } 474 475 if foo := p.ConfigureProviderRequest.Config.GetAttr("foo").AsString(); foo != test.value { 476 t.Fatalf("bad value %#v; want %#v", foo, test.value) 477 } 478 479 actual := strings.TrimSpace(state.String()) 480 expected := strings.TrimSpace(testImportStr) 481 if actual != expected { 482 t.Fatalf("bad: \n%s", actual) 483 } 484 }) 485 } 486 } 487 488 // Test that provider configs can't reference resources. 489 func TestContextImport_providerConfigResources(t *testing.T) { 490 p := testProvider("aws") 491 pTest := testProvider("test") 492 m := testModule(t, "import-provider-resources") 493 ctx := testContext2(t, &ContextOpts{ 494 Providers: map[addrs.Provider]providers.Factory{ 495 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 496 addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest), 497 }, 498 }) 499 500 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 501 ImportedResources: []providers.ImportedResource{ 502 { 503 TypeName: "aws_instance", 504 State: cty.ObjectVal(map[string]cty.Value{ 505 "id": cty.StringVal("foo"), 506 }), 507 }, 508 }, 509 } 510 511 _, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 512 Targets: []*ImportTarget{ 513 { 514 CommandLineImportTarget: &CommandLineImportTarget{ 515 Addr: addrs.RootModuleInstance.ResourceInstance( 516 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 517 ), 518 ID: "bar", 519 }, 520 }, 521 }, 522 }) 523 if !diags.HasErrors() { 524 t.Fatal("should error") 525 } 526 if got, want := diags.Err().Error(), `The configuration for provider["registry.opentofu.org/hashicorp/aws"] depends on values that cannot be determined until apply.`; !strings.Contains(got, want) { 527 t.Errorf("wrong error\n got: %s\nwant: %s", got, want) 528 } 529 } 530 531 func TestContextImport_refresh(t *testing.T) { 532 p := testProvider("aws") 533 m := testModuleInline(t, map[string]string{ 534 "main.tf": ` 535 provider "aws" { 536 foo = "bar" 537 } 538 539 resource "aws_instance" "foo" { 540 } 541 542 543 // we are only importing aws_instance.foo, so these resources will be unknown 544 resource "aws_instance" "bar" { 545 } 546 data "aws_data_source" "bar" { 547 foo = aws_instance.bar.id 548 } 549 `}) 550 551 ctx := testContext2(t, &ContextOpts{ 552 Providers: map[addrs.Provider]providers.Factory{ 553 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 554 }, 555 }) 556 557 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 558 ImportedResources: []providers.ImportedResource{ 559 { 560 TypeName: "aws_instance", 561 State: cty.ObjectVal(map[string]cty.Value{ 562 "id": cty.StringVal("foo"), 563 }), 564 }, 565 }, 566 } 567 568 p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{ 569 State: cty.ObjectVal(map[string]cty.Value{ 570 "id": cty.StringVal("id"), 571 "foo": cty.UnknownVal(cty.String), 572 }), 573 } 574 575 p.ReadResourceFn = nil 576 577 p.ReadResourceResponse = &providers.ReadResourceResponse{ 578 NewState: cty.ObjectVal(map[string]cty.Value{ 579 "id": cty.StringVal("foo"), 580 "foo": cty.StringVal("bar"), 581 }), 582 } 583 584 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 585 Targets: []*ImportTarget{ 586 { 587 CommandLineImportTarget: &CommandLineImportTarget{ 588 Addr: addrs.RootModuleInstance.ResourceInstance( 589 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 590 ), 591 ID: "bar", 592 }, 593 }, 594 }, 595 }) 596 if diags.HasErrors() { 597 t.Fatalf("unexpected errors: %s", diags.Err()) 598 } 599 600 if d := state.ResourceInstance(mustResourceInstanceAddr("data.aws_data_source.bar")); d != nil { 601 t.Errorf("data.aws_data_source.bar has a status of ObjectPlanned and should not be in the state\ngot:%#v\n", d.Current) 602 } 603 604 actual := strings.TrimSpace(state.String()) 605 expected := strings.TrimSpace(testImportRefreshStr) 606 if actual != expected { 607 t.Fatalf("bad: \n%s", actual) 608 } 609 } 610 611 func TestContextImport_refreshNil(t *testing.T) { 612 p := testProvider("aws") 613 m := testModule(t, "import-provider") 614 ctx := testContext2(t, &ContextOpts{ 615 Providers: map[addrs.Provider]providers.Factory{ 616 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 617 }, 618 }) 619 620 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 621 ImportedResources: []providers.ImportedResource{ 622 { 623 TypeName: "aws_instance", 624 State: cty.ObjectVal(map[string]cty.Value{ 625 "id": cty.StringVal("foo"), 626 }), 627 }, 628 }, 629 } 630 631 p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse { 632 return providers.ReadResourceResponse{ 633 NewState: cty.NullVal(cty.DynamicPseudoType), 634 } 635 } 636 637 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 638 Targets: []*ImportTarget{ 639 { 640 CommandLineImportTarget: &CommandLineImportTarget{ 641 Addr: addrs.RootModuleInstance.ResourceInstance( 642 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 643 ), 644 ID: "bar", 645 }, 646 }, 647 }, 648 }) 649 if !diags.HasErrors() { 650 t.Fatal("should error") 651 } 652 653 actual := strings.TrimSpace(state.String()) 654 expected := "<no state>" 655 if actual != expected { 656 t.Fatalf("bad: \n%s", actual) 657 } 658 } 659 660 func TestContextImport_module(t *testing.T) { 661 p := testProvider("aws") 662 m := testModule(t, "import-module") 663 ctx := testContext2(t, &ContextOpts{ 664 Providers: map[addrs.Provider]providers.Factory{ 665 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 666 }, 667 }) 668 669 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 670 ImportedResources: []providers.ImportedResource{ 671 { 672 TypeName: "aws_instance", 673 State: cty.ObjectVal(map[string]cty.Value{ 674 "id": cty.StringVal("foo"), 675 }), 676 }, 677 }, 678 } 679 680 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 681 Targets: []*ImportTarget{ 682 { 683 CommandLineImportTarget: &CommandLineImportTarget{ 684 Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).ResourceInstance( 685 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 686 ), 687 ID: "bar", 688 }, 689 }, 690 }, 691 }) 692 if diags.HasErrors() { 693 t.Fatalf("unexpected errors: %s", diags.Err()) 694 } 695 696 actual := strings.TrimSpace(state.String()) 697 expected := strings.TrimSpace(testImportModuleStr) 698 if actual != expected { 699 t.Fatalf("bad: \n%s", actual) 700 } 701 } 702 703 func TestContextImport_moduleDepth2(t *testing.T) { 704 p := testProvider("aws") 705 m := testModule(t, "import-module") 706 ctx := testContext2(t, &ContextOpts{ 707 Providers: map[addrs.Provider]providers.Factory{ 708 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 709 }, 710 }) 711 712 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 713 ImportedResources: []providers.ImportedResource{ 714 { 715 TypeName: "aws_instance", 716 State: cty.ObjectVal(map[string]cty.Value{ 717 "id": cty.StringVal("foo"), 718 }), 719 }, 720 }, 721 } 722 723 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 724 Targets: []*ImportTarget{ 725 { 726 CommandLineImportTarget: &CommandLineImportTarget{ 727 Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).Child("nested", addrs.NoKey).ResourceInstance( 728 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 729 ), 730 ID: "baz", 731 }, 732 }, 733 }, 734 }) 735 if diags.HasErrors() { 736 t.Fatalf("unexpected errors: %s", diags.Err()) 737 } 738 739 actual := strings.TrimSpace(state.String()) 740 expected := strings.TrimSpace(testImportModuleDepth2Str) 741 if actual != expected { 742 t.Fatalf("bad: \n%s", actual) 743 } 744 } 745 746 func TestContextImport_moduleDiff(t *testing.T) { 747 p := testProvider("aws") 748 m := testModule(t, "import-module") 749 ctx := testContext2(t, &ContextOpts{ 750 Providers: map[addrs.Provider]providers.Factory{ 751 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 752 }, 753 }) 754 755 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 756 ImportedResources: []providers.ImportedResource{ 757 { 758 TypeName: "aws_instance", 759 State: cty.ObjectVal(map[string]cty.Value{ 760 "id": cty.StringVal("foo"), 761 }), 762 }, 763 }, 764 } 765 766 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 767 Targets: []*ImportTarget{ 768 { 769 CommandLineImportTarget: &CommandLineImportTarget{ 770 Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).ResourceInstance( 771 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 772 ), 773 ID: "baz", 774 }, 775 }, 776 }, 777 }) 778 if diags.HasErrors() { 779 t.Fatalf("unexpected errors: %s", diags.Err()) 780 } 781 782 actual := strings.TrimSpace(state.String()) 783 expected := strings.TrimSpace(testImportModuleStr) 784 if actual != expected { 785 t.Fatalf("\nexpected: %q\ngot: %q\n", expected, actual) 786 } 787 } 788 789 func TestContextImport_multiState(t *testing.T) { 790 p := testProvider("aws") 791 m := testModule(t, "import-provider") 792 793 p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ 794 Provider: &configschema.Block{ 795 Attributes: map[string]*configschema.Attribute{ 796 "foo": {Type: cty.String, Optional: true}, 797 }, 798 }, 799 ResourceTypes: map[string]*configschema.Block{ 800 "aws_instance": { 801 Attributes: map[string]*configschema.Attribute{ 802 "id": {Type: cty.String, Computed: true}, 803 }, 804 }, 805 "aws_instance_thing": { 806 Attributes: map[string]*configschema.Attribute{ 807 "id": {Type: cty.String, Computed: true}, 808 }, 809 }, 810 }, 811 }) 812 813 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 814 ImportedResources: []providers.ImportedResource{ 815 { 816 TypeName: "aws_instance", 817 State: cty.ObjectVal(map[string]cty.Value{ 818 "id": cty.StringVal("foo"), 819 }), 820 }, 821 { 822 TypeName: "aws_instance_thing", 823 State: cty.ObjectVal(map[string]cty.Value{ 824 "id": cty.StringVal("bar"), 825 }), 826 }, 827 }, 828 } 829 830 ctx := testContext2(t, &ContextOpts{ 831 Providers: map[addrs.Provider]providers.Factory{ 832 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 833 }, 834 }) 835 836 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 837 Targets: []*ImportTarget{ 838 { 839 CommandLineImportTarget: &CommandLineImportTarget{ 840 Addr: addrs.RootModuleInstance.ResourceInstance( 841 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 842 ), 843 ID: "bar", 844 }, 845 }, 846 }, 847 }) 848 if diags.HasErrors() { 849 t.Fatalf("unexpected errors: %s", diags.Err()) 850 } 851 852 actual := strings.TrimSpace(state.String()) 853 expected := strings.TrimSpace(testImportMultiStr) 854 if actual != expected { 855 t.Fatalf("bad: \n%s", actual) 856 } 857 } 858 859 func TestContextImport_multiStateSame(t *testing.T) { 860 p := testProvider("aws") 861 m := testModule(t, "import-provider") 862 863 p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ 864 Provider: &configschema.Block{ 865 Attributes: map[string]*configschema.Attribute{ 866 "foo": {Type: cty.String, Optional: true}, 867 }, 868 }, 869 ResourceTypes: map[string]*configschema.Block{ 870 "aws_instance": { 871 Attributes: map[string]*configschema.Attribute{ 872 "id": {Type: cty.String, Computed: true}, 873 }, 874 }, 875 "aws_instance_thing": { 876 Attributes: map[string]*configschema.Attribute{ 877 "id": {Type: cty.String, Computed: true}, 878 }, 879 }, 880 }, 881 }) 882 883 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 884 ImportedResources: []providers.ImportedResource{ 885 { 886 TypeName: "aws_instance", 887 State: cty.ObjectVal(map[string]cty.Value{ 888 "id": cty.StringVal("foo"), 889 }), 890 }, 891 { 892 TypeName: "aws_instance_thing", 893 State: cty.ObjectVal(map[string]cty.Value{ 894 "id": cty.StringVal("bar"), 895 }), 896 }, 897 { 898 TypeName: "aws_instance_thing", 899 State: cty.ObjectVal(map[string]cty.Value{ 900 "id": cty.StringVal("qux"), 901 }), 902 }, 903 }, 904 } 905 906 ctx := testContext2(t, &ContextOpts{ 907 Providers: map[addrs.Provider]providers.Factory{ 908 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 909 }, 910 }) 911 912 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 913 Targets: []*ImportTarget{ 914 { 915 CommandLineImportTarget: &CommandLineImportTarget{ 916 Addr: addrs.RootModuleInstance.ResourceInstance( 917 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 918 ), 919 ID: "bar", 920 }, 921 }, 922 }, 923 }) 924 if diags.HasErrors() { 925 t.Fatalf("unexpected errors: %s", diags.Err()) 926 } 927 928 actual := strings.TrimSpace(state.String()) 929 expected := strings.TrimSpace(testImportMultiSameStr) 930 if actual != expected { 931 t.Fatalf("bad: \n%s", actual) 932 } 933 } 934 935 func TestContextImport_nestedModuleImport(t *testing.T) { 936 p := testProvider("aws") 937 m := testModuleInline(t, map[string]string{ 938 "main.tf": ` 939 locals { 940 xs = toset(["foo"]) 941 } 942 943 module "a" { 944 for_each = local.xs 945 source = "./a" 946 } 947 948 module "b" { 949 for_each = local.xs 950 source = "./b" 951 y = module.a[each.key].y 952 } 953 954 resource "test_resource" "test" { 955 } 956 `, 957 "a/main.tf": ` 958 output "y" { 959 value = "bar" 960 } 961 `, 962 "b/main.tf": ` 963 variable "y" { 964 type = string 965 } 966 967 resource "test_resource" "unused" { 968 value = var.y 969 // missing required, but should not error 970 } 971 `, 972 }) 973 974 p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ 975 Provider: &configschema.Block{ 976 Attributes: map[string]*configschema.Attribute{ 977 "foo": {Type: cty.String, Optional: true}, 978 }, 979 }, 980 ResourceTypes: map[string]*configschema.Block{ 981 "test_resource": { 982 Attributes: map[string]*configschema.Attribute{ 983 "id": {Type: cty.String, Computed: true}, 984 "required": {Type: cty.String, Required: true}, 985 }, 986 }, 987 }, 988 }) 989 990 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 991 ImportedResources: []providers.ImportedResource{ 992 { 993 TypeName: "test_resource", 994 State: cty.ObjectVal(map[string]cty.Value{ 995 "id": cty.StringVal("test"), 996 "required": cty.StringVal("value"), 997 }), 998 }, 999 }, 1000 } 1001 1002 ctx := testContext2(t, &ContextOpts{ 1003 Providers: map[addrs.Provider]providers.Factory{ 1004 addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), 1005 }, 1006 }) 1007 1008 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 1009 Targets: []*ImportTarget{ 1010 { 1011 CommandLineImportTarget: &CommandLineImportTarget{ 1012 Addr: addrs.RootModuleInstance.ResourceInstance( 1013 addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey, 1014 ), 1015 ID: "test", 1016 }, 1017 }, 1018 }, 1019 }) 1020 if diags.HasErrors() { 1021 t.Fatal(diags.ErrWithWarnings()) 1022 } 1023 1024 ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test")) 1025 expected := `{"id":"test","required":"value"}` 1026 if ri == nil || ri.Current == nil { 1027 t.Fatal("no state is recorded for resource instance test_resource.test") 1028 } 1029 if string(ri.Current.AttrsJSON) != expected { 1030 t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON) 1031 } 1032 } 1033 1034 // New resources in the config during import won't exist for evaluation 1035 // purposes (until import is upgraded to using a complete plan). This means 1036 // that references to them are unknown, but in the case of single instances, we 1037 // can at least know the type of unknown value. 1038 func TestContextImport_newResourceUnknown(t *testing.T) { 1039 p := testProvider("aws") 1040 m := testModuleInline(t, map[string]string{ 1041 "main.tf": ` 1042 resource "test_resource" "one" { 1043 } 1044 1045 resource "test_resource" "two" { 1046 count = length(flatten([test_resource.one.id])) 1047 } 1048 1049 resource "test_resource" "test" { 1050 } 1051 `}) 1052 1053 p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{ 1054 ResourceTypes: map[string]*configschema.Block{ 1055 "test_resource": { 1056 Attributes: map[string]*configschema.Attribute{ 1057 "id": {Type: cty.String, Computed: true}, 1058 }, 1059 }, 1060 }, 1061 }) 1062 1063 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 1064 ImportedResources: []providers.ImportedResource{ 1065 { 1066 TypeName: "test_resource", 1067 State: cty.ObjectVal(map[string]cty.Value{ 1068 "id": cty.StringVal("test"), 1069 }), 1070 }, 1071 }, 1072 } 1073 1074 ctx := testContext2(t, &ContextOpts{ 1075 Providers: map[addrs.Provider]providers.Factory{ 1076 addrs.NewDefaultProvider("test"): testProviderFuncFixed(p), 1077 }, 1078 }) 1079 1080 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 1081 Targets: []*ImportTarget{ 1082 { 1083 CommandLineImportTarget: &CommandLineImportTarget{ 1084 Addr: addrs.RootModuleInstance.ResourceInstance( 1085 addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey, 1086 ), 1087 ID: "test", 1088 }, 1089 }, 1090 }, 1091 }) 1092 if diags.HasErrors() { 1093 t.Fatal(diags.ErrWithWarnings()) 1094 } 1095 1096 ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test")) 1097 expected := `{"id":"test"}` 1098 if ri == nil || ri.Current == nil { 1099 t.Fatal("no state is recorded for resource instance test_resource.test") 1100 } 1101 if string(ri.Current.AttrsJSON) != expected { 1102 t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON) 1103 } 1104 } 1105 1106 func TestContextImport_33572(t *testing.T) { 1107 p := testProvider("aws") 1108 m := testModule(t, "issue-33572") 1109 1110 ctx := testContext2(t, &ContextOpts{ 1111 Providers: map[addrs.Provider]providers.Factory{ 1112 addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p), 1113 }, 1114 }) 1115 1116 p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{ 1117 ImportedResources: []providers.ImportedResource{ 1118 { 1119 TypeName: "aws_instance", 1120 State: cty.ObjectVal(map[string]cty.Value{ 1121 "id": cty.StringVal("foo"), 1122 }), 1123 }, 1124 }, 1125 } 1126 1127 state, diags := ctx.Import(m, states.NewState(), &ImportOpts{ 1128 Targets: []*ImportTarget{ 1129 { 1130 CommandLineImportTarget: &CommandLineImportTarget{ 1131 Addr: addrs.RootModuleInstance.ResourceInstance( 1132 addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey, 1133 ), 1134 ID: "bar", 1135 }, 1136 }, 1137 }, 1138 }) 1139 if diags.HasErrors() { 1140 t.Fatalf("unexpected errors: %s", diags.Err()) 1141 } 1142 actual := strings.TrimSpace(state.String()) 1143 expected := strings.TrimSpace(testImportStrWithDataSource) 1144 if diff := cmp.Diff(actual, expected); len(diff) > 0 { 1145 t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s\ndiff:\n%s", actual, expected, diff) 1146 } 1147 } 1148 1149 const testImportStr = ` 1150 aws_instance.foo: 1151 ID = foo 1152 provider = provider["registry.opentofu.org/hashicorp/aws"] 1153 ` 1154 1155 const testImportStrWithDataSource = ` 1156 data.aws_data_source.bar: 1157 ID = baz 1158 provider = provider["registry.opentofu.org/hashicorp/aws"] 1159 aws_instance.foo: 1160 ID = foo 1161 provider = provider["registry.opentofu.org/hashicorp/aws"] 1162 ` 1163 1164 const testImportCountIndexStr = ` 1165 aws_instance.foo.0: 1166 ID = foo 1167 provider = provider["registry.opentofu.org/hashicorp/aws"] 1168 ` 1169 1170 const testImportResourceWithSensitiveDataSource = ` 1171 data.aws_sensitive_data_source.source: 1172 ID = source_id 1173 provider = provider["registry.opentofu.org/hashicorp/aws"] 1174 value = pass 1175 aws_instance.foo: 1176 ID = bar 1177 provider = provider["registry.opentofu.org/hashicorp/aws"] 1178 var = pass 1179 ` 1180 1181 const testImportModuleStr = ` 1182 <no state> 1183 module.child[0]: 1184 aws_instance.foo: 1185 ID = foo 1186 provider = provider["registry.opentofu.org/hashicorp/aws"] 1187 ` 1188 1189 const testImportModuleDepth2Str = ` 1190 <no state> 1191 module.child[0].nested: 1192 aws_instance.foo: 1193 ID = foo 1194 provider = provider["registry.opentofu.org/hashicorp/aws"] 1195 ` 1196 1197 const testImportMultiStr = ` 1198 aws_instance.foo: 1199 ID = foo 1200 provider = provider["registry.opentofu.org/hashicorp/aws"] 1201 aws_instance_thing.foo: 1202 ID = bar 1203 provider = provider["registry.opentofu.org/hashicorp/aws"] 1204 ` 1205 1206 const testImportMultiSameStr = ` 1207 aws_instance.foo: 1208 ID = foo 1209 provider = provider["registry.opentofu.org/hashicorp/aws"] 1210 aws_instance_thing.foo: 1211 ID = bar 1212 provider = provider["registry.opentofu.org/hashicorp/aws"] 1213 aws_instance_thing.foo-1: 1214 ID = qux 1215 provider = provider["registry.opentofu.org/hashicorp/aws"] 1216 ` 1217 1218 const testImportRefreshStr = ` 1219 aws_instance.foo: 1220 ID = foo 1221 provider = provider["registry.opentofu.org/hashicorp/aws"] 1222 foo = bar 1223 `