github.com/pulumi/terraform@v1.4.0/pkg/command/state_rm_test.go (about)

     1  package command
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/mitchellh/cli"
    10  
    11  	"github.com/pulumi/terraform/pkg/addrs"
    12  	"github.com/pulumi/terraform/pkg/states"
    13  )
    14  
    15  func TestStateRm(t *testing.T) {
    16  	state := states.BuildState(func(s *states.SyncState) {
    17  		s.SetResourceInstanceCurrent(
    18  			addrs.Resource{
    19  				Mode: addrs.ManagedResourceMode,
    20  				Type: "test_instance",
    21  				Name: "foo",
    22  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    23  			&states.ResourceInstanceObjectSrc{
    24  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
    25  				Status:    states.ObjectReady,
    26  			},
    27  			addrs.AbsProviderConfig{
    28  				Provider: addrs.NewDefaultProvider("test"),
    29  				Module:   addrs.RootModule,
    30  			},
    31  		)
    32  		s.SetResourceInstanceCurrent(
    33  			addrs.Resource{
    34  				Mode: addrs.ManagedResourceMode,
    35  				Type: "test_instance",
    36  				Name: "bar",
    37  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    38  			&states.ResourceInstanceObjectSrc{
    39  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
    40  				Status:    states.ObjectReady,
    41  			},
    42  			addrs.AbsProviderConfig{
    43  				Provider: addrs.NewDefaultProvider("test"),
    44  				Module:   addrs.RootModule,
    45  			},
    46  		)
    47  	})
    48  	statePath := testStateFile(t, state)
    49  
    50  	p := testProvider()
    51  	ui := new(cli.MockUi)
    52  	view, _ := testView(t)
    53  	c := &StateRmCommand{
    54  		StateMeta{
    55  			Meta: Meta{
    56  				testingOverrides: metaOverridesForProvider(p),
    57  				Ui:               ui,
    58  				View:             view,
    59  			},
    60  		},
    61  	}
    62  
    63  	args := []string{
    64  		"-state", statePath,
    65  		"test_instance.foo",
    66  	}
    67  	if code := c.Run(args); code != 0 {
    68  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    69  	}
    70  
    71  	// Test it is correct
    72  	testStateOutput(t, statePath, testStateRmOutput)
    73  
    74  	// Test we have backups
    75  	backups := testStateBackups(t, filepath.Dir(statePath))
    76  	if len(backups) != 1 {
    77  		t.Fatalf("bad: %#v", backups)
    78  	}
    79  	testStateOutput(t, backups[0], testStateRmOutputOriginal)
    80  }
    81  
    82  func TestStateRmNotChildModule(t *testing.T) {
    83  	state := states.BuildState(func(s *states.SyncState) {
    84  		s.SetResourceInstanceCurrent(
    85  			addrs.Resource{
    86  				Mode: addrs.ManagedResourceMode,
    87  				Type: "test_instance",
    88  				Name: "foo",
    89  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    90  			&states.ResourceInstanceObjectSrc{
    91  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
    92  				Status:    states.ObjectReady,
    93  			},
    94  			addrs.AbsProviderConfig{
    95  				Provider: addrs.NewDefaultProvider("test"),
    96  				Module:   addrs.RootModule,
    97  			},
    98  		)
    99  		// This second instance has the same local address as the first but
   100  		// is in a child module. Older versions of Terraform would incorrectly
   101  		// remove this one too, since they failed to check the module address.
   102  		s.SetResourceInstanceCurrent(
   103  			addrs.Resource{
   104  				Mode: addrs.ManagedResourceMode,
   105  				Type: "test_instance",
   106  				Name: "foo",
   107  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
   108  			&states.ResourceInstanceObjectSrc{
   109  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   110  				Status:    states.ObjectReady,
   111  			},
   112  			addrs.AbsProviderConfig{
   113  				Provider: addrs.NewDefaultProvider("test"),
   114  				Module:   addrs.RootModule,
   115  			},
   116  		)
   117  	})
   118  	statePath := testStateFile(t, state)
   119  
   120  	p := testProvider()
   121  	ui := new(cli.MockUi)
   122  	view, _ := testView(t)
   123  	c := &StateRmCommand{
   124  		StateMeta{
   125  			Meta: Meta{
   126  				testingOverrides: metaOverridesForProvider(p),
   127  				Ui:               ui,
   128  				View:             view,
   129  			},
   130  		},
   131  	}
   132  
   133  	args := []string{
   134  		"-state", statePath,
   135  		"test_instance.foo",
   136  	}
   137  	if code := c.Run(args); code != 0 {
   138  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   139  	}
   140  
   141  	// Test it is correct
   142  	testStateOutput(t, statePath, `
   143  <no state>
   144  module.child:
   145    test_instance.foo:
   146      ID = foo
   147      provider = provider["registry.terraform.io/hashicorp/test"]
   148      bar = value
   149      foo = value
   150  `)
   151  
   152  	// Test we have backups
   153  	backups := testStateBackups(t, filepath.Dir(statePath))
   154  	if len(backups) != 1 {
   155  		t.Fatalf("bad: %#v", backups)
   156  	}
   157  	testStateOutput(t, backups[0], `
   158  test_instance.foo:
   159    ID = bar
   160    provider = provider["registry.terraform.io/hashicorp/test"]
   161    bar = value
   162    foo = value
   163  
   164  module.child:
   165    test_instance.foo:
   166      ID = foo
   167      provider = provider["registry.terraform.io/hashicorp/test"]
   168      bar = value
   169      foo = value
   170  `)
   171  }
   172  
   173  func TestStateRmNoArgs(t *testing.T) {
   174  	state := states.BuildState(func(s *states.SyncState) {
   175  		s.SetResourceInstanceCurrent(
   176  			addrs.Resource{
   177  				Mode: addrs.ManagedResourceMode,
   178  				Type: "test_instance",
   179  				Name: "foo",
   180  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   181  			&states.ResourceInstanceObjectSrc{
   182  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   183  				Status:    states.ObjectReady,
   184  			},
   185  			addrs.AbsProviderConfig{
   186  				Provider: addrs.NewDefaultProvider("test"),
   187  				Module:   addrs.RootModule,
   188  			},
   189  		)
   190  		s.SetResourceInstanceCurrent(
   191  			addrs.Resource{
   192  				Mode: addrs.ManagedResourceMode,
   193  				Type: "test_instance",
   194  				Name: "bar",
   195  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   196  			&states.ResourceInstanceObjectSrc{
   197  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   198  				Status:    states.ObjectReady,
   199  			},
   200  			addrs.AbsProviderConfig{
   201  				Provider: addrs.NewDefaultProvider("test"),
   202  				Module:   addrs.RootModule,
   203  			},
   204  		)
   205  	})
   206  	statePath := testStateFile(t, state)
   207  
   208  	p := testProvider()
   209  	ui := new(cli.MockUi)
   210  	view, _ := testView(t)
   211  	c := &StateRmCommand{
   212  		StateMeta{
   213  			Meta: Meta{
   214  				testingOverrides: metaOverridesForProvider(p),
   215  				Ui:               ui,
   216  				View:             view,
   217  			},
   218  		},
   219  	}
   220  
   221  	args := []string{
   222  		"-state", statePath,
   223  	}
   224  	if code := c.Run(args); code == 0 {
   225  		t.Errorf("expected non-zero exit code, got: %d", code)
   226  	}
   227  
   228  	if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one address") {
   229  		t.Errorf("not the error we were looking for:\n%s", msg)
   230  	}
   231  
   232  }
   233  
   234  func TestStateRmNonExist(t *testing.T) {
   235  	state := states.BuildState(func(s *states.SyncState) {
   236  		s.SetResourceInstanceCurrent(
   237  			addrs.Resource{
   238  				Mode: addrs.ManagedResourceMode,
   239  				Type: "test_instance",
   240  				Name: "foo",
   241  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   242  			&states.ResourceInstanceObjectSrc{
   243  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   244  				Status:    states.ObjectReady,
   245  			},
   246  			addrs.AbsProviderConfig{
   247  				Provider: addrs.NewDefaultProvider("test"),
   248  				Module:   addrs.RootModule,
   249  			},
   250  		)
   251  		s.SetResourceInstanceCurrent(
   252  			addrs.Resource{
   253  				Mode: addrs.ManagedResourceMode,
   254  				Type: "test_instance",
   255  				Name: "bar",
   256  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   257  			&states.ResourceInstanceObjectSrc{
   258  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   259  				Status:    states.ObjectReady,
   260  			},
   261  			addrs.AbsProviderConfig{
   262  				Provider: addrs.NewDefaultProvider("test"),
   263  				Module:   addrs.RootModule,
   264  			},
   265  		)
   266  	})
   267  	statePath := testStateFile(t, state)
   268  
   269  	p := testProvider()
   270  	ui := new(cli.MockUi)
   271  	view, _ := testView(t)
   272  	c := &StateRmCommand{
   273  		StateMeta{
   274  			Meta: Meta{
   275  				testingOverrides: metaOverridesForProvider(p),
   276  				Ui:               ui,
   277  				View:             view,
   278  			},
   279  		},
   280  	}
   281  
   282  	args := []string{
   283  		"-state", statePath,
   284  		"test_instance.baz", // doesn't exist in the state constructed above
   285  	}
   286  	if code := c.Run(args); code != 1 {
   287  		t.Fatalf("expected exit status %d, got: %d", 1, code)
   288  	}
   289  }
   290  
   291  func TestStateRm_backupExplicit(t *testing.T) {
   292  	state := states.BuildState(func(s *states.SyncState) {
   293  		s.SetResourceInstanceCurrent(
   294  			addrs.Resource{
   295  				Mode: addrs.ManagedResourceMode,
   296  				Type: "test_instance",
   297  				Name: "foo",
   298  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   299  			&states.ResourceInstanceObjectSrc{
   300  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   301  				Status:    states.ObjectReady,
   302  			},
   303  			addrs.AbsProviderConfig{
   304  				Provider: addrs.NewDefaultProvider("test"),
   305  				Module:   addrs.RootModule,
   306  			},
   307  		)
   308  		s.SetResourceInstanceCurrent(
   309  			addrs.Resource{
   310  				Mode: addrs.ManagedResourceMode,
   311  				Type: "test_instance",
   312  				Name: "bar",
   313  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   314  			&states.ResourceInstanceObjectSrc{
   315  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   316  				Status:    states.ObjectReady,
   317  			},
   318  			addrs.AbsProviderConfig{
   319  				Provider: addrs.NewDefaultProvider("test"),
   320  				Module:   addrs.RootModule,
   321  			},
   322  		)
   323  	})
   324  	statePath := testStateFile(t, state)
   325  	backupPath := statePath + ".backup.test"
   326  
   327  	p := testProvider()
   328  	ui := new(cli.MockUi)
   329  	view, _ := testView(t)
   330  	c := &StateRmCommand{
   331  		StateMeta{
   332  			Meta: Meta{
   333  				testingOverrides: metaOverridesForProvider(p),
   334  				Ui:               ui,
   335  				View:             view,
   336  			},
   337  		},
   338  	}
   339  
   340  	args := []string{
   341  		"-backup", backupPath,
   342  		"-state", statePath,
   343  		"test_instance.foo",
   344  	}
   345  	if code := c.Run(args); code != 0 {
   346  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   347  	}
   348  
   349  	// Test it is correct
   350  	testStateOutput(t, statePath, testStateRmOutput)
   351  
   352  	// Test backup
   353  	testStateOutput(t, backupPath, testStateRmOutputOriginal)
   354  }
   355  
   356  func TestStateRm_noState(t *testing.T) {
   357  	testCwd(t)
   358  
   359  	p := testProvider()
   360  	ui := new(cli.MockUi)
   361  	view, _ := testView(t)
   362  	c := &StateRmCommand{
   363  		StateMeta{
   364  			Meta: Meta{
   365  				testingOverrides: metaOverridesForProvider(p),
   366  				Ui:               ui,
   367  				View:             view,
   368  			},
   369  		},
   370  	}
   371  
   372  	args := []string{"foo"}
   373  	if code := c.Run(args); code != 1 {
   374  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   375  	}
   376  }
   377  
   378  func TestStateRm_needsInit(t *testing.T) {
   379  	td := t.TempDir()
   380  	testCopyDir(t, testFixturePath("backend-change"), td)
   381  	defer testChdir(t, td)()
   382  
   383  	p := testProvider()
   384  	ui := new(cli.MockUi)
   385  	view, _ := testView(t)
   386  	c := &StateRmCommand{
   387  		StateMeta{
   388  			Meta: Meta{
   389  				testingOverrides: metaOverridesForProvider(p),
   390  				Ui:               ui,
   391  				View:             view,
   392  			},
   393  		},
   394  	}
   395  
   396  	args := []string{"foo"}
   397  	if code := c.Run(args); code == 0 {
   398  		t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
   399  	}
   400  
   401  	if !strings.Contains(ui.ErrorWriter.String(), "Backend initialization") {
   402  		t.Fatalf("expected initialization error, got:\n%s", ui.ErrorWriter.String())
   403  	}
   404  }
   405  
   406  func TestStateRm_backendState(t *testing.T) {
   407  	td := t.TempDir()
   408  	testCopyDir(t, testFixturePath("backend-unchanged"), td)
   409  	defer testChdir(t, td)()
   410  
   411  	state := states.BuildState(func(s *states.SyncState) {
   412  		s.SetResourceInstanceCurrent(
   413  			addrs.Resource{
   414  				Mode: addrs.ManagedResourceMode,
   415  				Type: "test_instance",
   416  				Name: "foo",
   417  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   418  			&states.ResourceInstanceObjectSrc{
   419  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   420  				Status:    states.ObjectReady,
   421  			},
   422  			addrs.AbsProviderConfig{
   423  				Provider: addrs.NewDefaultProvider("test"),
   424  				Module:   addrs.RootModule,
   425  			},
   426  		)
   427  		s.SetResourceInstanceCurrent(
   428  			addrs.Resource{
   429  				Mode: addrs.ManagedResourceMode,
   430  				Type: "test_instance",
   431  				Name: "bar",
   432  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   433  			&states.ResourceInstanceObjectSrc{
   434  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   435  				Status:    states.ObjectReady,
   436  			},
   437  			addrs.AbsProviderConfig{
   438  				Provider: addrs.NewDefaultProvider("test"),
   439  				Module:   addrs.RootModule,
   440  			},
   441  		)
   442  	})
   443  
   444  	statePath := "local-state.tfstate"
   445  	backupPath := "local-state.backup"
   446  
   447  	f, err := os.Create(statePath)
   448  	if err != nil {
   449  		t.Fatalf("failed to create state file %s: %s", statePath, err)
   450  	}
   451  	defer f.Close()
   452  
   453  	err = writeStateForTesting(state, f)
   454  	if err != nil {
   455  		t.Fatalf("failed to write state to file %s: %s", statePath, err)
   456  	}
   457  
   458  	p := testProvider()
   459  	ui := new(cli.MockUi)
   460  	view, _ := testView(t)
   461  	c := &StateRmCommand{
   462  		StateMeta{
   463  			Meta: Meta{
   464  				testingOverrides: metaOverridesForProvider(p),
   465  				Ui:               ui,
   466  				View:             view,
   467  			},
   468  		},
   469  	}
   470  
   471  	args := []string{
   472  		"-backup", backupPath,
   473  		"test_instance.foo",
   474  	}
   475  	if code := c.Run(args); code != 0 {
   476  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   477  	}
   478  
   479  	// Test it is correct
   480  	testStateOutput(t, statePath, testStateRmOutput)
   481  
   482  	// Test backup
   483  	testStateOutput(t, backupPath, testStateRmOutputOriginal)
   484  }
   485  
   486  func TestStateRm_checkRequiredVersion(t *testing.T) {
   487  	// Create a temporary working directory that is empty
   488  	td := t.TempDir()
   489  	testCopyDir(t, testFixturePath("command-check-required-version"), td)
   490  	defer testChdir(t, td)()
   491  
   492  	state := states.BuildState(func(s *states.SyncState) {
   493  		s.SetResourceInstanceCurrent(
   494  			addrs.Resource{
   495  				Mode: addrs.ManagedResourceMode,
   496  				Type: "test_instance",
   497  				Name: "foo",
   498  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   499  			&states.ResourceInstanceObjectSrc{
   500  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   501  				Status:    states.ObjectReady,
   502  			},
   503  			addrs.AbsProviderConfig{
   504  				Provider: addrs.NewDefaultProvider("test"),
   505  				Module:   addrs.RootModule,
   506  			},
   507  		)
   508  		s.SetResourceInstanceCurrent(
   509  			addrs.Resource{
   510  				Mode: addrs.ManagedResourceMode,
   511  				Type: "test_instance",
   512  				Name: "bar",
   513  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   514  			&states.ResourceInstanceObjectSrc{
   515  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   516  				Status:    states.ObjectReady,
   517  			},
   518  			addrs.AbsProviderConfig{
   519  				Provider: addrs.NewDefaultProvider("test"),
   520  				Module:   addrs.RootModule,
   521  			},
   522  		)
   523  	})
   524  	statePath := testStateFile(t, state)
   525  
   526  	p := testProvider()
   527  	ui := new(cli.MockUi)
   528  	view, _ := testView(t)
   529  	c := &StateRmCommand{
   530  		StateMeta{
   531  			Meta: Meta{
   532  				testingOverrides: metaOverridesForProvider(p),
   533  				Ui:               ui,
   534  				View:             view,
   535  			},
   536  		},
   537  	}
   538  
   539  	args := []string{
   540  		"-state", statePath,
   541  		"test_instance.foo",
   542  	}
   543  	if code := c.Run(args); code != 1 {
   544  		t.Fatalf("got exit status %d; want 1\nstderr:\n%s\n\nstdout:\n%s", code, ui.ErrorWriter.String(), ui.OutputWriter.String())
   545  	}
   546  
   547  	// State is unchanged
   548  	testStateOutput(t, statePath, testStateRmOutputOriginal)
   549  
   550  	// Required version diags are correct
   551  	errStr := ui.ErrorWriter.String()
   552  	if !strings.Contains(errStr, `required_version = "~> 0.9.0"`) {
   553  		t.Fatalf("output should point to unmet version constraint, but is:\n\n%s", errStr)
   554  	}
   555  	if strings.Contains(errStr, `required_version = ">= 0.13.0"`) {
   556  		t.Fatalf("output should not point to met version constraint, but is:\n\n%s", errStr)
   557  	}
   558  }
   559  
   560  const testStateRmOutputOriginal = `
   561  test_instance.bar:
   562    ID = foo
   563    provider = provider["registry.terraform.io/hashicorp/test"]
   564    bar = value
   565    foo = value
   566  test_instance.foo:
   567    ID = bar
   568    provider = provider["registry.terraform.io/hashicorp/test"]
   569    bar = value
   570    foo = value
   571  `
   572  
   573  const testStateRmOutput = `
   574  test_instance.bar:
   575    ID = foo
   576    provider = provider["registry.terraform.io/hashicorp/test"]
   577    bar = value
   578    foo = value
   579  `