github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/command/remote_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  	}
   249  	if code := c.Run(args); code != 0 {
   250  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   251  	}
   252  
   253  	remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
   254  	ls := &state.LocalState{Path: remotePath}
   255  	if err := ls.RefreshState(); err != nil {
   256  		t.Fatalf("err: %s", err)
   257  	}
   258  
   259  	local := ls.State()
   260  	if local.Remote.Type != "http" {
   261  		t.Fatalf("Bad: %#v", local.Remote)
   262  	}
   263  	if local.Remote.Config["address"] != "http://example.com" {
   264  		t.Fatalf("Bad: %#v", local.Remote)
   265  	}
   266  	if local.Remote.Config["access_token"] != "test" {
   267  		t.Fatalf("Bad: %#v", local.Remote)
   268  	}
   269  }
   270  
   271  // Test initializing without remote settings
   272  func TestRemoteConfig_initBlank_missingRemote(t *testing.T) {
   273  	tmp, cwd := testCwd(t)
   274  	defer testFixCwd(t, tmp, cwd)
   275  
   276  	ui := new(cli.MockUi)
   277  	c := &RemoteConfigCommand{
   278  		Meta: Meta{
   279  			ContextOpts: testCtxConfig(testProvider()),
   280  			Ui:          ui,
   281  		},
   282  	}
   283  
   284  	args := []string{}
   285  	if code := c.Run(args); code != 1 {
   286  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   287  	}
   288  }
   289  
   290  // Test updating remote config
   291  func TestRemoteConfig_updateRemote(t *testing.T) {
   292  	tmp, cwd := testCwd(t)
   293  	defer testFixCwd(t, tmp, cwd)
   294  
   295  	// Persist local remote state
   296  	s := terraform.NewState()
   297  	s.Serial = 5
   298  	s.Remote = &terraform.RemoteState{
   299  		Type: "invalid",
   300  	}
   301  
   302  	// Write the state
   303  	statePath := filepath.Join(tmp, DefaultDataDir, DefaultStateFilename)
   304  	ls := &state.LocalState{Path: statePath}
   305  	if err := ls.WriteState(s); err != nil {
   306  		t.Fatalf("err: %s", err)
   307  	}
   308  	if err := ls.PersistState(); err != nil {
   309  		t.Fatalf("err: %s", err)
   310  	}
   311  
   312  	ui := new(cli.MockUi)
   313  	c := &RemoteConfigCommand{
   314  		Meta: Meta{
   315  			ContextOpts: testCtxConfig(testProvider()),
   316  			Ui:          ui,
   317  		},
   318  	}
   319  
   320  	args := []string{
   321  		"-backend=http",
   322  		"-backend-config", "address=http://example.com",
   323  		"-backend-config", "access_token=test",
   324  	}
   325  	if code := c.Run(args); code != 0 {
   326  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   327  	}
   328  
   329  	remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
   330  	ls = &state.LocalState{Path: remotePath}
   331  	if err := ls.RefreshState(); err != nil {
   332  		t.Fatalf("err: %s", err)
   333  	}
   334  	local := ls.State()
   335  
   336  	if local.Remote.Type != "http" {
   337  		t.Fatalf("Bad: %#v", local.Remote)
   338  	}
   339  	if local.Remote.Config["address"] != "http://example.com" {
   340  		t.Fatalf("Bad: %#v", local.Remote)
   341  	}
   342  	if local.Remote.Config["access_token"] != "test" {
   343  		t.Fatalf("Bad: %#v", local.Remote)
   344  	}
   345  }
   346  
   347  // Test enabling remote state
   348  func TestRemoteConfig_enableRemote(t *testing.T) {
   349  	tmp, cwd := testCwd(t)
   350  	defer testFixCwd(t, tmp, cwd)
   351  
   352  	// Create a non-remote enabled state
   353  	s := terraform.NewState()
   354  	s.Serial = 5
   355  
   356  	// Add the state at the default path
   357  	fh, err := os.Create(DefaultStateFilename)
   358  	if err != nil {
   359  		t.Fatalf("err: %v", err)
   360  	}
   361  	err = terraform.WriteState(s, fh)
   362  	fh.Close()
   363  	if err != nil {
   364  		t.Fatalf("err: %v", err)
   365  	}
   366  
   367  	ui := new(cli.MockUi)
   368  	c := &RemoteConfigCommand{
   369  		Meta: Meta{
   370  			ContextOpts: testCtxConfig(testProvider()),
   371  			Ui:          ui,
   372  		},
   373  	}
   374  
   375  	args := []string{
   376  		"-backend=http",
   377  		"-backend-config", "address=http://example.com",
   378  		"-backend-config", "access_token=test",
   379  	}
   380  	if code := c.Run(args); code != 0 {
   381  		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
   382  	}
   383  
   384  	remotePath := filepath.Join(DefaultDataDir, DefaultStateFilename)
   385  	ls := &state.LocalState{Path: remotePath}
   386  	if err := ls.RefreshState(); err != nil {
   387  		t.Fatalf("err: %s", err)
   388  	}
   389  	local := ls.State()
   390  
   391  	if local.Remote.Type != "http" {
   392  		t.Fatalf("Bad: %#v", local.Remote)
   393  	}
   394  	if local.Remote.Config["address"] != "http://example.com" {
   395  		t.Fatalf("Bad: %#v", local.Remote)
   396  	}
   397  	if local.Remote.Config["access_token"] != "test" {
   398  		t.Fatalf("Bad: %#v", local.Remote)
   399  	}
   400  
   401  	// Backup file should exist, state file should not
   402  	testRemoteLocal(t, false)
   403  	testRemoteLocalBackup(t, true)
   404  }
   405  
   406  func testRemoteLocal(t *testing.T, exists bool) {
   407  	_, err := os.Stat(DefaultStateFilename)
   408  	if os.IsNotExist(err) && !exists {
   409  		return
   410  	}
   411  	if err == nil && exists {
   412  		return
   413  	}
   414  
   415  	t.Fatalf("bad: %#v", err)
   416  }
   417  
   418  func testRemoteLocalBackup(t *testing.T, exists bool) {
   419  	_, err := os.Stat(DefaultStateFilename + DefaultBackupExtention)
   420  	if os.IsNotExist(err) && !exists {
   421  		return
   422  	}
   423  	if err == nil && exists {
   424  		return
   425  	}
   426  	if err == nil && !exists {
   427  		t.Fatal("expected local backup to exist")
   428  	}
   429  
   430  	t.Fatalf("bad: %#v", err)
   431  }
   432  
   433  func testRemoteLocalCache(t *testing.T, exists bool) {
   434  	_, err := os.Stat(filepath.Join(DefaultDataDir, DefaultStateFilename))
   435  	if os.IsNotExist(err) && !exists {
   436  		return
   437  	}
   438  	if err == nil && exists {
   439  		return
   440  	}
   441  	if err == nil && !exists {
   442  		t.Fatal("expected local cache to exist")
   443  	}
   444  
   445  	t.Fatalf("bad: %#v", err)
   446  }