github.com/paultyng/terraform@v0.6.11-0.20180227224804-66ff8f8bed40/command/import_test.go (about)

     1  package command
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"strings"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/terraform/helper/copy"
    11  	"github.com/hashicorp/terraform/plugin"
    12  	"github.com/hashicorp/terraform/plugin/discovery"
    13  	"github.com/hashicorp/terraform/terraform"
    14  	"github.com/mitchellh/cli"
    15  )
    16  
    17  func TestImport(t *testing.T) {
    18  	defer testChdir(t, testFixturePath("import-provider-implicit"))()
    19  
    20  	statePath := testTempFile(t)
    21  
    22  	p := testProvider()
    23  	ui := new(cli.MockUi)
    24  	c := &ImportCommand{
    25  		Meta: Meta{
    26  			testingOverrides: metaOverridesForProvider(p),
    27  			Ui:               ui,
    28  		},
    29  	}
    30  
    31  	p.ImportStateFn = nil
    32  	p.ImportStateReturn = []*terraform.InstanceState{
    33  		&terraform.InstanceState{
    34  			ID: "yay",
    35  			Ephemeral: terraform.EphemeralState{
    36  				Type: "test_instance",
    37  			},
    38  		},
    39  	}
    40  
    41  	args := []string{
    42  		"-state", statePath,
    43  		"test_instance.foo",
    44  		"bar",
    45  	}
    46  	if code := c.Run(args); code != 0 {
    47  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    48  	}
    49  
    50  	if !p.ImportStateCalled {
    51  		t.Fatal("ImportState should be called")
    52  	}
    53  
    54  	testStateOutput(t, statePath, testImportStr)
    55  }
    56  
    57  func TestImport_providerConfig(t *testing.T) {
    58  	defer testChdir(t, testFixturePath("import-provider"))()
    59  
    60  	statePath := testTempFile(t)
    61  
    62  	p := testProvider()
    63  	ui := new(cli.MockUi)
    64  	c := &ImportCommand{
    65  		Meta: Meta{
    66  			testingOverrides: metaOverridesForProvider(p),
    67  			Ui:               ui,
    68  		},
    69  	}
    70  
    71  	p.ImportStateFn = nil
    72  	p.ImportStateReturn = []*terraform.InstanceState{
    73  		&terraform.InstanceState{
    74  			ID: "yay",
    75  			Ephemeral: terraform.EphemeralState{
    76  				Type: "test_instance",
    77  			},
    78  		},
    79  	}
    80  
    81  	configured := false
    82  	p.ConfigureFn = func(c *terraform.ResourceConfig) error {
    83  		configured = true
    84  
    85  		if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
    86  			return fmt.Errorf("bad value: %#v", v)
    87  		}
    88  
    89  		return nil
    90  	}
    91  
    92  	args := []string{
    93  		"-state", statePath,
    94  		"test_instance.foo",
    95  		"bar",
    96  	}
    97  	if code := c.Run(args); code != 0 {
    98  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    99  	}
   100  
   101  	// Verify that we were called
   102  	if !configured {
   103  		t.Fatal("Configure should be called")
   104  	}
   105  
   106  	if !p.ImportStateCalled {
   107  		t.Fatal("ImportState should be called")
   108  	}
   109  
   110  	testStateOutput(t, statePath, testImportStr)
   111  }
   112  
   113  // "remote" state provided by the "local" backend
   114  func TestImport_remoteState(t *testing.T) {
   115  	td := tempDir(t)
   116  	copy.CopyDir(testFixturePath("import-provider-remote-state"), td)
   117  	defer os.RemoveAll(td)
   118  	defer testChdir(t, td)()
   119  
   120  	statePath := "imported.tfstate"
   121  
   122  	// init our backend
   123  	ui := new(cli.MockUi)
   124  	m := Meta{
   125  		testingOverrides: metaOverridesForProvider(testProvider()),
   126  		Ui:               ui,
   127  	}
   128  
   129  	ic := &InitCommand{
   130  		Meta: m,
   131  		providerInstaller: &mockProviderInstaller{
   132  			Providers: map[string][]string{
   133  				"test": []string{"1.2.3"},
   134  			},
   135  
   136  			Dir: m.pluginDir(),
   137  		},
   138  	}
   139  
   140  	if code := ic.Run([]string{}); code != 0 {
   141  		t.Fatalf("bad: \n%s", ui.ErrorWriter)
   142  	}
   143  
   144  	p := testProvider()
   145  	ui = new(cli.MockUi)
   146  	c := &ImportCommand{
   147  		Meta: Meta{
   148  			testingOverrides: metaOverridesForProvider(p),
   149  			Ui:               ui,
   150  		},
   151  	}
   152  
   153  	p.ImportStateFn = nil
   154  	p.ImportStateReturn = []*terraform.InstanceState{
   155  		&terraform.InstanceState{
   156  			ID: "yay",
   157  			Ephemeral: terraform.EphemeralState{
   158  				Type: "test_instance",
   159  			},
   160  		},
   161  	}
   162  
   163  	configured := false
   164  	p.ConfigureFn = func(c *terraform.ResourceConfig) error {
   165  		configured = true
   166  
   167  		if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
   168  			return fmt.Errorf("bad value: %#v", v)
   169  		}
   170  
   171  		return nil
   172  	}
   173  
   174  	args := []string{
   175  		"test_instance.foo",
   176  		"bar",
   177  	}
   178  	if code := c.Run(args); code != 0 {
   179  		fmt.Println(ui.OutputWriter)
   180  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   181  	}
   182  
   183  	// Verify that we were called
   184  	if !configured {
   185  		t.Fatal("Configure should be called")
   186  	}
   187  
   188  	if !p.ImportStateCalled {
   189  		t.Fatal("ImportState should be called")
   190  	}
   191  
   192  	testStateOutput(t, statePath, testImportStr)
   193  }
   194  
   195  func TestImport_providerConfigWithVar(t *testing.T) {
   196  	defer testChdir(t, testFixturePath("import-provider-var"))()
   197  
   198  	statePath := testTempFile(t)
   199  
   200  	p := testProvider()
   201  	ui := new(cli.MockUi)
   202  	c := &ImportCommand{
   203  		Meta: Meta{
   204  			testingOverrides: metaOverridesForProvider(p),
   205  			Ui:               ui,
   206  		},
   207  	}
   208  
   209  	p.ImportStateFn = nil
   210  	p.ImportStateReturn = []*terraform.InstanceState{
   211  		&terraform.InstanceState{
   212  			ID: "yay",
   213  			Ephemeral: terraform.EphemeralState{
   214  				Type: "test_instance",
   215  			},
   216  		},
   217  	}
   218  
   219  	configured := false
   220  	p.ConfigureFn = func(c *terraform.ResourceConfig) error {
   221  		configured = true
   222  
   223  		if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
   224  			return fmt.Errorf("bad value: %#v", v)
   225  		}
   226  
   227  		return nil
   228  	}
   229  
   230  	args := []string{
   231  		"-state", statePath,
   232  		"-var", "foo=bar",
   233  		"test_instance.foo",
   234  		"bar",
   235  	}
   236  	if code := c.Run(args); code != 0 {
   237  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   238  	}
   239  
   240  	// Verify that we were called
   241  	if !configured {
   242  		t.Fatal("Configure should be called")
   243  	}
   244  
   245  	if !p.ImportStateCalled {
   246  		t.Fatal("ImportState should be called")
   247  	}
   248  
   249  	testStateOutput(t, statePath, testImportStr)
   250  }
   251  
   252  func TestImport_providerConfigWithVarDefault(t *testing.T) {
   253  	defer testChdir(t, testFixturePath("import-provider-var-default"))()
   254  
   255  	statePath := testTempFile(t)
   256  
   257  	p := testProvider()
   258  	ui := new(cli.MockUi)
   259  	c := &ImportCommand{
   260  		Meta: Meta{
   261  			testingOverrides: metaOverridesForProvider(p),
   262  			Ui:               ui,
   263  		},
   264  	}
   265  
   266  	p.ImportStateFn = nil
   267  	p.ImportStateReturn = []*terraform.InstanceState{
   268  		&terraform.InstanceState{
   269  			ID: "yay",
   270  			Ephemeral: terraform.EphemeralState{
   271  				Type: "test_instance",
   272  			},
   273  		},
   274  	}
   275  
   276  	configured := false
   277  	p.ConfigureFn = func(c *terraform.ResourceConfig) error {
   278  		configured = true
   279  
   280  		if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
   281  			return fmt.Errorf("bad value: %#v", v)
   282  		}
   283  
   284  		return nil
   285  	}
   286  
   287  	args := []string{
   288  		"-state", statePath,
   289  		"test_instance.foo",
   290  		"bar",
   291  	}
   292  	if code := c.Run(args); code != 0 {
   293  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   294  	}
   295  
   296  	// Verify that we were called
   297  	if !configured {
   298  		t.Fatal("Configure should be called")
   299  	}
   300  
   301  	if !p.ImportStateCalled {
   302  		t.Fatal("ImportState should be called")
   303  	}
   304  
   305  	testStateOutput(t, statePath, testImportStr)
   306  }
   307  
   308  func TestImport_providerConfigWithVarFile(t *testing.T) {
   309  	defer testChdir(t, testFixturePath("import-provider-var-file"))()
   310  
   311  	statePath := testTempFile(t)
   312  
   313  	p := testProvider()
   314  	ui := new(cli.MockUi)
   315  	c := &ImportCommand{
   316  		Meta: Meta{
   317  			testingOverrides: metaOverridesForProvider(p),
   318  			Ui:               ui,
   319  		},
   320  	}
   321  
   322  	p.ImportStateFn = nil
   323  	p.ImportStateReturn = []*terraform.InstanceState{
   324  		&terraform.InstanceState{
   325  			ID: "yay",
   326  			Ephemeral: terraform.EphemeralState{
   327  				Type: "test_instance",
   328  			},
   329  		},
   330  	}
   331  
   332  	configured := false
   333  	p.ConfigureFn = func(c *terraform.ResourceConfig) error {
   334  		configured = true
   335  
   336  		if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
   337  			return fmt.Errorf("bad value: %#v", v)
   338  		}
   339  
   340  		return nil
   341  	}
   342  
   343  	args := []string{
   344  		"-state", statePath,
   345  		"-var-file", "blah.tfvars",
   346  		"test_instance.foo",
   347  		"bar",
   348  	}
   349  	if code := c.Run(args); code != 0 {
   350  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   351  	}
   352  
   353  	// Verify that we were called
   354  	if !configured {
   355  		t.Fatal("Configure should be called")
   356  	}
   357  
   358  	if !p.ImportStateCalled {
   359  		t.Fatal("ImportState should be called")
   360  	}
   361  
   362  	testStateOutput(t, statePath, testImportStr)
   363  }
   364  
   365  func TestImport_customProvider(t *testing.T) {
   366  	defer testChdir(t, testFixturePath("import-provider-aliased"))()
   367  
   368  	statePath := testTempFile(t)
   369  
   370  	p := testProvider()
   371  	ui := new(cli.MockUi)
   372  	c := &ImportCommand{
   373  		Meta: Meta{
   374  			testingOverrides: metaOverridesForProvider(p),
   375  			Ui:               ui,
   376  		},
   377  	}
   378  
   379  	p.ImportStateFn = nil
   380  	p.ImportStateReturn = []*terraform.InstanceState{
   381  		&terraform.InstanceState{
   382  			ID: "yay",
   383  			Ephemeral: terraform.EphemeralState{
   384  				Type: "test_instance",
   385  			},
   386  		},
   387  	}
   388  
   389  	args := []string{
   390  		"-provider", "test.alias",
   391  		"-state", statePath,
   392  		"test_instance.foo",
   393  		"bar",
   394  	}
   395  	if code := c.Run(args); code != 0 {
   396  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   397  	}
   398  
   399  	if !p.ImportStateCalled {
   400  		t.Fatal("ImportState should be called")
   401  	}
   402  
   403  	testStateOutput(t, statePath, testImportCustomProviderStr)
   404  }
   405  
   406  func TestImport_allowMissingResourceConfig(t *testing.T) {
   407  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   408  
   409  	statePath := testTempFile(t)
   410  
   411  	p := testProvider()
   412  	ui := new(cli.MockUi)
   413  	c := &ImportCommand{
   414  		Meta: Meta{
   415  			testingOverrides: metaOverridesForProvider(p),
   416  			Ui:               ui,
   417  		},
   418  	}
   419  
   420  	p.ImportStateFn = nil
   421  	p.ImportStateReturn = []*terraform.InstanceState{
   422  		{
   423  			ID: "yay",
   424  			Ephemeral: terraform.EphemeralState{
   425  				Type: "test_instance",
   426  			},
   427  		},
   428  	}
   429  
   430  	args := []string{
   431  		"-state", statePath,
   432  		"-allow-missing-config",
   433  		"test_instance.foo",
   434  		"bar",
   435  	}
   436  	if code := c.Run(args); code != 0 {
   437  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   438  	}
   439  
   440  	if !p.ImportStateCalled {
   441  		t.Fatal("ImportState should be called")
   442  	}
   443  
   444  	testStateOutput(t, statePath, testImportStr)
   445  }
   446  
   447  func TestImport_emptyConfig(t *testing.T) {
   448  	defer testChdir(t, testFixturePath("empty"))()
   449  
   450  	statePath := testTempFile(t)
   451  
   452  	p := testProvider()
   453  	ui := new(cli.MockUi)
   454  	c := &ImportCommand{
   455  		Meta: Meta{
   456  			testingOverrides: metaOverridesForProvider(p),
   457  			Ui:               ui,
   458  		},
   459  	}
   460  
   461  	args := []string{
   462  		"-state", statePath,
   463  		"test_instance.foo",
   464  		"bar",
   465  	}
   466  	code := c.Run(args)
   467  	if code != 1 {
   468  		t.Fatalf("import succeeded; expected failure")
   469  	}
   470  
   471  	msg := ui.ErrorWriter.String()
   472  	if want := `No Terraform configuration files`; !strings.Contains(msg, want) {
   473  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   474  	}
   475  }
   476  
   477  func TestImport_missingResourceConfig(t *testing.T) {
   478  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   479  
   480  	statePath := testTempFile(t)
   481  
   482  	p := testProvider()
   483  	ui := new(cli.MockUi)
   484  	c := &ImportCommand{
   485  		Meta: Meta{
   486  			testingOverrides: metaOverridesForProvider(p),
   487  			Ui:               ui,
   488  		},
   489  	}
   490  
   491  	args := []string{
   492  		"-state", statePath,
   493  		"test_instance.foo",
   494  		"bar",
   495  	}
   496  	code := c.Run(args)
   497  	if code != 1 {
   498  		t.Fatalf("import succeeded; expected failure")
   499  	}
   500  
   501  	msg := ui.ErrorWriter.String()
   502  	if want := `resource address "test_instance.foo" does not exist`; !strings.Contains(msg, want) {
   503  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   504  	}
   505  }
   506  
   507  func TestImport_missingModuleConfig(t *testing.T) {
   508  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   509  
   510  	statePath := testTempFile(t)
   511  
   512  	p := testProvider()
   513  	ui := new(cli.MockUi)
   514  	c := &ImportCommand{
   515  		Meta: Meta{
   516  			testingOverrides: metaOverridesForProvider(p),
   517  			Ui:               ui,
   518  		},
   519  	}
   520  
   521  	args := []string{
   522  		"-state", statePath,
   523  		"module.baz.test_instance.foo",
   524  		"bar",
   525  	}
   526  	code := c.Run(args)
   527  	if code != 1 {
   528  		t.Fatalf("import succeeded; expected failure")
   529  	}
   530  
   531  	msg := ui.ErrorWriter.String()
   532  	if want := `module.baz is not defined in the configuration`; !strings.Contains(msg, want) {
   533  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   534  	}
   535  }
   536  
   537  func TestImport_dataResource(t *testing.T) {
   538  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   539  
   540  	statePath := testTempFile(t)
   541  
   542  	p := testProvider()
   543  	ui := new(cli.MockUi)
   544  	c := &ImportCommand{
   545  		Meta: Meta{
   546  			testingOverrides: metaOverridesForProvider(p),
   547  			Ui:               ui,
   548  		},
   549  	}
   550  
   551  	args := []string{
   552  		"-state", statePath,
   553  		"data.test_data_source.foo",
   554  		"bar",
   555  	}
   556  	code := c.Run(args)
   557  	if code != 1 {
   558  		t.Fatalf("import succeeded; expected failure")
   559  	}
   560  
   561  	msg := ui.ErrorWriter.String()
   562  	if want := `resource address must refer to a managed resource`; !strings.Contains(msg, want) {
   563  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   564  	}
   565  }
   566  
   567  func TestImport_invalidResourceAddr(t *testing.T) {
   568  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   569  
   570  	statePath := testTempFile(t)
   571  
   572  	p := testProvider()
   573  	ui := new(cli.MockUi)
   574  	c := &ImportCommand{
   575  		Meta: Meta{
   576  			testingOverrides: metaOverridesForProvider(p),
   577  			Ui:               ui,
   578  		},
   579  	}
   580  
   581  	args := []string{
   582  		"-state", statePath,
   583  		"bananas",
   584  		"bar",
   585  	}
   586  	code := c.Run(args)
   587  	if code != 1 {
   588  		t.Fatalf("import succeeded; expected failure")
   589  	}
   590  
   591  	msg := ui.ErrorWriter.String()
   592  	if want := `invalid resource address "bananas"`; !strings.Contains(msg, want) {
   593  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   594  	}
   595  }
   596  
   597  func TestImport_targetIsModule(t *testing.T) {
   598  	defer testChdir(t, testFixturePath("import-missing-resource-config"))()
   599  
   600  	statePath := testTempFile(t)
   601  
   602  	p := testProvider()
   603  	ui := new(cli.MockUi)
   604  	c := &ImportCommand{
   605  		Meta: Meta{
   606  			testingOverrides: metaOverridesForProvider(p),
   607  			Ui:               ui,
   608  		},
   609  	}
   610  
   611  	args := []string{
   612  		"-state", statePath,
   613  		"module.foo",
   614  		"bar",
   615  	}
   616  	code := c.Run(args)
   617  	if code != 1 {
   618  		t.Fatalf("import succeeded; expected failure")
   619  	}
   620  
   621  	msg := ui.ErrorWriter.String()
   622  	if want := `resource address must include a full resource spec`; !strings.Contains(msg, want) {
   623  		t.Errorf("incorrect message\nwant substring: %s\ngot:\n%s", want, msg)
   624  	}
   625  }
   626  
   627  // make sure we search the full plugin path during import
   628  func TestImport_pluginDir(t *testing.T) {
   629  	td := tempDir(t)
   630  	copy.CopyDir(testFixturePath("import-provider"), td)
   631  	defer os.RemoveAll(td)
   632  	defer testChdir(t, td)()
   633  
   634  	// make a fake provider in a custom plugin directory
   635  	if err := os.Mkdir("plugins", 0755); err != nil {
   636  		t.Fatal(err)
   637  	}
   638  	if err := ioutil.WriteFile("plugins/terraform-provider-test_v1.1.1_x4", []byte("invalid binary"), 0755); err != nil {
   639  		t.Fatal(err)
   640  	}
   641  
   642  	ui := new(cli.MockUi)
   643  	c := &ImportCommand{
   644  		Meta: Meta{
   645  			Ui: ui,
   646  		},
   647  	}
   648  
   649  	// store our custom plugin path, which would normally happen during init
   650  	if err := c.storePluginPath([]string{"./plugins"}); err != nil {
   651  		t.Fatal(err)
   652  	}
   653  
   654  	// Now we need to go through some plugin init.
   655  	// This discovers our fake plugin and writes the lock file.
   656  	initCmd := &InitCommand{
   657  		Meta: Meta{
   658  			pluginPath: []string{"./plugins"},
   659  			Ui:         new(cli.MockUi),
   660  		},
   661  		providerInstaller: &discovery.ProviderInstaller{
   662  			PluginProtocolVersion: plugin.Handshake.ProtocolVersion,
   663  		},
   664  	}
   665  	if err := initCmd.getProviders(".", nil, false); err != nil {
   666  		t.Fatal(err)
   667  	}
   668  
   669  	args := []string{
   670  		"test_instance.foo",
   671  		"bar",
   672  	}
   673  	if code := c.Run(args); code == 0 {
   674  		t.Fatalf("expected error, got: %s", ui.OutputWriter)
   675  	}
   676  
   677  	outMsg := ui.OutputWriter.String()
   678  	// if we were missing a plugin, the output will have some explanation
   679  	// about requirements. If discovery starts verifying binary compatibility,
   680  	// we will need to write a dummy provider above.
   681  	if strings.Contains(outMsg, "requirements") {
   682  		t.Fatal("unexpected output:", outMsg)
   683  	}
   684  
   685  	// We wanted a plugin execution error, rather than a requirement error.
   686  	// Looking for "exec" in the error should suffice for now.
   687  	errMsg := ui.ErrorWriter.String()
   688  	if !strings.Contains(errMsg, "exec") {
   689  		t.Fatal("unexpected error:", errMsg)
   690  	}
   691  }
   692  
   693  const testImportStr = `
   694  test_instance.foo:
   695    ID = yay
   696    provider = provider.test
   697  `
   698  
   699  const testImportCustomProviderStr = `
   700  test_instance.foo:
   701    ID = yay
   702    provider = provider.test.alias
   703  `