github.com/jae-cisco/terraform@v0.11.12-beta1/command/import_test.go (about)

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