github.com/nicgrayson/terraform@v0.4.3-0.20150415203910-c4de50829380/command/remote_config_test.go (about)

     1  package command
     2  
     3  import (
     4  	"bytes"
     5  	"io/ioutil"
     6  	"os"
     7  	"path/filepath"
     8  	"testing"
     9  
    10  	"github.com/hashicorp/terraform/state"
    11  	"github.com/hashicorp/terraform/terraform"
    12  	"github.com/mitchellh/cli"
    13  )
    14  
    15  // Test disabling remote management
    16  func TestRemoteConfig_disable(t *testing.T) {
    17  	tmp, cwd := testCwd(t)
    18  	defer testFixCwd(t, tmp, cwd)
    19  
    20  	// Create remote state file, this should be pulled
    21  	s := terraform.NewState()
    22  	s.Serial = 10
    23  	conf, srv := testRemoteState(t, s, 200)
    24  	defer srv.Close()
    25  
    26  	// Persist local remote state
    27  	s = terraform.NewState()
    28  	s.Serial = 5
    29  	s.Remote = conf
    30  
    31  	// Write the state
    32  	statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
    33  	state := &state.LocalState{Path: statePath}
    34  	if err := state.WriteState(s); err != nil {
    35  		t.Fatalf("err: %s", err)
    36  	}
    37  	if err := state.PersistState(); err != nil {
    38  		t.Fatalf("err: %s", err)
    39  	}
    40  
    41  	ui := new(cli.MockUi)
    42  	c := &RemoteConfigCommand{
    43  		Meta: Meta{
    44  			ContextOpts: testCtxConfig(testProvider()),
    45  			Ui:          ui,
    46  		},
    47  	}
    48  	args := []string{"-disable"}
    49  	if code := c.Run(args); code != 0 {
    50  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
    51  	}
    52  
    53  	// Local state file should be removed and the local cache should exist
    54  	testRemoteLocal(t, true)
    55  	testRemoteLocalCache(t, false)
    56  
    57  	// Check that the state file was updated
    58  	raw, _ := ioutil.ReadFile(DefaultStateFilename)
    59  	newState, err := terraform.ReadState(bytes.NewReader(raw))
    60  	if err != nil {
    61  		t.Fatalf("err: %v", err)
    62  	}
    63  
    64  	// Ensure we updated
    65  	if newState.Remote != nil {
    66  		t.Fatalf("remote configuration not removed")
    67  	}
    68  }
    69  
    70  // Test disabling remote management without pulling
    71  func TestRemoteConfig_disable_noPull(t *testing.T) {
    72  	tmp, cwd := testCwd(t)
    73  	defer testFixCwd(t, tmp, cwd)
    74  
    75  	// Create remote state file, this should be pulled
    76  	s := terraform.NewState()
    77  	s.Serial = 10
    78  	conf, srv := testRemoteState(t, s, 200)
    79  	defer srv.Close()
    80  
    81  	// Persist local remote state
    82  	s = terraform.NewState()
    83  	s.Serial = 5
    84  	s.Remote = conf
    85  
    86  	// Write the state
    87  	statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
    88  	state := &state.LocalState{Path: statePath}
    89  	if err := state.WriteState(s); err != nil {
    90  		t.Fatalf("err: %s", err)
    91  	}
    92  	if err := state.PersistState(); err != nil {
    93  		t.Fatalf("err: %s", err)
    94  	}
    95  
    96  	ui := new(cli.MockUi)
    97  	c := &RemoteConfigCommand{
    98  		Meta: Meta{
    99  			ContextOpts: testCtxConfig(testProvider()),
   100  			Ui:          ui,
   101  		},
   102  	}
   103  	args := []string{"-disable", "-pull=false"}
   104  	if code := c.Run(args); code != 0 {
   105  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   106  	}
   107  
   108  	// Local state file should be removed and the local cache should exist
   109  	testRemoteLocal(t, true)
   110  	testRemoteLocalCache(t, false)
   111  
   112  	// Check that the state file was updated
   113  	raw, _ := ioutil.ReadFile(DefaultStateFilename)
   114  	newState, err := terraform.ReadState(bytes.NewReader(raw))
   115  	if err != nil {
   116  		t.Fatalf("err: %v", err)
   117  	}
   118  
   119  	if newState.Remote != nil {
   120  		t.Fatalf("remote configuration not removed")
   121  	}
   122  }
   123  
   124  // Test disabling remote management when not enabled
   125  func TestRemoteConfig_disable_notEnabled(t *testing.T) {
   126  	tmp, cwd := testCwd(t)
   127  	defer testFixCwd(t, tmp, cwd)
   128  
   129  	ui := new(cli.MockUi)
   130  	c := &RemoteConfigCommand{
   131  		Meta: Meta{
   132  			ContextOpts: testCtxConfig(testProvider()),
   133  			Ui:          ui,
   134  		},
   135  	}
   136  
   137  	args := []string{"-disable"}
   138  	if code := c.Run(args); code != 1 {
   139  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   140  	}
   141  }
   142  
   143  // Test disabling remote management with a state file in the way
   144  func TestRemoteConfig_disable_otherState(t *testing.T) {
   145  	tmp, cwd := testCwd(t)
   146  	defer testFixCwd(t, tmp, cwd)
   147  
   148  	// Persist local remote state
   149  	s := terraform.NewState()
   150  	s.Serial = 5
   151  
   152  	// Write the state
   153  	statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
   154  	state := &state.LocalState{Path: statePath}
   155  	if err := state.WriteState(s); err != nil {
   156  		t.Fatalf("err: %s", err)
   157  	}
   158  	if err := state.PersistState(); err != nil {
   159  		t.Fatalf("err: %s", err)
   160  	}
   161  
   162  	// Also put a file at the default path
   163  	fh, err := os.Create(DefaultStateFilename)
   164  	if err != nil {
   165  		t.Fatalf("err: %v", err)
   166  	}
   167  	err = terraform.WriteState(s, fh)
   168  	fh.Close()
   169  	if err != nil {
   170  		t.Fatalf("err: %v", err)
   171  	}
   172  
   173  	ui := new(cli.MockUi)
   174  	c := &RemoteConfigCommand{
   175  		Meta: Meta{
   176  			ContextOpts: testCtxConfig(testProvider()),
   177  			Ui:          ui,
   178  		},
   179  	}
   180  
   181  	args := []string{"-disable"}
   182  	if code := c.Run(args); code != 1 {
   183  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   184  	}
   185  }
   186  
   187  // Test the case where both managed and non managed state present
   188  func TestRemoteConfig_managedAndNonManaged(t *testing.T) {
   189  	tmp, cwd := testCwd(t)
   190  	defer testFixCwd(t, tmp, cwd)
   191  
   192  	// Persist local remote state
   193  	s := terraform.NewState()
   194  	s.Serial = 5
   195  
   196  	// Write the state
   197  	statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
   198  	state := &state.LocalState{Path: statePath}
   199  	if err := state.WriteState(s); err != nil {
   200  		t.Fatalf("err: %s", err)
   201  	}
   202  	if err := state.PersistState(); err != nil {
   203  		t.Fatalf("err: %s", err)
   204  	}
   205  
   206  	// Also put a file at the default path
   207  	fh, err := os.Create(DefaultStateFilename)
   208  	if err != nil {
   209  		t.Fatalf("err: %v", err)
   210  	}
   211  	err = terraform.WriteState(s, fh)
   212  	fh.Close()
   213  	if err != nil {
   214  		t.Fatalf("err: %v", err)
   215  	}
   216  
   217  	ui := new(cli.MockUi)
   218  	c := &RemoteConfigCommand{
   219  		Meta: Meta{
   220  			ContextOpts: testCtxConfig(testProvider()),
   221  			Ui:          ui,
   222  		},
   223  	}
   224  
   225  	args := []string{}
   226  	if code := c.Run(args); code != 1 {
   227  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   228  	}
   229  }
   230  
   231  // Test initializing blank state
   232  func TestRemoteConfig_initBlank(t *testing.T) {
   233  	tmp, cwd := testCwd(t)
   234  	defer testFixCwd(t, tmp, cwd)
   235  
   236  	ui := new(cli.MockUi)
   237  	c := &RemoteConfigCommand{
   238  		Meta: Meta{
   239  			ContextOpts: testCtxConfig(testProvider()),
   240  			Ui:          ui,
   241  		},
   242  	}
   243  
   244  	args := []string{
   245  		"-backend=http",
   246  		"-backend-config", "address=http://example.com",
   247  		"-backend-config", "access_token=test",
   248  		"-pull=false",
   249  	}
   250  	if code := c.Run(args); code != 0 {
   251  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   252  	}
   253  
   254  	remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
   255  	ls := &state.LocalState{Path: remotePath}
   256  	if err := ls.RefreshState(); err != nil {
   257  		t.Fatalf("err: %s", err)
   258  	}
   259  
   260  	local := ls.State()
   261  	if local.Remote.Type != "http" {
   262  		t.Fatalf("Bad: %#v", local.Remote)
   263  	}
   264  	if local.Remote.Config["address"] != "http://example.com" {
   265  		t.Fatalf("Bad: %#v", local.Remote)
   266  	}
   267  	if local.Remote.Config["access_token"] != "test" {
   268  		t.Fatalf("Bad: %#v", local.Remote)
   269  	}
   270  }
   271  
   272  // Test initializing without remote settings
   273  func TestRemoteConfig_initBlank_missingRemote(t *testing.T) {
   274  	tmp, cwd := testCwd(t)
   275  	defer testFixCwd(t, tmp, cwd)
   276  
   277  	ui := new(cli.MockUi)
   278  	c := &RemoteConfigCommand{
   279  		Meta: Meta{
   280  			ContextOpts: testCtxConfig(testProvider()),
   281  			Ui:          ui,
   282  		},
   283  	}
   284  
   285  	args := []string{}
   286  	if code := c.Run(args); code != 1 {
   287  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   288  	}
   289  }
   290  
   291  // Test updating remote config
   292  func TestRemoteConfig_updateRemote(t *testing.T) {
   293  	tmp, cwd := testCwd(t)
   294  	defer testFixCwd(t, tmp, cwd)
   295  
   296  	// Persist local remote state
   297  	s := terraform.NewState()
   298  	s.Serial = 5
   299  	s.Remote = &terraform.RemoteState{
   300  		Type: "invalid",
   301  	}
   302  
   303  	// Write the state
   304  	statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
   305  	ls := &state.LocalState{Path: statePath}
   306  	if err := ls.WriteState(s); err != nil {
   307  		t.Fatalf("err: %s", err)
   308  	}
   309  	if err := ls.PersistState(); err != nil {
   310  		t.Fatalf("err: %s", err)
   311  	}
   312  
   313  	ui := new(cli.MockUi)
   314  	c := &RemoteConfigCommand{
   315  		Meta: Meta{
   316  			ContextOpts: testCtxConfig(testProvider()),
   317  			Ui:          ui,
   318  		},
   319  	}
   320  
   321  	args := []string{
   322  		"-backend=http",
   323  		"-backend-config", "address=http://example.com",
   324  		"-backend-config", "access_token=test",
   325  		"-pull=false",
   326  	}
   327  	if code := c.Run(args); code != 0 {
   328  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   329  	}
   330  
   331  	remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
   332  	ls = &state.LocalState{Path: remotePath}
   333  	if err := ls.RefreshState(); err != nil {
   334  		t.Fatalf("err: %s", err)
   335  	}
   336  	local := ls.State()
   337  
   338  	if local.Remote.Type != "http" {
   339  		t.Fatalf("Bad: %#v", local.Remote)
   340  	}
   341  	if local.Remote.Config["address"] != "http://example.com" {
   342  		t.Fatalf("Bad: %#v", local.Remote)
   343  	}
   344  	if local.Remote.Config["access_token"] != "test" {
   345  		t.Fatalf("Bad: %#v", local.Remote)
   346  	}
   347  }
   348  
   349  // Test enabling remote state
   350  func TestRemoteConfig_enableRemote(t *testing.T) {
   351  	tmp, cwd := testCwd(t)
   352  	defer testFixCwd(t, tmp, cwd)
   353  
   354  	// Create a non-remote enabled state
   355  	s := terraform.NewState()
   356  	s.Serial = 5
   357  
   358  	// Add the state at the default path
   359  	fh, err := os.Create(DefaultStateFilename)
   360  	if err != nil {
   361  		t.Fatalf("err: %v", err)
   362  	}
   363  	err = terraform.WriteState(s, fh)
   364  	fh.Close()
   365  	if err != nil {
   366  		t.Fatalf("err: %v", err)
   367  	}
   368  
   369  	ui := new(cli.MockUi)
   370  	c := &RemoteConfigCommand{
   371  		Meta: Meta{
   372  			ContextOpts: testCtxConfig(testProvider()),
   373  			Ui:          ui,
   374  		},
   375  	}
   376  
   377  	args := []string{
   378  		"-backend=http",
   379  		"-backend-config", "address=http://example.com",
   380  		"-backend-config", "access_token=test",
   381  		"-pull=false",
   382  	}
   383  	if code := c.Run(args); code != 0 {
   384  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   385  	}
   386  
   387  	remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
   388  	ls := &state.LocalState{Path: remotePath}
   389  	if err := ls.RefreshState(); err != nil {
   390  		t.Fatalf("err: %s", err)
   391  	}
   392  	local := ls.State()
   393  
   394  	if local.Remote.Type != "http" {
   395  		t.Fatalf("Bad: %#v", local.Remote)
   396  	}
   397  	if local.Remote.Config["address"] != "http://example.com" {
   398  		t.Fatalf("Bad: %#v", local.Remote)
   399  	}
   400  	if local.Remote.Config["access_token"] != "test" {
   401  		t.Fatalf("Bad: %#v", local.Remote)
   402  	}
   403  
   404  	// Backup file should exist, state file should not
   405  	testRemoteLocal(t, false)
   406  	testRemoteLocalBackup(t, true)
   407  }
   408  
   409  func testRemoteLocal(t *testing.T, exists bool) {
   410  	_, err := os.Stat(DefaultStateFilename)
   411  	if os.IsNotExist(err) && !exists {
   412  		return
   413  	}
   414  	if err == nil && exists {
   415  		return
   416  	}
   417  
   418  	t.Fatalf("bad: %#v", err)
   419  }
   420  
   421  func testRemoteLocalBackup(t *testing.T, exists bool) {
   422  	_, err := os.Stat(DefaultStateFilename + DefaultBackupExtention)
   423  	if os.IsNotExist(err) && !exists {
   424  		return
   425  	}
   426  	if err == nil && exists {
   427  		return
   428  	}
   429  	if err == nil && !exists {
   430  		t.Fatal("expected local backup to exist")
   431  	}
   432  
   433  	t.Fatalf("bad: %#v", err)
   434  }
   435  
   436  func testRemoteLocalCache(t *testing.T, exists bool) {
   437  	_, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename))
   438  	if os.IsNotExist(err) && !exists {
   439  		return
   440  	}
   441  	if err == nil && exists {
   442  		return
   443  	}
   444  	if err == nil && !exists {
   445  		t.Fatal("expected local cache to exist")
   446  	}
   447  
   448  	t.Fatalf("bad: %#v", err)
   449  }