示例#1
0
func TestMeta_loadState_remote(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	err := remote.EnsureDirectory()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	s := terraform.NewState()
	s.Serial = 1000
	conf, srv := testRemoteState(t, s, 200)
	s.Remote = conf
	defer srv.Close()

	s.Serial = 500
	if err := remote.PersistState(s); err != nil {
		t.Fatalf("err: %v", err)
	}

	m := new(Meta)
	s1, err := m.loadState()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if s1.Serial < 1000 {
		t.Fatalf("Bad: %#v", s1)
	}

	if !m.useRemoteState {
		t.Fatalf("should enable remote")
	}
}
示例#2
0
// initBlank state is used to initialize a blank state that is
// remote enabled
func (c *RemoteCommand) initBlankState() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Make the hidden directory
	if err := remote.EnsureDirectory(); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Make a blank state, attach the remote configuration
	blank := terraform.NewState()
	blank.Remote = &c.remoteConf

	// Persist the state
	if err := remote.PersistState(blank); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to initialize state file: %v", err))
		return 1
	}

	// Success!
	c.Ui.Output("Initialized blank state with remote state enabled!")
	return 0
}
示例#3
0
// Test updating remote config
func TestRemote_updateRemote(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	// Persist local remote state
	s := terraform.NewState()
	s.Serial = 5
	s.Remote = &terraform.RemoteState{
		Type: "invalid",
	}
	if err := remote.EnsureDirectory(); err != nil {
		t.Fatalf("err: %v", err)
	}
	if err := remote.PersistState(s); err != nil {
		t.Fatalf("err: %v", err)
	}

	ui := new(cli.MockUi)
	c := &RemoteCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}

	args := []string{
		"-backend=http",
		"-address",
		"http://example.com",
		"-access-token=test",
	}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	local, _, err := remote.ReadLocalState()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	if local.Remote.Type != "http" {
		t.Fatalf("Bad: %#v", local.Remote)
	}
	if local.Remote.Config["address"] != "http://example.com" {
		t.Fatalf("Bad: %#v", local.Remote)
	}
	if local.Remote.Config["access_token"] != "test" {
		t.Fatalf("Bad: %#v", local.Remote)
	}
}
示例#4
0
// persistRemoteState is used to handle persisting a state file
// when remote state management is enabled
func (m *Meta) persistRemoteState(s *terraform.State) error {
	log.Printf("[INFO] Persisting state to local cache")
	if err := remote.PersistState(s); err != nil {
		return err
	}
	log.Printf("[INFO] Uploading state to remote store")
	change, err := remote.PushState(s.Remote, false)
	if err != nil {
		return err
	}
	if !change.SuccessfulPush() {
		return fmt.Errorf("Failed to upload state: %s", change)
	}
	return nil
}
示例#5
0
// Test the case where both managed and non managed state present
func TestRemote_managedAndNonManaged(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	// Persist local remote state
	s := terraform.NewState()
	s.Serial = 5
	if err := remote.EnsureDirectory(); err != nil {
		t.Fatalf("err: %v", err)
	}
	if err := remote.PersistState(s); err != nil {
		t.Fatalf("err: %v", err)
	}

	// Also put a file at the default path
	fh, err := os.Create(DefaultStateFilename)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	err = terraform.WriteState(s, fh)
	fh.Close()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	ui := new(cli.MockUi)
	c := &RemoteCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}

	args := []string{}
	if code := c.Run(args); code != 1 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}
}
示例#6
0
func TestMeta_loadState_conflict(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	err := remote.EnsureDirectory()
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	m := new(Meta)

	s := terraform.NewState()
	if err := remote.PersistState(s); err != nil {
		t.Fatalf("err: %v", err)
	}
	if err := m.persistLocalState(s); err != nil {
		t.Fatalf("err: %v", err)
	}

	_, err = m.loadState()
	if err == nil {
		t.Fatalf("should error with conflict")
	}
}
示例#7
0
// updateRemoteConfig is used to update the configuration of the
// remote state store
func (c *RemoteCommand) updateRemoteConfig() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Read in the local state
	local, _, err := remote.ReadLocalState()
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read local state: %v", err))
		return 1
	}

	// Update the configuration
	local.Remote = &c.remoteConf
	if err := remote.PersistState(local); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Success!
	c.Ui.Output("Remote configuration updated")
	return 0
}
示例#8
0
// Test disabling remote management without pulling
func TestRemote_disable_noPull(t *testing.T) {
	tmp, cwd := testCwd(t)
	defer testFixCwd(t, tmp, cwd)

	// Create remote state file, this should be pulled
	s := terraform.NewState()
	s.Serial = 10
	conf, srv := testRemoteState(t, s, 200)
	defer srv.Close()

	// Persist local remote state
	s = terraform.NewState()
	s.Serial = 5
	s.Remote = conf
	if err := remote.EnsureDirectory(); err != nil {
		t.Fatalf("err: %v", err)
	}
	if err := remote.PersistState(s); err != nil {
		t.Fatalf("err: %v", err)
	}

	ui := new(cli.MockUi)
	c := &RemoteCommand{
		Meta: Meta{
			ContextOpts: testCtxConfig(testProvider()),
			Ui:          ui,
		},
	}
	args := []string{"-disable", "-pull=false"}
	if code := c.Run(args); code != 0 {
		t.Fatalf("bad: \n%s", ui.ErrorWriter.String())
	}

	// Local state file should be removed
	haveLocal, err := remote.HaveLocalState()
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if haveLocal {
		t.Fatalf("should be disabled")
	}

	// New state file should be installed
	exists, err := remote.ExistsFile(DefaultStateFilename)
	if err != nil {
		t.Fatalf("err: %v", err)
	}
	if !exists {
		t.Fatalf("failed to make state file")
	}

	// Check that the state file was updated
	raw, _ := ioutil.ReadFile(DefaultStateFilename)
	newState, err := terraform.ReadState(bytes.NewReader(raw))
	if err != nil {
		t.Fatalf("err: %v", err)
	}

	// Ensure we DIDNT updated
	// TODO: Should be 5, but WriteState currently increments
	// this which is incorrect.
	if newState.Serial != 7 {
		t.Fatalf("state file updated: %#v", newState)
	}
	if newState.Remote != nil {
		t.Fatalf("remote configuration not removed")
	}
}
示例#9
0
// enableRemoteState is used to enable remote state management
// and to move a state file into place
func (c *RemoteCommand) enableRemoteState() int {
	// Validate the remote configuration
	if err := c.validateRemoteConfig(); err != nil {
		return 1
	}

	// Make the hidden directory
	if err := remote.EnsureDirectory(); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Read the provided state file
	raw, err := ioutil.ReadFile(c.conf.statePath)
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to read '%s': %v", c.conf.statePath, err))
		return 1
	}
	state, err := terraform.ReadState(bytes.NewReader(raw))
	if err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to decode '%s': %v", c.conf.statePath, err))
		return 1
	}

	// Backup the state file before we modify it
	backupPath := c.conf.backupPath
	if backupPath != "-" {
		// Provide default backup path if none provided
		if backupPath == "" {
			backupPath = c.conf.statePath + DefaultBackupExtention
		}

		log.Printf("[INFO] Writing backup state to: %s", backupPath)
		f, err := os.Create(backupPath)
		if err == nil {
			err = terraform.WriteState(state, f)
			f.Close()
		}
		if err != nil {
			c.Ui.Error(fmt.Sprintf("Error writing backup state file: %s", err))
			return 1
		}
	}

	// Update the local configuration, move into place
	state.Remote = &c.remoteConf
	if err := remote.PersistState(state); err != nil {
		c.Ui.Error(fmt.Sprintf("%s", err))
		return 1
	}

	// Remove the state file
	log.Printf("[INFO] Removing state file: %s", c.conf.statePath)
	if err := os.Remove(c.conf.statePath); err != nil {
		c.Ui.Error(fmt.Sprintf("Failed to remove state file '%s': %v",
			c.conf.statePath, err))
		return 1
	}

	// Success!
	c.Ui.Output("Remote state management enabled")
	return 0
}