kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/command/meta_backend_test.go (about)

     1  package command
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"reflect"
     8  	"sort"
     9  	"testing"
    10  
    11  	"kubeform.dev/terraform-backend-sdk/addrs"
    12  	"kubeform.dev/terraform-backend-sdk/backend"
    13  	"kubeform.dev/terraform-backend-sdk/configs"
    14  	"kubeform.dev/terraform-backend-sdk/copy"
    15  	"kubeform.dev/terraform-backend-sdk/plans"
    16  	"kubeform.dev/terraform-backend-sdk/states"
    17  	"kubeform.dev/terraform-backend-sdk/states/statefile"
    18  	"kubeform.dev/terraform-backend-sdk/states/statemgr"
    19  	"github.com/mitchellh/cli"
    20  	"github.com/zclconf/go-cty/cty"
    21  
    22  	backendInit "kubeform.dev/terraform-backend-sdk/backend/init"
    23  	backendLocal "kubeform.dev/terraform-backend-sdk/backend/local"
    24  	backendInmem "kubeform.dev/terraform-backend-sdk/backend/remote-state/inmem"
    25  )
    26  
    27  // Test empty directory with no config/state creates a local state.
    28  func TestMetaBackend_emptyDir(t *testing.T) {
    29  	// Create a temporary working directory that is empty
    30  	td := tempDir(t)
    31  	os.MkdirAll(td, 0755)
    32  	defer os.RemoveAll(td)
    33  	defer testChdir(t, td)()
    34  
    35  	// Get the backend
    36  	m := testMetaBackend(t, nil)
    37  	b, diags := m.Backend(&BackendOpts{Init: true})
    38  	if diags.HasErrors() {
    39  		t.Fatal(diags.Err())
    40  	}
    41  
    42  	// Write some state
    43  	s, err := b.StateMgr(backend.DefaultStateName)
    44  	if err != nil {
    45  		t.Fatalf("unexpected error: %s", err)
    46  	}
    47  	s.WriteState(testState())
    48  	if err := s.PersistState(); err != nil {
    49  		t.Fatalf("unexpected error: %s", err)
    50  	}
    51  
    52  	// Verify it exists where we expect it to
    53  	if isEmptyState(DefaultStateFilename) {
    54  		t.Fatalf("no state was written")
    55  	}
    56  
    57  	// Verify no backup since it was empty to start
    58  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
    59  		t.Fatal("backup state should be empty")
    60  	}
    61  
    62  	// Verify no backend state was made
    63  	if !isEmptyState(filepath.Join(m.DataDir(), DefaultStateFilename)) {
    64  		t.Fatal("backend state should be empty")
    65  	}
    66  }
    67  
    68  // check for no state. Either the file doesn't exist, or is empty
    69  func isEmptyState(path string) bool {
    70  	fi, err := os.Stat(path)
    71  	if os.IsNotExist(err) {
    72  		return true
    73  	}
    74  
    75  	if fi.Size() == 0 {
    76  		return true
    77  	}
    78  
    79  	return false
    80  }
    81  
    82  // Test a directory with a legacy state and no config continues to
    83  // use the legacy state.
    84  func TestMetaBackend_emptyWithDefaultState(t *testing.T) {
    85  	// Create a temporary working directory that is empty
    86  	td := tempDir(t)
    87  	os.MkdirAll(td, 0755)
    88  	defer os.RemoveAll(td)
    89  	defer testChdir(t, td)()
    90  
    91  	// Write the legacy state
    92  	statePath := DefaultStateFilename
    93  	{
    94  		f, err := os.Create(statePath)
    95  		if err != nil {
    96  			t.Fatalf("err: %s", err)
    97  		}
    98  		err = writeStateForTesting(testState(), f)
    99  		f.Close()
   100  		if err != nil {
   101  			t.Fatalf("err: %s", err)
   102  		}
   103  	}
   104  
   105  	// Get the backend
   106  	m := testMetaBackend(t, nil)
   107  	b, diags := m.Backend(&BackendOpts{Init: true})
   108  	if diags.HasErrors() {
   109  		t.Fatal(diags.Err())
   110  	}
   111  
   112  	// Check the state
   113  	s, err := b.StateMgr(backend.DefaultStateName)
   114  	if err != nil {
   115  		t.Fatalf("unexpected error: %s", err)
   116  	}
   117  	if err := s.RefreshState(); err != nil {
   118  		t.Fatalf("err: %s", err)
   119  	}
   120  	if actual := s.State().String(); actual != testState().String() {
   121  		t.Fatalf("bad: %s", actual)
   122  	}
   123  
   124  	// Verify it exists where we expect it to
   125  	if _, err := os.Stat(DefaultStateFilename); err != nil {
   126  		t.Fatalf("err: %s", err)
   127  	}
   128  
   129  	stateName := filepath.Join(m.DataDir(), DefaultStateFilename)
   130  	if !isEmptyState(stateName) {
   131  		t.Fatal("expected no state at", stateName)
   132  	}
   133  
   134  	// Write some state
   135  	next := testState()
   136  	next.RootModule().SetOutputValue("foo", cty.StringVal("bar"), false)
   137  	s.WriteState(next)
   138  	if err := s.PersistState(); err != nil {
   139  		t.Fatalf("unexpected error: %s", err)
   140  	}
   141  
   142  	// Verify a backup was made since we're modifying a pre-existing state
   143  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   144  		t.Fatal("backup state should not be empty")
   145  	}
   146  }
   147  
   148  // Test an empty directory with an explicit state path (outside the dir)
   149  func TestMetaBackend_emptyWithExplicitState(t *testing.T) {
   150  	// Create a temporary working directory that is empty
   151  	td := tempDir(t)
   152  	os.MkdirAll(td, 0755)
   153  	defer os.RemoveAll(td)
   154  	defer testChdir(t, td)()
   155  
   156  	// Create another directory to store our state
   157  	stateDir := tempDir(t)
   158  	os.MkdirAll(stateDir, 0755)
   159  	defer os.RemoveAll(stateDir)
   160  
   161  	// Write the legacy state
   162  	statePath := filepath.Join(stateDir, "foo")
   163  	{
   164  		f, err := os.Create(statePath)
   165  		if err != nil {
   166  			t.Fatalf("err: %s", err)
   167  		}
   168  		err = writeStateForTesting(testState(), f)
   169  		f.Close()
   170  		if err != nil {
   171  			t.Fatalf("err: %s", err)
   172  		}
   173  	}
   174  
   175  	// Setup the meta
   176  	m := testMetaBackend(t, nil)
   177  	m.statePath = statePath
   178  
   179  	// Get the backend
   180  	b, diags := m.Backend(&BackendOpts{Init: true})
   181  	if diags.HasErrors() {
   182  		t.Fatal(diags.Err())
   183  	}
   184  
   185  	// Check the state
   186  	s, err := b.StateMgr(backend.DefaultStateName)
   187  	if err != nil {
   188  		t.Fatalf("unexpected error: %s", err)
   189  	}
   190  	if err := s.RefreshState(); err != nil {
   191  		t.Fatalf("err: %s", err)
   192  	}
   193  	if actual := s.State().String(); actual != testState().String() {
   194  		t.Fatalf("bad: %s", actual)
   195  	}
   196  
   197  	// Verify neither defaults exist
   198  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   199  		t.Fatal("file should not exist")
   200  	}
   201  
   202  	stateName := filepath.Join(m.DataDir(), DefaultStateFilename)
   203  	if !isEmptyState(stateName) {
   204  		t.Fatal("expected no state at", stateName)
   205  	}
   206  
   207  	// Write some state
   208  	next := testState()
   209  	markStateForMatching(next, "bar") // just any change so it shows as different than before
   210  	s.WriteState(next)
   211  	if err := s.PersistState(); err != nil {
   212  		t.Fatalf("unexpected error: %s", err)
   213  	}
   214  
   215  	// Verify a backup was made since we're modifying a pre-existing state
   216  	if isEmptyState(statePath + DefaultBackupExtension) {
   217  		t.Fatal("backup state should not be empty")
   218  	}
   219  }
   220  
   221  // Verify that interpolations result in an error
   222  func TestMetaBackend_configureInterpolation(t *testing.T) {
   223  	// Create a temporary working directory that is empty
   224  	td := tempDir(t)
   225  	testCopyDir(t, testFixturePath("backend-new-interp"), td)
   226  	defer os.RemoveAll(td)
   227  	defer testChdir(t, td)()
   228  
   229  	// Setup the meta
   230  	m := testMetaBackend(t, nil)
   231  
   232  	// Get the backend
   233  	_, err := m.Backend(&BackendOpts{Init: true})
   234  	if err == nil {
   235  		t.Fatal("should error")
   236  	}
   237  }
   238  
   239  // Newly configured backend
   240  func TestMetaBackend_configureNew(t *testing.T) {
   241  	td := tempDir(t)
   242  	testCopyDir(t, testFixturePath("backend-new"), td)
   243  	defer os.RemoveAll(td)
   244  	defer testChdir(t, td)()
   245  
   246  	// Setup the meta
   247  	m := testMetaBackend(t, nil)
   248  
   249  	// Get the backend
   250  	b, diags := m.Backend(&BackendOpts{Init: true})
   251  	if diags.HasErrors() {
   252  		t.Fatal(diags.Err())
   253  	}
   254  
   255  	// Check the state
   256  	s, err := b.StateMgr(backend.DefaultStateName)
   257  	if err != nil {
   258  		t.Fatalf("unexpected error: %s", err)
   259  	}
   260  	if err := s.RefreshState(); err != nil {
   261  		t.Fatalf("unexpected error: %s", err)
   262  	}
   263  	state := s.State()
   264  	if state != nil {
   265  		t.Fatal("state should be nil")
   266  	}
   267  
   268  	// Write some state
   269  	state = states.NewState()
   270  	mark := markStateForMatching(state, "changing")
   271  
   272  	s.WriteState(state)
   273  	if err := s.PersistState(); err != nil {
   274  		t.Fatalf("unexpected error: %s", err)
   275  	}
   276  
   277  	// Verify the state is where we expect
   278  	{
   279  		f, err := os.Open("local-state.tfstate")
   280  		if err != nil {
   281  			t.Fatalf("err: %s", err)
   282  		}
   283  		actual, err := statefile.Read(f)
   284  		f.Close()
   285  		if err != nil {
   286  			t.Fatalf("err: %s", err)
   287  		}
   288  
   289  		assertStateHasMarker(t, actual.State, mark)
   290  	}
   291  
   292  	// Verify the default paths don't exist
   293  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   294  		t.Fatal("file should not exist")
   295  	}
   296  
   297  	// Verify a backup doesn't exist
   298  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   299  		t.Fatal("file should not exist")
   300  	}
   301  }
   302  
   303  // Newly configured backend with prior local state and no remote state
   304  func TestMetaBackend_configureNewWithState(t *testing.T) {
   305  	// Create a temporary working directory that is empty
   306  	td := tempDir(t)
   307  	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
   308  	defer os.RemoveAll(td)
   309  	defer testChdir(t, td)()
   310  
   311  	// Ask input
   312  	defer testInteractiveInput(t, []string{"yes"})()
   313  
   314  	// Setup the meta
   315  	m := testMetaBackend(t, nil)
   316  
   317  	// This combination should not require the extra -migrate-state flag, since
   318  	// there is no existing backend config
   319  	m.migrateState = false
   320  
   321  	// Get the backend
   322  	b, diags := m.Backend(&BackendOpts{Init: true})
   323  	if diags.HasErrors() {
   324  		t.Fatal(diags.Err())
   325  	}
   326  
   327  	// Check the state
   328  	s, err := b.StateMgr(backend.DefaultStateName)
   329  	if err != nil {
   330  		t.Fatalf("unexpected error: %s", err)
   331  	}
   332  	state, err := statemgr.RefreshAndRead(s)
   333  	if err != nil {
   334  		t.Fatalf("unexpected error: %s", err)
   335  	}
   336  	if state == nil {
   337  		t.Fatal("state is nil")
   338  	}
   339  
   340  	if got, want := testStateMgrCurrentLineage(s), "backend-new-migrate"; got != want {
   341  		t.Fatalf("lineage changed during migration\nnow: %s\nwas: %s", got, want)
   342  	}
   343  
   344  	// Write some state
   345  	state = states.NewState()
   346  	mark := markStateForMatching(state, "changing")
   347  
   348  	if err := statemgr.WriteAndPersist(s, state); err != nil {
   349  		t.Fatalf("unexpected error: %s", err)
   350  	}
   351  
   352  	// Verify the state is where we expect
   353  	{
   354  		f, err := os.Open("local-state.tfstate")
   355  		if err != nil {
   356  			t.Fatalf("err: %s", err)
   357  		}
   358  		actual, err := statefile.Read(f)
   359  		f.Close()
   360  		if err != nil {
   361  			t.Fatalf("err: %s", err)
   362  		}
   363  
   364  		assertStateHasMarker(t, actual.State, mark)
   365  	}
   366  
   367  	// Verify the default paths don't exist
   368  	if !isEmptyState(DefaultStateFilename) {
   369  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   370  
   371  		t.Fatal("state should not exist, but contains:\n", string(data))
   372  	}
   373  
   374  	// Verify a backup does exist
   375  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   376  		t.Fatal("backup state is empty or missing")
   377  	}
   378  }
   379  
   380  // Newly configured backend with matching local and remote state doesn't prompt
   381  // for copy.
   382  func TestMetaBackend_configureNewWithoutCopy(t *testing.T) {
   383  	// Create a temporary working directory that is empty
   384  	td := tempDir(t)
   385  	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
   386  	defer os.RemoveAll(td)
   387  	defer testChdir(t, td)()
   388  
   389  	if err := copy.CopyFile(DefaultStateFilename, "local-state.tfstate"); err != nil {
   390  		t.Fatal(err)
   391  	}
   392  
   393  	// Setup the meta
   394  	m := testMetaBackend(t, nil)
   395  	m.input = false
   396  
   397  	// init the backend
   398  	_, diags := m.Backend(&BackendOpts{Init: true})
   399  	if diags.HasErrors() {
   400  		t.Fatal(diags.Err())
   401  	}
   402  
   403  	// Verify the state is where we expect
   404  	f, err := os.Open("local-state.tfstate")
   405  	if err != nil {
   406  		t.Fatalf("err: %s", err)
   407  	}
   408  	actual, err := statefile.Read(f)
   409  	f.Close()
   410  	if err != nil {
   411  		t.Fatalf("err: %s", err)
   412  	}
   413  
   414  	if actual.Lineage != "backend-new-migrate" {
   415  		t.Fatalf("incorrect state lineage: %q", actual.Lineage)
   416  	}
   417  
   418  	// Verify the default paths don't exist
   419  	if !isEmptyState(DefaultStateFilename) {
   420  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   421  
   422  		t.Fatal("state should not exist, but contains:\n", string(data))
   423  	}
   424  
   425  	// Verify a backup does exist
   426  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   427  		t.Fatal("backup state is empty or missing")
   428  	}
   429  }
   430  
   431  // Newly configured backend with prior local state and no remote state,
   432  // but opting to not migrate.
   433  func TestMetaBackend_configureNewWithStateNoMigrate(t *testing.T) {
   434  	// Create a temporary working directory that is empty
   435  	td := tempDir(t)
   436  	testCopyDir(t, testFixturePath("backend-new-migrate"), td)
   437  	defer os.RemoveAll(td)
   438  	defer testChdir(t, td)()
   439  
   440  	// Ask input
   441  	defer testInteractiveInput(t, []string{"no"})()
   442  
   443  	// Setup the meta
   444  	m := testMetaBackend(t, nil)
   445  
   446  	// Get the backend
   447  	b, diags := m.Backend(&BackendOpts{Init: true})
   448  	if diags.HasErrors() {
   449  		t.Fatal(diags.Err())
   450  	}
   451  
   452  	// Check the state
   453  	s, err := b.StateMgr(backend.DefaultStateName)
   454  	if err != nil {
   455  		t.Fatalf("unexpected error: %s", err)
   456  	}
   457  	if err := s.RefreshState(); err != nil {
   458  		t.Fatalf("unexpected error: %s", err)
   459  	}
   460  	if state := s.State(); state != nil {
   461  		t.Fatal("state is not nil")
   462  	}
   463  
   464  	// Verify the default paths don't exist
   465  	if !isEmptyState(DefaultStateFilename) {
   466  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   467  
   468  		t.Fatal("state should not exist, but contains:\n", string(data))
   469  	}
   470  
   471  	// Verify a backup does exist
   472  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   473  		t.Fatal("backup state is empty or missing")
   474  	}
   475  }
   476  
   477  // Newly configured backend with prior local state and remote state
   478  func TestMetaBackend_configureNewWithStateExisting(t *testing.T) {
   479  	// Create a temporary working directory that is empty
   480  	td := tempDir(t)
   481  	testCopyDir(t, testFixturePath("backend-new-migrate-existing"), td)
   482  	defer os.RemoveAll(td)
   483  	defer testChdir(t, td)()
   484  
   485  	// Setup the meta
   486  	m := testMetaBackend(t, nil)
   487  	// suppress input
   488  	m.forceInitCopy = true
   489  
   490  	// Get the backend
   491  	b, diags := m.Backend(&BackendOpts{Init: true})
   492  	if diags.HasErrors() {
   493  		t.Fatal(diags.Err())
   494  	}
   495  
   496  	// Check the state
   497  	s, err := b.StateMgr(backend.DefaultStateName)
   498  	if err != nil {
   499  		t.Fatalf("unexpected error: %s", err)
   500  	}
   501  	if err := s.RefreshState(); err != nil {
   502  		t.Fatalf("unexpected error: %s", err)
   503  	}
   504  	state := s.State()
   505  	if state == nil {
   506  		t.Fatal("state is nil")
   507  	}
   508  	if got, want := testStateMgrCurrentLineage(s), "local"; got != want {
   509  		t.Fatalf("wrong lineage %q; want %q", got, want)
   510  	}
   511  
   512  	// Write some state
   513  	state = states.NewState()
   514  	mark := markStateForMatching(state, "changing")
   515  
   516  	s.WriteState(state)
   517  	if err := s.PersistState(); err != nil {
   518  		t.Fatalf("unexpected error: %s", err)
   519  	}
   520  
   521  	// Verify the state is where we expect
   522  	{
   523  		f, err := os.Open("local-state.tfstate")
   524  		if err != nil {
   525  			t.Fatalf("err: %s", err)
   526  		}
   527  		actual, err := statefile.Read(f)
   528  		f.Close()
   529  		if err != nil {
   530  			t.Fatalf("err: %s", err)
   531  		}
   532  
   533  		assertStateHasMarker(t, actual.State, mark)
   534  	}
   535  
   536  	// Verify the default paths don't exist
   537  	if !isEmptyState(DefaultStateFilename) {
   538  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   539  
   540  		t.Fatal("state should not exist, but contains:\n", string(data))
   541  	}
   542  
   543  	// Verify a backup does exist
   544  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   545  		t.Fatal("backup state is empty or missing")
   546  	}
   547  }
   548  
   549  // Newly configured backend with prior local state and remote state
   550  func TestMetaBackend_configureNewWithStateExistingNoMigrate(t *testing.T) {
   551  	// Create a temporary working directory that is empty
   552  	td := tempDir(t)
   553  	testCopyDir(t, testFixturePath("backend-new-migrate-existing"), td)
   554  	defer os.RemoveAll(td)
   555  	defer testChdir(t, td)()
   556  
   557  	// Ask input
   558  	defer testInteractiveInput(t, []string{"no"})()
   559  
   560  	// Setup the meta
   561  	m := testMetaBackend(t, nil)
   562  
   563  	// Get the backend
   564  	b, diags := m.Backend(&BackendOpts{Init: true})
   565  	if diags.HasErrors() {
   566  		t.Fatal(diags.Err())
   567  	}
   568  
   569  	// Check the state
   570  	s, err := b.StateMgr(backend.DefaultStateName)
   571  	if err != nil {
   572  		t.Fatalf("unexpected error: %s", err)
   573  	}
   574  	if err := s.RefreshState(); err != nil {
   575  		t.Fatalf("unexpected error: %s", err)
   576  	}
   577  	state := s.State()
   578  	if state == nil {
   579  		t.Fatal("state is nil")
   580  	}
   581  	if testStateMgrCurrentLineage(s) != "remote" {
   582  		t.Fatalf("bad: %#v", state)
   583  	}
   584  
   585  	// Write some state
   586  	state = states.NewState()
   587  	mark := markStateForMatching(state, "changing")
   588  	s.WriteState(state)
   589  	if err := s.PersistState(); err != nil {
   590  		t.Fatalf("unexpected error: %s", err)
   591  	}
   592  
   593  	// Verify the state is where we expect
   594  	{
   595  		f, err := os.Open("local-state.tfstate")
   596  		if err != nil {
   597  			t.Fatalf("err: %s", err)
   598  		}
   599  		actual, err := statefile.Read(f)
   600  		f.Close()
   601  		if err != nil {
   602  			t.Fatalf("err: %s", err)
   603  		}
   604  
   605  		assertStateHasMarker(t, actual.State, mark)
   606  	}
   607  
   608  	// Verify the default paths don't exist
   609  	if !isEmptyState(DefaultStateFilename) {
   610  		data, _ := ioutil.ReadFile(DefaultStateFilename)
   611  
   612  		t.Fatal("state should not exist, but contains:\n", string(data))
   613  	}
   614  
   615  	// Verify a backup does exist
   616  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
   617  		t.Fatal("backup state is empty or missing")
   618  	}
   619  }
   620  
   621  // Saved backend state matching config
   622  func TestMetaBackend_configuredUnchanged(t *testing.T) {
   623  	defer testChdir(t, testFixturePath("backend-unchanged"))()
   624  
   625  	// Setup the meta
   626  	m := testMetaBackend(t, nil)
   627  
   628  	// Get the backend
   629  	b, diags := m.Backend(&BackendOpts{Init: true})
   630  	if diags.HasErrors() {
   631  		t.Fatal(diags.Err())
   632  	}
   633  
   634  	// Check the state
   635  	s, err := b.StateMgr(backend.DefaultStateName)
   636  	if err != nil {
   637  		t.Fatalf("unexpected error: %s", err)
   638  	}
   639  	if err := s.RefreshState(); err != nil {
   640  		t.Fatalf("unexpected error: %s", err)
   641  	}
   642  	state := s.State()
   643  	if state == nil {
   644  		t.Fatal("nil state")
   645  	}
   646  	if testStateMgrCurrentLineage(s) != "configuredUnchanged" {
   647  		t.Fatalf("bad: %#v", state)
   648  	}
   649  
   650  	// Verify the default paths don't exist
   651  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   652  		t.Fatal("file should not exist")
   653  	}
   654  
   655  	// Verify a backup doesn't exist
   656  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   657  		t.Fatal("file should not exist")
   658  	}
   659  }
   660  
   661  // Changing a configured backend
   662  func TestMetaBackend_configuredChange(t *testing.T) {
   663  	// Create a temporary working directory that is empty
   664  	td := tempDir(t)
   665  	testCopyDir(t, testFixturePath("backend-change"), td)
   666  	defer os.RemoveAll(td)
   667  	defer testChdir(t, td)()
   668  
   669  	// Ask input
   670  	defer testInteractiveInput(t, []string{"no"})()
   671  
   672  	// Setup the meta
   673  	m := testMetaBackend(t, nil)
   674  
   675  	// Get the backend
   676  	b, diags := m.Backend(&BackendOpts{Init: true})
   677  	if diags.HasErrors() {
   678  		t.Fatal(diags.Err())
   679  	}
   680  
   681  	// Check the state
   682  	s, err := b.StateMgr(backend.DefaultStateName)
   683  	if err != nil {
   684  		t.Fatalf("unexpected error: %s", err)
   685  	}
   686  	if err := s.RefreshState(); err != nil {
   687  		t.Fatalf("unexpected error: %s", err)
   688  	}
   689  	state := s.State()
   690  	if state != nil {
   691  		t.Fatal("state should be nil")
   692  	}
   693  
   694  	// Verify the default paths don't exist
   695  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   696  		t.Fatal("file should not exist")
   697  	}
   698  
   699  	// Verify a backup doesn't exist
   700  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   701  		t.Fatal("file should not exist")
   702  	}
   703  
   704  	// Write some state
   705  	state = states.NewState()
   706  	mark := markStateForMatching(state, "changing")
   707  
   708  	s.WriteState(state)
   709  	if err := s.PersistState(); err != nil {
   710  		t.Fatalf("unexpected error: %s", err)
   711  	}
   712  
   713  	// Verify the state is where we expect
   714  	{
   715  		f, err := os.Open("local-state-2.tfstate")
   716  		if err != nil {
   717  			t.Fatalf("err: %s", err)
   718  		}
   719  		actual, err := statefile.Read(f)
   720  		f.Close()
   721  		if err != nil {
   722  			t.Fatalf("err: %s", err)
   723  		}
   724  
   725  		assertStateHasMarker(t, actual.State, mark)
   726  	}
   727  
   728  	// Verify no local state
   729  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   730  		t.Fatal("file should not exist")
   731  	}
   732  
   733  	// Verify no local backup
   734  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   735  		t.Fatal("file should not exist")
   736  	}
   737  }
   738  
   739  // Reconfiguring with an already configured backend.
   740  // This should ignore the existing backend config, and configure the new
   741  // backend is if this is the first time.
   742  func TestMetaBackend_reconfigureChange(t *testing.T) {
   743  	// Create a temporary working directory that is empty
   744  	td := tempDir(t)
   745  	testCopyDir(t, testFixturePath("backend-change-single-to-single"), td)
   746  	defer os.RemoveAll(td)
   747  	defer testChdir(t, td)()
   748  
   749  	// Register the single-state backend
   750  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
   751  	defer backendInit.Set("local-single", nil)
   752  
   753  	// Setup the meta
   754  	m := testMetaBackend(t, nil)
   755  
   756  	// this should not ask for input
   757  	m.input = false
   758  
   759  	// cli flag -reconfigure
   760  	m.reconfigure = true
   761  
   762  	// Get the backend
   763  	b, diags := m.Backend(&BackendOpts{Init: true})
   764  	if diags.HasErrors() {
   765  		t.Fatal(diags.Err())
   766  	}
   767  
   768  	// Check the state
   769  	s, err := b.StateMgr(backend.DefaultStateName)
   770  	if err != nil {
   771  		t.Fatalf("unexpected error: %s", err)
   772  	}
   773  	if err := s.RefreshState(); err != nil {
   774  		t.Fatalf("unexpected error: %s", err)
   775  	}
   776  	newState := s.State()
   777  	if newState != nil || !newState.Empty() {
   778  		t.Fatal("state should be nil/empty after forced reconfiguration")
   779  	}
   780  
   781  	// verify that the old state is still there
   782  	s = statemgr.NewFilesystem("local-state.tfstate")
   783  	if err := s.RefreshState(); err != nil {
   784  		t.Fatal(err)
   785  	}
   786  	oldState := s.State()
   787  	if oldState == nil || oldState.Empty() {
   788  		t.Fatal("original state should be untouched")
   789  	}
   790  }
   791  
   792  // Changing a configured backend, copying state
   793  func TestMetaBackend_configuredChangeCopy(t *testing.T) {
   794  	// Create a temporary working directory that is empty
   795  	td := tempDir(t)
   796  	testCopyDir(t, testFixturePath("backend-change"), td)
   797  	defer os.RemoveAll(td)
   798  	defer testChdir(t, td)()
   799  
   800  	// Ask input
   801  	defer testInteractiveInput(t, []string{"yes", "yes"})()
   802  
   803  	// Setup the meta
   804  	m := testMetaBackend(t, nil)
   805  
   806  	// Get the backend
   807  	b, diags := m.Backend(&BackendOpts{Init: true})
   808  	if diags.HasErrors() {
   809  		t.Fatal(diags.Err())
   810  	}
   811  
   812  	// Check the state
   813  	s, err := b.StateMgr(backend.DefaultStateName)
   814  	if err != nil {
   815  		t.Fatalf("unexpected error: %s", err)
   816  	}
   817  	if err := s.RefreshState(); err != nil {
   818  		t.Fatalf("unexpected error: %s", err)
   819  	}
   820  	state := s.State()
   821  	if state == nil {
   822  		t.Fatal("state should not be nil")
   823  	}
   824  	if testStateMgrCurrentLineage(s) != "backend-change" {
   825  		t.Fatalf("bad: %#v", state)
   826  	}
   827  
   828  	// Verify no local state
   829  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   830  		t.Fatal("file should not exist")
   831  	}
   832  
   833  	// Verify no local backup
   834  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   835  		t.Fatal("file should not exist")
   836  	}
   837  }
   838  
   839  // Changing a configured backend that supports only single states to another
   840  // backend that only supports single states.
   841  func TestMetaBackend_configuredChangeCopy_singleState(t *testing.T) {
   842  	// Create a temporary working directory that is empty
   843  	td := tempDir(t)
   844  	testCopyDir(t, testFixturePath("backend-change-single-to-single"), td)
   845  	defer os.RemoveAll(td)
   846  	defer testChdir(t, td)()
   847  
   848  	// Register the single-state backend
   849  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
   850  	defer backendInit.Set("local-single", nil)
   851  
   852  	// Ask input
   853  	defer testInputMap(t, map[string]string{
   854  		"backend-migrate-copy-to-empty": "yes",
   855  	})()
   856  
   857  	// Setup the meta
   858  	m := testMetaBackend(t, nil)
   859  
   860  	// Get the backend
   861  	b, diags := m.Backend(&BackendOpts{Init: true})
   862  	if diags.HasErrors() {
   863  		t.Fatal(diags.Err())
   864  	}
   865  
   866  	// Check the state
   867  	s, err := b.StateMgr(backend.DefaultStateName)
   868  	if err != nil {
   869  		t.Fatalf("unexpected error: %s", err)
   870  	}
   871  	if err := s.RefreshState(); err != nil {
   872  		t.Fatalf("unexpected error: %s", err)
   873  	}
   874  	state := s.State()
   875  	if state == nil {
   876  		t.Fatal("state should not be nil")
   877  	}
   878  	if testStateMgrCurrentLineage(s) != "backend-change" {
   879  		t.Fatalf("bad: %#v", state)
   880  	}
   881  
   882  	// Verify no local state
   883  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   884  		t.Fatal("file should not exist")
   885  	}
   886  
   887  	// Verify no local backup
   888  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   889  		t.Fatal("file should not exist")
   890  	}
   891  }
   892  
   893  // Changing a configured backend that supports multi-state to a
   894  // backend that only supports single states. The multi-state only has
   895  // a default state.
   896  func TestMetaBackend_configuredChangeCopy_multiToSingleDefault(t *testing.T) {
   897  	// Create a temporary working directory that is empty
   898  	td := tempDir(t)
   899  	testCopyDir(t, testFixturePath("backend-change-multi-default-to-single"), td)
   900  	defer os.RemoveAll(td)
   901  	defer testChdir(t, td)()
   902  
   903  	// Register the single-state backend
   904  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
   905  	defer backendInit.Set("local-single", nil)
   906  
   907  	// Ask input
   908  	defer testInputMap(t, map[string]string{
   909  		"backend-migrate-copy-to-empty": "yes",
   910  	})()
   911  
   912  	// Setup the meta
   913  	m := testMetaBackend(t, nil)
   914  
   915  	// Get the backend
   916  	b, diags := m.Backend(&BackendOpts{Init: true})
   917  	if diags.HasErrors() {
   918  		t.Fatal(diags.Err())
   919  	}
   920  
   921  	// Check the state
   922  	s, err := b.StateMgr(backend.DefaultStateName)
   923  	if err != nil {
   924  		t.Fatalf("unexpected error: %s", err)
   925  	}
   926  	if err := s.RefreshState(); err != nil {
   927  		t.Fatalf("unexpected error: %s", err)
   928  	}
   929  	state := s.State()
   930  	if state == nil {
   931  		t.Fatal("state should not be nil")
   932  	}
   933  	if testStateMgrCurrentLineage(s) != "backend-change" {
   934  		t.Fatalf("bad: %#v", state)
   935  	}
   936  
   937  	// Verify no local state
   938  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   939  		t.Fatal("file should not exist")
   940  	}
   941  
   942  	// Verify no local backup
   943  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   944  		t.Fatal("file should not exist")
   945  	}
   946  }
   947  
   948  // Changing a configured backend that supports multi-state to a
   949  // backend that only supports single states.
   950  func TestMetaBackend_configuredChangeCopy_multiToSingle(t *testing.T) {
   951  	// Create a temporary working directory that is empty
   952  	td := tempDir(t)
   953  	testCopyDir(t, testFixturePath("backend-change-multi-to-single"), td)
   954  	defer os.RemoveAll(td)
   955  	defer testChdir(t, td)()
   956  
   957  	// Register the single-state backend
   958  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
   959  	defer backendInit.Set("local-single", nil)
   960  
   961  	// Ask input
   962  	defer testInputMap(t, map[string]string{
   963  		"backend-migrate-multistate-to-single": "yes",
   964  		"backend-migrate-copy-to-empty":        "yes",
   965  	})()
   966  
   967  	// Setup the meta
   968  	m := testMetaBackend(t, nil)
   969  
   970  	// Get the backend
   971  	b, diags := m.Backend(&BackendOpts{Init: true})
   972  	if diags.HasErrors() {
   973  		t.Fatal(diags.Err())
   974  	}
   975  
   976  	// Check the state
   977  	s, err := b.StateMgr(backend.DefaultStateName)
   978  	if err != nil {
   979  		t.Fatalf("unexpected error: %s", err)
   980  	}
   981  	if err := s.RefreshState(); err != nil {
   982  		t.Fatalf("unexpected error: %s", err)
   983  	}
   984  	state := s.State()
   985  	if state == nil {
   986  		t.Fatal("state should not be nil")
   987  	}
   988  	if testStateMgrCurrentLineage(s) != "backend-change" {
   989  		t.Fatalf("bad: %#v", state)
   990  	}
   991  
   992  	// Verify no local state
   993  	if _, err := os.Stat(DefaultStateFilename); err == nil {
   994  		t.Fatal("file should not exist")
   995  	}
   996  
   997  	// Verify no local backup
   998  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
   999  		t.Fatal("file should not exist")
  1000  	}
  1001  
  1002  	// Verify existing workspaces exist
  1003  	envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1004  	if _, err := os.Stat(envPath); err != nil {
  1005  		t.Fatal("env should exist")
  1006  	}
  1007  
  1008  	// Verify we are now in the default env, or we may not be able to access the new backend
  1009  	env, err := m.Workspace()
  1010  	if err != nil {
  1011  		t.Fatal(err)
  1012  	}
  1013  	if env != backend.DefaultStateName {
  1014  		t.Fatal("using non-default env with single-env backend")
  1015  	}
  1016  }
  1017  
  1018  // Changing a configured backend that supports multi-state to a
  1019  // backend that only supports single states.
  1020  func TestMetaBackend_configuredChangeCopy_multiToSingleCurrentEnv(t *testing.T) {
  1021  	// Create a temporary working directory that is empty
  1022  	td := tempDir(t)
  1023  	testCopyDir(t, testFixturePath("backend-change-multi-to-single"), td)
  1024  	defer os.RemoveAll(td)
  1025  	defer testChdir(t, td)()
  1026  
  1027  	// Register the single-state backend
  1028  	backendInit.Set("local-single", backendLocal.TestNewLocalSingle)
  1029  	defer backendInit.Set("local-single", nil)
  1030  
  1031  	// Ask input
  1032  	defer testInputMap(t, map[string]string{
  1033  		"backend-migrate-multistate-to-single": "yes",
  1034  		"backend-migrate-copy-to-empty":        "yes",
  1035  	})()
  1036  
  1037  	// Setup the meta
  1038  	m := testMetaBackend(t, nil)
  1039  
  1040  	// Change env
  1041  	if err := m.SetWorkspace("env2"); err != nil {
  1042  		t.Fatalf("unexpected error: %s", err)
  1043  	}
  1044  
  1045  	// Get the backend
  1046  	b, diags := m.Backend(&BackendOpts{Init: true})
  1047  	if diags.HasErrors() {
  1048  		t.Fatal(diags.Err())
  1049  	}
  1050  
  1051  	// Check the state
  1052  	s, err := b.StateMgr(backend.DefaultStateName)
  1053  	if err != nil {
  1054  		t.Fatalf("unexpected error: %s", err)
  1055  	}
  1056  	if err := s.RefreshState(); err != nil {
  1057  		t.Fatalf("unexpected error: %s", err)
  1058  	}
  1059  	state := s.State()
  1060  	if state == nil {
  1061  		t.Fatal("state should not be nil")
  1062  	}
  1063  	if testStateMgrCurrentLineage(s) != "backend-change-env2" {
  1064  		t.Fatalf("bad: %#v", state)
  1065  	}
  1066  
  1067  	// Verify no local state
  1068  	if _, err := os.Stat(DefaultStateFilename); err == nil {
  1069  		t.Fatal("file should not exist")
  1070  	}
  1071  
  1072  	// Verify no local backup
  1073  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1074  		t.Fatal("file should not exist")
  1075  	}
  1076  
  1077  	// Verify existing workspaces exist
  1078  	envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1079  	if _, err := os.Stat(envPath); err != nil {
  1080  		t.Fatal("env should exist")
  1081  	}
  1082  }
  1083  
  1084  // Changing a configured backend that supports multi-state to a
  1085  // backend that also supports multi-state.
  1086  func TestMetaBackend_configuredChangeCopy_multiToMulti(t *testing.T) {
  1087  	// Create a temporary working directory that is empty
  1088  	td := tempDir(t)
  1089  	testCopyDir(t, testFixturePath("backend-change-multi-to-multi"), td)
  1090  	defer os.RemoveAll(td)
  1091  	defer testChdir(t, td)()
  1092  
  1093  	// Ask input
  1094  	defer testInputMap(t, map[string]string{
  1095  		"backend-migrate-multistate-to-multistate": "yes",
  1096  	})()
  1097  
  1098  	// Setup the meta
  1099  	m := testMetaBackend(t, nil)
  1100  
  1101  	// Get the backend
  1102  	b, diags := m.Backend(&BackendOpts{Init: true})
  1103  	if diags.HasErrors() {
  1104  		t.Fatal(diags.Err())
  1105  	}
  1106  
  1107  	// Check resulting states
  1108  	workspaces, err := b.Workspaces()
  1109  	if err != nil {
  1110  		t.Fatalf("unexpected error: %s", err)
  1111  	}
  1112  
  1113  	sort.Strings(workspaces)
  1114  	expected := []string{"default", "env2"}
  1115  	if !reflect.DeepEqual(workspaces, expected) {
  1116  		t.Fatalf("bad: %#v", workspaces)
  1117  	}
  1118  
  1119  	{
  1120  		// Check the default state
  1121  		s, err := b.StateMgr(backend.DefaultStateName)
  1122  		if err != nil {
  1123  			t.Fatalf("unexpected error: %s", err)
  1124  		}
  1125  		if err := s.RefreshState(); err != nil {
  1126  			t.Fatalf("unexpected error: %s", err)
  1127  		}
  1128  		state := s.State()
  1129  		if state == nil {
  1130  			t.Fatal("state should not be nil")
  1131  		}
  1132  		if testStateMgrCurrentLineage(s) != "backend-change" {
  1133  			t.Fatalf("bad: %#v", state)
  1134  		}
  1135  	}
  1136  
  1137  	{
  1138  		// Check the other state
  1139  		s, err := b.StateMgr("env2")
  1140  		if err != nil {
  1141  			t.Fatalf("unexpected error: %s", err)
  1142  		}
  1143  		if err := s.RefreshState(); err != nil {
  1144  			t.Fatalf("unexpected error: %s", err)
  1145  		}
  1146  		state := s.State()
  1147  		if state == nil {
  1148  			t.Fatal("state should not be nil")
  1149  		}
  1150  		if testStateMgrCurrentLineage(s) != "backend-change-env2" {
  1151  			t.Fatalf("bad: %#v", state)
  1152  		}
  1153  	}
  1154  
  1155  	// Verify no local backup
  1156  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1157  		t.Fatal("file should not exist")
  1158  	}
  1159  
  1160  	{
  1161  		// Verify existing workspaces exist
  1162  		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1163  		if _, err := os.Stat(envPath); err != nil {
  1164  			t.Fatalf("%s should exist, but does not", envPath)
  1165  		}
  1166  	}
  1167  
  1168  	{
  1169  		// Verify new workspaces exist
  1170  		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
  1171  		if _, err := os.Stat(envPath); err != nil {
  1172  			t.Fatalf("%s should exist, but does not", envPath)
  1173  		}
  1174  	}
  1175  }
  1176  
  1177  // Changing a configured backend that supports multi-state to a
  1178  // backend that also supports multi-state, but doesn't allow a
  1179  // default state while the default state is non-empty.
  1180  func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithDefault(t *testing.T) {
  1181  	// Create a temporary working directory that is empty
  1182  	td := tempDir(t)
  1183  	testCopyDir(t, testFixturePath("backend-change-multi-to-no-default-with-default"), td)
  1184  	defer os.RemoveAll(td)
  1185  	defer testChdir(t, td)()
  1186  
  1187  	// Register the single-state backend
  1188  	backendInit.Set("local-no-default", backendLocal.TestNewLocalNoDefault)
  1189  	defer backendInit.Set("local-no-default", nil)
  1190  
  1191  	// Ask input
  1192  	defer testInputMap(t, map[string]string{
  1193  		"backend-migrate-multistate-to-multistate": "yes",
  1194  		"new-state-name": "env1",
  1195  	})()
  1196  
  1197  	// Setup the meta
  1198  	m := testMetaBackend(t, nil)
  1199  
  1200  	// Get the backend
  1201  	b, diags := m.Backend(&BackendOpts{Init: true})
  1202  	if diags.HasErrors() {
  1203  		t.Fatal(diags.Err())
  1204  	}
  1205  
  1206  	// Check resulting states
  1207  	workspaces, err := b.Workspaces()
  1208  	if err != nil {
  1209  		t.Fatalf("unexpected error: %s", err)
  1210  	}
  1211  
  1212  	sort.Strings(workspaces)
  1213  	expected := []string{"env1", "env2"}
  1214  	if !reflect.DeepEqual(workspaces, expected) {
  1215  		t.Fatalf("bad: %#v", workspaces)
  1216  	}
  1217  
  1218  	{
  1219  		// Check the renamed default state
  1220  		s, err := b.StateMgr("env1")
  1221  		if err != nil {
  1222  			t.Fatalf("unexpected error: %s", err)
  1223  		}
  1224  		if err := s.RefreshState(); err != nil {
  1225  			t.Fatalf("unexpected error: %s", err)
  1226  		}
  1227  		state := s.State()
  1228  		if state == nil {
  1229  			t.Fatal("state should not be nil")
  1230  		}
  1231  		if testStateMgrCurrentLineage(s) != "backend-change-env1" {
  1232  			t.Fatalf("bad: %#v", state)
  1233  		}
  1234  	}
  1235  
  1236  	{
  1237  		// Verify existing workspaces exist
  1238  		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1239  		if _, err := os.Stat(envPath); err != nil {
  1240  			t.Fatal("env should exist")
  1241  		}
  1242  	}
  1243  
  1244  	{
  1245  		// Verify new workspaces exist
  1246  		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
  1247  		if _, err := os.Stat(envPath); err != nil {
  1248  			t.Fatal("env should exist")
  1249  		}
  1250  	}
  1251  }
  1252  
  1253  // Changing a configured backend that supports multi-state to a
  1254  // backend that also supports multi-state, but doesn't allow a
  1255  // default state while the default state is empty.
  1256  func TestMetaBackend_configuredChangeCopy_multiToNoDefaultWithoutDefault(t *testing.T) {
  1257  	// Create a temporary working directory that is empty
  1258  	td := tempDir(t)
  1259  	testCopyDir(t, testFixturePath("backend-change-multi-to-no-default-without-default"), td)
  1260  	defer os.RemoveAll(td)
  1261  	defer testChdir(t, td)()
  1262  
  1263  	// Register the single-state backend
  1264  	backendInit.Set("local-no-default", backendLocal.TestNewLocalNoDefault)
  1265  	defer backendInit.Set("local-no-default", nil)
  1266  
  1267  	// Ask input
  1268  	defer testInputMap(t, map[string]string{
  1269  		"backend-migrate-multistate-to-multistate": "yes",
  1270  		"select-workspace":                         "1",
  1271  	})()
  1272  
  1273  	// Setup the meta
  1274  	m := testMetaBackend(t, nil)
  1275  
  1276  	// Get the backend
  1277  	b, diags := m.Backend(&BackendOpts{Init: true})
  1278  	if diags.HasErrors() {
  1279  		t.Fatal(diags.Err())
  1280  	}
  1281  
  1282  	// Check resulting states
  1283  	workspaces, err := b.Workspaces()
  1284  	if err != nil {
  1285  		t.Fatalf("unexpected error: %s", err)
  1286  	}
  1287  
  1288  	sort.Strings(workspaces)
  1289  	expected := []string{"env2"} // default is skipped because it is absent in the source backend
  1290  	if !reflect.DeepEqual(workspaces, expected) {
  1291  		t.Fatalf("wrong workspaces\ngot:  %#v\nwant: %#v", workspaces, expected)
  1292  	}
  1293  
  1294  	{
  1295  		// Check the named state
  1296  		s, err := b.StateMgr("env2")
  1297  		if err != nil {
  1298  			t.Fatalf("unexpected error: %s", err)
  1299  		}
  1300  		if err := s.RefreshState(); err != nil {
  1301  			t.Fatalf("unexpected error: %s", err)
  1302  		}
  1303  		state := s.State()
  1304  		if state == nil {
  1305  			t.Fatal("state should not be nil")
  1306  		}
  1307  		if testStateMgrCurrentLineage(s) != "backend-change-env2" {
  1308  			t.Fatalf("bad: %#v", state)
  1309  		}
  1310  	}
  1311  
  1312  	{
  1313  		// Verify existing workspaces exist
  1314  		envPath := filepath.Join(backendLocal.DefaultWorkspaceDir, "env2", backendLocal.DefaultStateFilename)
  1315  		if _, err := os.Stat(envPath); err != nil {
  1316  			t.Fatalf("%s should exist, but does not", envPath)
  1317  		}
  1318  	}
  1319  
  1320  	{
  1321  		// Verify new workspaces exist
  1322  		envPath := filepath.Join("envdir-new", "env2", backendLocal.DefaultStateFilename)
  1323  		if _, err := os.Stat(envPath); err != nil {
  1324  			t.Fatalf("%s should exist, but does not", envPath)
  1325  		}
  1326  	}
  1327  }
  1328  
  1329  // Unsetting a saved backend
  1330  func TestMetaBackend_configuredUnset(t *testing.T) {
  1331  	// Create a temporary working directory that is empty
  1332  	td := tempDir(t)
  1333  	testCopyDir(t, testFixturePath("backend-unset"), td)
  1334  	defer os.RemoveAll(td)
  1335  	defer testChdir(t, td)()
  1336  
  1337  	// Ask input
  1338  	defer testInteractiveInput(t, []string{"no"})()
  1339  
  1340  	// Setup the meta
  1341  	m := testMetaBackend(t, nil)
  1342  
  1343  	// Get the backend
  1344  	b, diags := m.Backend(&BackendOpts{Init: true})
  1345  	if diags.HasErrors() {
  1346  		t.Fatal(diags.Err())
  1347  	}
  1348  
  1349  	// Check the state
  1350  	s, err := b.StateMgr(backend.DefaultStateName)
  1351  	if err != nil {
  1352  		t.Fatalf("unexpected error: %s", err)
  1353  	}
  1354  	if err := s.RefreshState(); err != nil {
  1355  		t.Fatalf("unexpected error: %s", err)
  1356  	}
  1357  	state := s.State()
  1358  	if state != nil {
  1359  		t.Fatal("state should be nil")
  1360  	}
  1361  
  1362  	// Verify the default paths don't exist
  1363  	if !isEmptyState(DefaultStateFilename) {
  1364  		data, _ := ioutil.ReadFile(DefaultStateFilename)
  1365  		t.Fatal("state should not exist, but contains:\n", string(data))
  1366  	}
  1367  
  1368  	// Verify a backup doesn't exist
  1369  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1370  		data, _ := ioutil.ReadFile(DefaultStateFilename + DefaultBackupExtension)
  1371  		t.Fatal("backup should not exist, but contains:\n", string(data))
  1372  	}
  1373  
  1374  	// Write some state
  1375  	s.WriteState(testState())
  1376  	if err := s.PersistState(); err != nil {
  1377  		t.Fatalf("unexpected error: %s", err)
  1378  	}
  1379  
  1380  	// Verify it exists where we expect it to
  1381  	if isEmptyState(DefaultStateFilename) {
  1382  		t.Fatal(DefaultStateFilename, "is empty")
  1383  	}
  1384  
  1385  	// Verify no backup since it was empty to start
  1386  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1387  		data, _ := ioutil.ReadFile(DefaultStateFilename + DefaultBackupExtension)
  1388  		t.Fatal("backup state should be empty, but contains:\n", string(data))
  1389  	}
  1390  }
  1391  
  1392  // Unsetting a saved backend and copying the remote state
  1393  func TestMetaBackend_configuredUnsetCopy(t *testing.T) {
  1394  	// Create a temporary working directory that is empty
  1395  	td := tempDir(t)
  1396  	testCopyDir(t, testFixturePath("backend-unset"), td)
  1397  	defer os.RemoveAll(td)
  1398  	defer testChdir(t, td)()
  1399  
  1400  	// Ask input
  1401  	defer testInteractiveInput(t, []string{"yes", "yes"})()
  1402  
  1403  	// Setup the meta
  1404  	m := testMetaBackend(t, nil)
  1405  
  1406  	// Get the backend
  1407  	b, diags := m.Backend(&BackendOpts{Init: true})
  1408  	if diags.HasErrors() {
  1409  		t.Fatal(diags.Err())
  1410  	}
  1411  
  1412  	// Check the state
  1413  	s, err := b.StateMgr(backend.DefaultStateName)
  1414  	if err != nil {
  1415  		t.Fatalf("unexpected error: %s", err)
  1416  	}
  1417  	if err := s.RefreshState(); err != nil {
  1418  		t.Fatalf("unexpected error: %s", err)
  1419  	}
  1420  	state := s.State()
  1421  	if state == nil {
  1422  		t.Fatal("state is nil")
  1423  	}
  1424  	if got, want := testStateMgrCurrentLineage(s), "configuredUnset"; got != want {
  1425  		t.Fatalf("wrong state lineage %q; want %q", got, want)
  1426  	}
  1427  
  1428  	// Verify a backup doesn't exist
  1429  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1430  		t.Fatalf("backup state should be empty")
  1431  	}
  1432  
  1433  	// Write some state
  1434  	s.WriteState(testState())
  1435  	if err := s.PersistState(); err != nil {
  1436  		t.Fatalf("unexpected error: %s", err)
  1437  	}
  1438  
  1439  	// Verify it exists where we expect it to
  1440  	if _, err := os.Stat(DefaultStateFilename); err != nil {
  1441  		t.Fatalf("err: %s", err)
  1442  	}
  1443  
  1444  	// Verify a backup since it wasn't empty to start
  1445  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1446  		t.Fatal("backup is empty")
  1447  	}
  1448  }
  1449  
  1450  // A plan that has uses the local backend
  1451  func TestMetaBackend_planLocal(t *testing.T) {
  1452  	// Create a temporary working directory that is empty
  1453  	td := tempDir(t)
  1454  	testCopyDir(t, testFixturePath("backend-plan-local"), td)
  1455  	defer os.RemoveAll(td)
  1456  	defer testChdir(t, td)()
  1457  
  1458  	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
  1459  		"path":          cty.NullVal(cty.String),
  1460  		"workspace_dir": cty.NullVal(cty.String),
  1461  	})
  1462  	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
  1463  	if err != nil {
  1464  		t.Fatal(err)
  1465  	}
  1466  	backendConfig := plans.Backend{
  1467  		Type:      "local",
  1468  		Config:    backendConfigRaw,
  1469  		Workspace: "default",
  1470  	}
  1471  
  1472  	// Setup the meta
  1473  	m := testMetaBackend(t, nil)
  1474  
  1475  	// Get the backend
  1476  	b, diags := m.BackendForPlan(backendConfig)
  1477  	if diags.HasErrors() {
  1478  		t.Fatal(diags.Err())
  1479  	}
  1480  
  1481  	// Check the state
  1482  	s, err := b.StateMgr(backend.DefaultStateName)
  1483  	if err != nil {
  1484  		t.Fatalf("unexpected error: %s", err)
  1485  	}
  1486  	if err := s.RefreshState(); err != nil {
  1487  		t.Fatalf("unexpected error: %s", err)
  1488  	}
  1489  	state := s.State()
  1490  	if state != nil {
  1491  		t.Fatalf("state should be nil: %#v", state)
  1492  	}
  1493  
  1494  	// The default state file should not exist yet
  1495  	if !isEmptyState(DefaultStateFilename) {
  1496  		t.Fatal("expected empty state")
  1497  	}
  1498  
  1499  	// A backup file shouldn't exist yet either.
  1500  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1501  		t.Fatal("expected empty backup")
  1502  	}
  1503  
  1504  	// Verify we have no configured backend
  1505  	path := filepath.Join(m.DataDir(), DefaultStateFilename)
  1506  	if _, err := os.Stat(path); err == nil {
  1507  		t.Fatalf("should not have backend configured")
  1508  	}
  1509  
  1510  	// Write some state
  1511  	state = states.NewState()
  1512  	mark := markStateForMatching(state, "changing")
  1513  
  1514  	s.WriteState(state)
  1515  	if err := s.PersistState(); err != nil {
  1516  		t.Fatalf("unexpected error: %s", err)
  1517  	}
  1518  
  1519  	// Verify the state is where we expect
  1520  	{
  1521  		f, err := os.Open(DefaultStateFilename)
  1522  		if err != nil {
  1523  			t.Fatalf("err: %s", err)
  1524  		}
  1525  		actual, err := statefile.Read(f)
  1526  		f.Close()
  1527  		if err != nil {
  1528  			t.Fatalf("err: %s", err)
  1529  		}
  1530  
  1531  		assertStateHasMarker(t, actual.State, mark)
  1532  	}
  1533  
  1534  	// Verify no local backup
  1535  	if !isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1536  		t.Fatalf("backup state should be empty")
  1537  	}
  1538  }
  1539  
  1540  // A plan with a custom state save path
  1541  func TestMetaBackend_planLocalStatePath(t *testing.T) {
  1542  	td := tempDir(t)
  1543  	testCopyDir(t, testFixturePath("backend-plan-local"), td)
  1544  	defer os.RemoveAll(td)
  1545  	defer testChdir(t, td)()
  1546  
  1547  	original := testState()
  1548  	markStateForMatching(original, "hello")
  1549  
  1550  	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
  1551  		"path":          cty.NullVal(cty.String),
  1552  		"workspace_dir": cty.NullVal(cty.String),
  1553  	})
  1554  	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
  1555  	if err != nil {
  1556  		t.Fatal(err)
  1557  	}
  1558  	plannedBackend := plans.Backend{
  1559  		Type:      "local",
  1560  		Config:    backendConfigRaw,
  1561  		Workspace: "default",
  1562  	}
  1563  
  1564  	// Create an alternate output path
  1565  	statePath := "foo.tfstate"
  1566  
  1567  	// put an initial state there that needs to be backed up
  1568  	err = (statemgr.NewFilesystem(statePath)).WriteState(original)
  1569  	if err != nil {
  1570  		t.Fatal(err)
  1571  	}
  1572  
  1573  	// Setup the meta
  1574  	m := testMetaBackend(t, nil)
  1575  	m.stateOutPath = statePath
  1576  
  1577  	// Get the backend
  1578  	b, diags := m.BackendForPlan(plannedBackend)
  1579  	if diags.HasErrors() {
  1580  		t.Fatal(diags.Err())
  1581  	}
  1582  
  1583  	// Check the state
  1584  	s, err := b.StateMgr(backend.DefaultStateName)
  1585  	if err != nil {
  1586  		t.Fatalf("unexpected error: %s", err)
  1587  	}
  1588  	if err := s.RefreshState(); err != nil {
  1589  		t.Fatalf("unexpected error: %s", err)
  1590  	}
  1591  	state := s.State()
  1592  	if state != nil {
  1593  		t.Fatal("default workspace state is not nil, but should be because we've not put anything there")
  1594  	}
  1595  
  1596  	// Verify the default path doesn't exist
  1597  	if _, err := os.Stat(DefaultStateFilename); err == nil {
  1598  		t.Fatalf("err: %s", err)
  1599  	}
  1600  
  1601  	// Verify a backup doesn't exists
  1602  	if _, err := os.Stat(DefaultStateFilename + DefaultBackupExtension); err == nil {
  1603  		t.Fatal("file should not exist")
  1604  	}
  1605  
  1606  	// Verify we have no configured backend/legacy
  1607  	path := filepath.Join(m.DataDir(), DefaultStateFilename)
  1608  	if _, err := os.Stat(path); err == nil {
  1609  		t.Fatalf("should not have backend configured")
  1610  	}
  1611  
  1612  	// Write some state
  1613  	state = states.NewState()
  1614  	mark := markStateForMatching(state, "changing")
  1615  
  1616  	s.WriteState(state)
  1617  	if err := s.PersistState(); err != nil {
  1618  		t.Fatalf("unexpected error: %s", err)
  1619  	}
  1620  
  1621  	// Verify the state is where we expect
  1622  	{
  1623  		f, err := os.Open(statePath)
  1624  		if err != nil {
  1625  			t.Fatalf("err: %s", err)
  1626  		}
  1627  		actual, err := statefile.Read(f)
  1628  		f.Close()
  1629  		if err != nil {
  1630  			t.Fatalf("err: %s", err)
  1631  		}
  1632  
  1633  		assertStateHasMarker(t, actual.State, mark)
  1634  	}
  1635  
  1636  	// Verify we have a backup
  1637  	if isEmptyState(statePath + DefaultBackupExtension) {
  1638  		t.Fatal("backup is empty")
  1639  	}
  1640  }
  1641  
  1642  // A plan that has no backend config, matching local state
  1643  func TestMetaBackend_planLocalMatch(t *testing.T) {
  1644  	// Create a temporary working directory that is empty
  1645  	td := tempDir(t)
  1646  	testCopyDir(t, testFixturePath("backend-plan-local-match"), td)
  1647  	defer os.RemoveAll(td)
  1648  	defer testChdir(t, td)()
  1649  
  1650  	backendConfigBlock := cty.ObjectVal(map[string]cty.Value{
  1651  		"path":          cty.NullVal(cty.String),
  1652  		"workspace_dir": cty.NullVal(cty.String),
  1653  	})
  1654  	backendConfigRaw, err := plans.NewDynamicValue(backendConfigBlock, backendConfigBlock.Type())
  1655  	if err != nil {
  1656  		t.Fatal(err)
  1657  	}
  1658  	backendConfig := plans.Backend{
  1659  		Type:      "local",
  1660  		Config:    backendConfigRaw,
  1661  		Workspace: "default",
  1662  	}
  1663  
  1664  	// Setup the meta
  1665  	m := testMetaBackend(t, nil)
  1666  
  1667  	// Get the backend
  1668  	b, diags := m.BackendForPlan(backendConfig)
  1669  	if diags.HasErrors() {
  1670  		t.Fatal(diags.Err())
  1671  	}
  1672  
  1673  	// Check the state
  1674  	s, err := b.StateMgr(backend.DefaultStateName)
  1675  	if err != nil {
  1676  		t.Fatalf("unexpected error: %s", err)
  1677  	}
  1678  	if err := s.RefreshState(); err != nil {
  1679  		t.Fatalf("unexpected error: %s", err)
  1680  	}
  1681  	state := s.State()
  1682  	if state == nil {
  1683  		t.Fatal("should is nil")
  1684  	}
  1685  	if testStateMgrCurrentLineage(s) != "hello" {
  1686  		t.Fatalf("bad: %#v", state)
  1687  	}
  1688  
  1689  	// Verify the default path
  1690  	if isEmptyState(DefaultStateFilename) {
  1691  		t.Fatal("state is empty")
  1692  	}
  1693  
  1694  	// Verify we have no configured backend/legacy
  1695  	path := filepath.Join(m.DataDir(), DefaultStateFilename)
  1696  	if _, err := os.Stat(path); err == nil {
  1697  		t.Fatalf("should not have backend configured")
  1698  	}
  1699  
  1700  	// Write some state
  1701  	state = states.NewState()
  1702  	mark := markStateForMatching(state, "changing")
  1703  
  1704  	s.WriteState(state)
  1705  	if err := s.PersistState(); err != nil {
  1706  		t.Fatalf("unexpected error: %s", err)
  1707  	}
  1708  
  1709  	// Verify the state is where we expect
  1710  	{
  1711  		f, err := os.Open(DefaultStateFilename)
  1712  		if err != nil {
  1713  			t.Fatalf("err: %s", err)
  1714  		}
  1715  		actual, err := statefile.Read(f)
  1716  		f.Close()
  1717  		if err != nil {
  1718  			t.Fatalf("err: %s", err)
  1719  		}
  1720  
  1721  		assertStateHasMarker(t, actual.State, mark)
  1722  	}
  1723  
  1724  	// Verify local backup
  1725  	if isEmptyState(DefaultStateFilename + DefaultBackupExtension) {
  1726  		t.Fatal("backup is empty")
  1727  	}
  1728  }
  1729  
  1730  // init a backend using -backend-config options multiple times
  1731  func TestMetaBackend_configureWithExtra(t *testing.T) {
  1732  	// Create a temporary working directory that is empty
  1733  	td := tempDir(t)
  1734  	testCopyDir(t, testFixturePath("init-backend-empty"), td)
  1735  	defer os.RemoveAll(td)
  1736  	defer testChdir(t, td)()
  1737  
  1738  	extras := map[string]cty.Value{"path": cty.StringVal("hello")}
  1739  	m := testMetaBackend(t, nil)
  1740  	opts := &BackendOpts{
  1741  		ConfigOverride: configs.SynthBody("synth", extras),
  1742  		Init:           true,
  1743  	}
  1744  
  1745  	_, cHash, err := m.backendConfig(opts)
  1746  	if err != nil {
  1747  		t.Fatal(err)
  1748  	}
  1749  
  1750  	// init the backend
  1751  	_, diags := m.Backend(&BackendOpts{
  1752  		ConfigOverride: configs.SynthBody("synth", extras),
  1753  		Init:           true,
  1754  	})
  1755  	if diags.HasErrors() {
  1756  		t.Fatal(diags.Err())
  1757  	}
  1758  
  1759  	// Check the state
  1760  	s := testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1761  	if s.Backend.Hash != uint64(cHash) {
  1762  		t.Fatal("mismatched state and config backend hashes")
  1763  	}
  1764  
  1765  	// init the backend again with the same options
  1766  	m = testMetaBackend(t, nil)
  1767  	_, err = m.Backend(&BackendOpts{
  1768  		ConfigOverride: configs.SynthBody("synth", extras),
  1769  		Init:           true,
  1770  	})
  1771  	if err != nil {
  1772  		t.Fatalf("unexpected error: %s", err)
  1773  	}
  1774  
  1775  	// Check the state
  1776  	s = testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1777  	if s.Backend.Hash != uint64(cHash) {
  1778  		t.Fatal("mismatched state and config backend hashes")
  1779  	}
  1780  }
  1781  
  1782  // when configuring a default local state, don't delete local state
  1783  func TestMetaBackend_localDoesNotDeleteLocal(t *testing.T) {
  1784  	// Create a temporary working directory that is empty
  1785  	td := tempDir(t)
  1786  	testCopyDir(t, testFixturePath("init-backend-empty"), td)
  1787  	defer os.RemoveAll(td)
  1788  	defer testChdir(t, td)()
  1789  
  1790  	// // create our local state
  1791  	orig := states.NewState()
  1792  	orig.Module(addrs.RootModuleInstance).SetOutputValue("foo", cty.StringVal("bar"), false)
  1793  	testStateFileDefault(t, orig)
  1794  
  1795  	m := testMetaBackend(t, nil)
  1796  	m.forceInitCopy = true
  1797  	// init the backend
  1798  	_, diags := m.Backend(&BackendOpts{Init: true})
  1799  	if diags.HasErrors() {
  1800  		t.Fatal(diags.Err())
  1801  	}
  1802  
  1803  	// check that we can read the state
  1804  	s := testStateRead(t, DefaultStateFilename)
  1805  	if s.Empty() {
  1806  		t.Fatal("our state was deleted")
  1807  	}
  1808  }
  1809  
  1810  // move options from config to -backend-config
  1811  func TestMetaBackend_configToExtra(t *testing.T) {
  1812  	// Create a temporary working directory that is empty
  1813  	td := tempDir(t)
  1814  	testCopyDir(t, testFixturePath("init-backend"), td)
  1815  	defer os.RemoveAll(td)
  1816  	defer testChdir(t, td)()
  1817  
  1818  	// init the backend
  1819  	m := testMetaBackend(t, nil)
  1820  	_, err := m.Backend(&BackendOpts{
  1821  		Init: true,
  1822  	})
  1823  	if err != nil {
  1824  		t.Fatalf("unexpected error: %s", err)
  1825  	}
  1826  
  1827  	// Check the state
  1828  	s := testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1829  	backendHash := s.Backend.Hash
  1830  
  1831  	// init again but remove the path option from the config
  1832  	cfg := "terraform {\n  backend \"local\" {}\n}\n"
  1833  	if err := ioutil.WriteFile("main.tf", []byte(cfg), 0644); err != nil {
  1834  		t.Fatal(err)
  1835  	}
  1836  
  1837  	// init the backend again with the  options
  1838  	extras := map[string]cty.Value{"path": cty.StringVal("hello")}
  1839  	m = testMetaBackend(t, nil)
  1840  	m.forceInitCopy = true
  1841  	_, diags := m.Backend(&BackendOpts{
  1842  		ConfigOverride: configs.SynthBody("synth", extras),
  1843  		Init:           true,
  1844  	})
  1845  	if diags.HasErrors() {
  1846  		t.Fatal(diags.Err())
  1847  	}
  1848  
  1849  	s = testDataStateRead(t, filepath.Join(DefaultDataDir, backendLocal.DefaultStateFilename))
  1850  
  1851  	if s.Backend.Hash == backendHash {
  1852  		t.Fatal("state.Backend.Hash was not updated")
  1853  	}
  1854  }
  1855  
  1856  // no config; return inmem backend stored in state
  1857  func TestBackendFromState(t *testing.T) {
  1858  	wd := tempWorkingDirFixture(t, "backend-from-state")
  1859  	defer testChdir(t, wd.RootModuleDir())()
  1860  
  1861  	// Setup the meta
  1862  	m := testMetaBackend(t, nil)
  1863  	m.WorkingDir = wd
  1864  	// terraform caches a small "state" file that stores the backend config.
  1865  	// This test must override m.dataDir so it loads the "terraform.tfstate" file in the
  1866  	// test directory as the backend config cache. This fixture is really a
  1867  	// fixture for the data dir rather than the module dir, so we'll override
  1868  	// them to match just for this test.
  1869  	wd.OverrideDataDir(".")
  1870  
  1871  	stateBackend, diags := m.backendFromState()
  1872  	if diags.HasErrors() {
  1873  		t.Fatal(diags.Err())
  1874  	}
  1875  
  1876  	if _, ok := stateBackend.(*backendInmem.Backend); !ok {
  1877  		t.Fatal("did not get expected inmem backend")
  1878  	}
  1879  }
  1880  
  1881  func testMetaBackend(t *testing.T, args []string) *Meta {
  1882  	var m Meta
  1883  	m.Ui = new(cli.MockUi)
  1884  	view, _ := testView(t)
  1885  	m.View = view
  1886  	m.process(args)
  1887  	f := m.extendedFlagSet("test")
  1888  	if err := f.Parse(args); err != nil {
  1889  		t.Fatalf("unexpected error: %s", err)
  1890  	}
  1891  
  1892  	// metaBackend tests are verifying migrate actions
  1893  	m.migrateState = true
  1894  
  1895  	return &m
  1896  }