github.com/rstandt/terraform@v0.12.32-0.20230710220336-b1063613405c/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/hashicorp/terraform/addrs"
    12  	"github.com/hashicorp/terraform/helper/copy"
    13  	"github.com/hashicorp/terraform/states"
    14  )
    15  
    16  func TestStateRm(t *testing.T) {
    17  	state := states.BuildState(func(s *states.SyncState) {
    18  		s.SetResourceInstanceCurrent(
    19  			addrs.Resource{
    20  				Mode: addrs.ManagedResourceMode,
    21  				Type: "test_instance",
    22  				Name: "foo",
    23  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    24  			&states.ResourceInstanceObjectSrc{
    25  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
    26  				Status:    states.ObjectReady,
    27  			},
    28  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
    29  		)
    30  		s.SetResourceInstanceCurrent(
    31  			addrs.Resource{
    32  				Mode: addrs.ManagedResourceMode,
    33  				Type: "test_instance",
    34  				Name: "bar",
    35  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    36  			&states.ResourceInstanceObjectSrc{
    37  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
    38  				Status:    states.ObjectReady,
    39  			},
    40  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
    41  		)
    42  	})
    43  	statePath := testStateFile(t, state)
    44  
    45  	p := testProvider()
    46  	ui := new(cli.MockUi)
    47  	c := &StateRmCommand{
    48  		StateMeta{
    49  			Meta: Meta{
    50  				testingOverrides: metaOverridesForProvider(p),
    51  				Ui:               ui,
    52  			},
    53  		},
    54  	}
    55  
    56  	args := []string{
    57  		"-state", statePath,
    58  		"test_instance.foo",
    59  	}
    60  	if code := c.Run(args); code != 0 {
    61  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
    62  	}
    63  
    64  	// Test it is correct
    65  	testStateOutput(t, statePath, testStateRmOutput)
    66  
    67  	// Test we have backups
    68  	backups := testStateBackups(t, filepath.Dir(statePath))
    69  	if len(backups) != 1 {
    70  		t.Fatalf("bad: %#v", backups)
    71  	}
    72  	testStateOutput(t, backups[0], testStateRmOutputOriginal)
    73  }
    74  
    75  func TestStateRmNotChildModule(t *testing.T) {
    76  	state := states.BuildState(func(s *states.SyncState) {
    77  		s.SetResourceInstanceCurrent(
    78  			addrs.Resource{
    79  				Mode: addrs.ManagedResourceMode,
    80  				Type: "test_instance",
    81  				Name: "foo",
    82  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
    83  			&states.ResourceInstanceObjectSrc{
    84  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
    85  				Status:    states.ObjectReady,
    86  			},
    87  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
    88  		)
    89  		// This second instance has the same local address as the first but
    90  		// is in a child module. Older versions of Terraform would incorrectly
    91  		// remove this one too, since they failed to check the module address.
    92  		s.SetResourceInstanceCurrent(
    93  			addrs.Resource{
    94  				Mode: addrs.ManagedResourceMode,
    95  				Type: "test_instance",
    96  				Name: "foo",
    97  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance.Child("child", addrs.NoKey)),
    98  			&states.ResourceInstanceObjectSrc{
    99  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   100  				Status:    states.ObjectReady,
   101  			},
   102  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   103  		)
   104  	})
   105  	statePath := testStateFile(t, state)
   106  
   107  	p := testProvider()
   108  	ui := new(cli.MockUi)
   109  	c := &StateRmCommand{
   110  		StateMeta{
   111  			Meta: Meta{
   112  				testingOverrides: metaOverridesForProvider(p),
   113  				Ui:               ui,
   114  			},
   115  		},
   116  	}
   117  
   118  	args := []string{
   119  		"-state", statePath,
   120  		"test_instance.foo",
   121  	}
   122  	if code := c.Run(args); code != 0 {
   123  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   124  	}
   125  
   126  	// Test it is correct
   127  	testStateOutput(t, statePath, `
   128  <no state>
   129  module.child:
   130    test_instance.foo:
   131      ID = foo
   132      provider = provider.test
   133      bar = value
   134      foo = value
   135  `)
   136  
   137  	// Test we have backups
   138  	backups := testStateBackups(t, filepath.Dir(statePath))
   139  	if len(backups) != 1 {
   140  		t.Fatalf("bad: %#v", backups)
   141  	}
   142  	testStateOutput(t, backups[0], `
   143  test_instance.foo:
   144    ID = bar
   145    provider = provider.test
   146    bar = value
   147    foo = value
   148  
   149  module.child:
   150    test_instance.foo:
   151      ID = foo
   152      provider = provider.test
   153      bar = value
   154      foo = value
   155  `)
   156  }
   157  
   158  func TestStateRmNoArgs(t *testing.T) {
   159  	state := states.BuildState(func(s *states.SyncState) {
   160  		s.SetResourceInstanceCurrent(
   161  			addrs.Resource{
   162  				Mode: addrs.ManagedResourceMode,
   163  				Type: "test_instance",
   164  				Name: "foo",
   165  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   166  			&states.ResourceInstanceObjectSrc{
   167  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   168  				Status:    states.ObjectReady,
   169  			},
   170  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   171  		)
   172  		s.SetResourceInstanceCurrent(
   173  			addrs.Resource{
   174  				Mode: addrs.ManagedResourceMode,
   175  				Type: "test_instance",
   176  				Name: "bar",
   177  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   178  			&states.ResourceInstanceObjectSrc{
   179  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   180  				Status:    states.ObjectReady,
   181  			},
   182  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   183  		)
   184  	})
   185  	statePath := testStateFile(t, state)
   186  
   187  	p := testProvider()
   188  	ui := new(cli.MockUi)
   189  	c := &StateRmCommand{
   190  		StateMeta{
   191  			Meta: Meta{
   192  				testingOverrides: metaOverridesForProvider(p),
   193  				Ui:               ui,
   194  			},
   195  		},
   196  	}
   197  
   198  	args := []string{
   199  		"-state", statePath,
   200  	}
   201  	if code := c.Run(args); code == 0 {
   202  		t.Errorf("expected non-zero exit code, got: %d", code)
   203  	}
   204  
   205  	if msg := ui.ErrorWriter.String(); !strings.Contains(msg, "At least one address") {
   206  		t.Errorf("not the error we were looking for:\n%s", msg)
   207  	}
   208  
   209  }
   210  
   211  func TestStateRmNonExist(t *testing.T) {
   212  	state := states.BuildState(func(s *states.SyncState) {
   213  		s.SetResourceInstanceCurrent(
   214  			addrs.Resource{
   215  				Mode: addrs.ManagedResourceMode,
   216  				Type: "test_instance",
   217  				Name: "foo",
   218  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   219  			&states.ResourceInstanceObjectSrc{
   220  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   221  				Status:    states.ObjectReady,
   222  			},
   223  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   224  		)
   225  		s.SetResourceInstanceCurrent(
   226  			addrs.Resource{
   227  				Mode: addrs.ManagedResourceMode,
   228  				Type: "test_instance",
   229  				Name: "bar",
   230  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   231  			&states.ResourceInstanceObjectSrc{
   232  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   233  				Status:    states.ObjectReady,
   234  			},
   235  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   236  		)
   237  	})
   238  	statePath := testStateFile(t, state)
   239  
   240  	p := testProvider()
   241  	ui := new(cli.MockUi)
   242  	c := &StateRmCommand{
   243  		StateMeta{
   244  			Meta: Meta{
   245  				testingOverrides: metaOverridesForProvider(p),
   246  				Ui:               ui,
   247  			},
   248  		},
   249  	}
   250  
   251  	args := []string{
   252  		"-state", statePath,
   253  		"test_instance.baz", // doesn't exist in the state constructed above
   254  	}
   255  	if code := c.Run(args); code != 0 {
   256  		t.Fatalf("expected exit status %d, got: %d", 0, code)
   257  	}
   258  
   259  	if msg := ui.OutputWriter.String(); !strings.Contains(msg, "No matching resource instances found") {
   260  		t.Fatalf("unexpected output:\n%s", msg)
   261  	}
   262  
   263  }
   264  
   265  func TestStateRm_backupExplicit(t *testing.T) {
   266  	state := states.BuildState(func(s *states.SyncState) {
   267  		s.SetResourceInstanceCurrent(
   268  			addrs.Resource{
   269  				Mode: addrs.ManagedResourceMode,
   270  				Type: "test_instance",
   271  				Name: "foo",
   272  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   273  			&states.ResourceInstanceObjectSrc{
   274  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   275  				Status:    states.ObjectReady,
   276  			},
   277  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   278  		)
   279  		s.SetResourceInstanceCurrent(
   280  			addrs.Resource{
   281  				Mode: addrs.ManagedResourceMode,
   282  				Type: "test_instance",
   283  				Name: "bar",
   284  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   285  			&states.ResourceInstanceObjectSrc{
   286  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   287  				Status:    states.ObjectReady,
   288  			},
   289  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   290  		)
   291  	})
   292  	statePath := testStateFile(t, state)
   293  	backupPath := statePath + ".backup.test"
   294  
   295  	p := testProvider()
   296  	ui := new(cli.MockUi)
   297  	c := &StateRmCommand{
   298  		StateMeta{
   299  			Meta: Meta{
   300  				testingOverrides: metaOverridesForProvider(p),
   301  				Ui:               ui,
   302  			},
   303  		},
   304  	}
   305  
   306  	args := []string{
   307  		"-backup", backupPath,
   308  		"-state", statePath,
   309  		"test_instance.foo",
   310  	}
   311  	if code := c.Run(args); code != 0 {
   312  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   313  	}
   314  
   315  	// Test it is correct
   316  	testStateOutput(t, statePath, testStateRmOutput)
   317  
   318  	// Test backup
   319  	testStateOutput(t, backupPath, testStateRmOutputOriginal)
   320  }
   321  
   322  func TestStateRm_noState(t *testing.T) {
   323  	tmp, cwd := testCwd(t)
   324  	defer testFixCwd(t, tmp, cwd)
   325  
   326  	p := testProvider()
   327  	ui := new(cli.MockUi)
   328  	c := &StateRmCommand{
   329  		StateMeta{
   330  			Meta: Meta{
   331  				testingOverrides: metaOverridesForProvider(p),
   332  				Ui:               ui,
   333  			},
   334  		},
   335  	}
   336  
   337  	args := []string{"foo"}
   338  	if code := c.Run(args); code != 1 {
   339  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   340  	}
   341  }
   342  
   343  func TestStateRm_needsInit(t *testing.T) {
   344  	td := tempDir(t)
   345  	copy.CopyDir(testFixturePath("backend-change"), td)
   346  	defer os.RemoveAll(td)
   347  	defer testChdir(t, td)()
   348  
   349  	p := testProvider()
   350  	ui := new(cli.MockUi)
   351  	c := &StateRmCommand{
   352  		StateMeta{
   353  			Meta: Meta{
   354  				testingOverrides: metaOverridesForProvider(p),
   355  				Ui:               ui,
   356  			},
   357  		},
   358  	}
   359  
   360  	args := []string{"foo"}
   361  	if code := c.Run(args); code == 0 {
   362  		t.Fatalf("expected error output, got:\n%s", ui.OutputWriter.String())
   363  	}
   364  
   365  	if !strings.Contains(ui.ErrorWriter.String(), "Initialization") {
   366  		t.Fatalf("expected initialization error, got:\n%s", ui.ErrorWriter.String())
   367  	}
   368  }
   369  
   370  func TestStateRm_backendState(t *testing.T) {
   371  	td := tempDir(t)
   372  	copy.CopyDir(testFixturePath("backend-unchanged"), td)
   373  	defer os.RemoveAll(td)
   374  	defer testChdir(t, td)()
   375  
   376  	state := states.BuildState(func(s *states.SyncState) {
   377  		s.SetResourceInstanceCurrent(
   378  			addrs.Resource{
   379  				Mode: addrs.ManagedResourceMode,
   380  				Type: "test_instance",
   381  				Name: "foo",
   382  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   383  			&states.ResourceInstanceObjectSrc{
   384  				AttrsJSON: []byte(`{"id":"bar","foo":"value","bar":"value"}`),
   385  				Status:    states.ObjectReady,
   386  			},
   387  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   388  		)
   389  		s.SetResourceInstanceCurrent(
   390  			addrs.Resource{
   391  				Mode: addrs.ManagedResourceMode,
   392  				Type: "test_instance",
   393  				Name: "bar",
   394  			}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
   395  			&states.ResourceInstanceObjectSrc{
   396  				AttrsJSON: []byte(`{"id":"foo","foo":"value","bar":"value"}`),
   397  				Status:    states.ObjectReady,
   398  			},
   399  			addrs.ProviderConfig{Type: addrs.NewLegacyProvider("test")}.Absolute(addrs.RootModuleInstance),
   400  		)
   401  	})
   402  
   403  	statePath := "local-state.tfstate"
   404  	backupPath := "local-state.backup"
   405  
   406  	f, err := os.Create(statePath)
   407  	if err != nil {
   408  		t.Fatalf("failed to create state file %s: %s", statePath, err)
   409  	}
   410  	defer f.Close()
   411  
   412  	err = writeStateForTesting(state, f)
   413  	if err != nil {
   414  		t.Fatalf("failed to write state to file %s: %s", statePath, err)
   415  	}
   416  
   417  	p := testProvider()
   418  	ui := new(cli.MockUi)
   419  	c := &StateRmCommand{
   420  		StateMeta{
   421  			Meta: Meta{
   422  				testingOverrides: metaOverridesForProvider(p),
   423  				Ui:               ui,
   424  			},
   425  		},
   426  	}
   427  
   428  	args := []string{
   429  		"-backup", backupPath,
   430  		"test_instance.foo",
   431  	}
   432  	if code := c.Run(args); code != 0 {
   433  		t.Fatalf("bad: %d\n\n%s", code, ui.ErrorWriter.String())
   434  	}
   435  
   436  	// Test it is correct
   437  	testStateOutput(t, statePath, testStateRmOutput)
   438  
   439  	// Test backup
   440  	testStateOutput(t, backupPath, testStateRmOutputOriginal)
   441  }
   442  
   443  const testStateRmOutputOriginal = `
   444  test_instance.bar:
   445    ID = foo
   446    provider = provider.test
   447    bar = value
   448    foo = value
   449  test_instance.foo:
   450    ID = bar
   451    provider = provider.test
   452    bar = value
   453    foo = value
   454  `
   455  
   456  const testStateRmOutput = `
   457  test_instance.bar:
   458    ID = foo
   459    provider = provider.test
   460    bar = value
   461    foo = value
   462  `