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  `