github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/command/import_test.go (about)

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