command: Enable reading remote-enabled state

This commit is contained in:
Armon Dadgar 2014-10-11 18:21:20 -07:00 committed by Mitchell Hashimoto
parent bf10111745
commit 53704db4ee
2 changed files with 120 additions and 15 deletions

View File

@ -42,6 +42,8 @@ type Meta struct {
oldUi cli.Ui
// useRemoteState is enabled if we are using remote state storage
// This is set when the context is loaded if we read from a remote
// enabled state file.
useRemoteState bool
// statePath is the path to the state file. If this is empty, then
@ -106,25 +108,16 @@ func (m *Meta) Context(copts contextOpts) (*terraform.Context, bool, error) {
}
}
// Load up the state
var state *terraform.State
// Load the statePath if not given
if copts.StatePath != "" {
f, err := os.Open(copts.StatePath)
if err != nil && os.IsNotExist(err) {
// If the state file doesn't exist, it is okay, since it
// is probably a new infrastructure.
err = nil
} else if err == nil {
state, err = terraform.ReadState(f)
f.Close()
}
if err != nil {
return nil, false, fmt.Errorf("Error loading state: %s", err)
}
m.statePath = copts.StatePath
}
// Store the loaded state
state, err := m.loadState()
if err != nil {
return nil, false, err
}
m.state = state
// Load the root module
@ -171,6 +164,43 @@ func (m *Meta) UIInput() terraform.UIInput {
}
}
// laodState is used to load the Terraform state. We give precedence
// to a remote state if enabled, and then check the normal state path.
func (m *Meta) loadState() (*terraform.State, error) {
// Check if we remote state is enabled
localCache, _, err := remote.ReadLocalState()
if err != nil {
return nil, fmt.Errorf("Error loading state: %s", err)
}
// Set the state if enabled
var state *terraform.State
if localCache != nil {
state = localCache
m.useRemoteState = true
}
// Load up the state
if m.statePath != "" {
f, err := os.Open(m.statePath)
if err != nil && os.IsNotExist(err) {
// If the state file doesn't exist, it is okay, since it
// is probably a new infrastructure.
err = nil
} else if m.useRemoteState && err == nil {
err = fmt.Errorf("Remote state enabled, but state file '%s' also present.", m.statePath)
f.Close()
} else if err == nil {
state, err = terraform.ReadState(f)
f.Close()
}
if err != nil {
return nil, fmt.Errorf("Error loading state: %s", err)
}
}
return state, nil
}
// PersistState is used to write out the state, handling backup of
// the existing state file and respecting path configurations.
func (m *Meta) PersistState(s *terraform.State) error {

View File

@ -255,3 +255,78 @@ func TestMeta_persistRemote(t *testing.T) {
t.Fatalf("backup should exist")
}
}
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
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")
}
}
func TestMeta_loadState_statePath(t *testing.T) {
tmp, cwd := testCwd(t)
defer testFixCwd(t, tmp, cwd)
m := new(Meta)
s := terraform.NewState()
s.Serial = 1000
if err := m.persistLocalState(s); err != nil {
t.Fatalf("err: %v", err)
}
s1, err := m.loadState()
if err != nil {
t.Fatalf("err: %v", err)
}
if s1.Serial < 1000 {
t.Fatalf("Bad: %#v", s1)
}
}
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")
}
}