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