diff --git a/state/backup.go b/state/backup.go new file mode 100644 index 000000000..276979905 --- /dev/null +++ b/state/backup.go @@ -0,0 +1,63 @@ +package state + +import ( + "github.com/hashicorp/terraform/terraform" +) + +// BackupState wraps a State that backs up the state on the first time that +// a WriteState or PersistState is called. +// +// If Path exists, it will be overwritten. +type BackupState struct { + Real State + Path string + + done bool +} + +func (s *BackupState) State() *terraform.State { + return s.Real.State() +} + +func (s *BackupState) RefreshState() error { + return s.Real.RefreshState() +} + +func (s *BackupState) WriteState(state *terraform.State) error { + if !s.done { + if err := s.backup(); err != nil { + return err + } + } + + return s.Real.WriteState(state) +} + +func (s *BackupState) PersistState() error { + if !s.done { + if err := s.backup(); err != nil { + return err + } + } + + return s.Real.PersistState() +} + +func (s *BackupState) backup() error { + state := s.Real.State() + if state == nil { + if err := s.Real.RefreshState(); err != nil { + return err + } + + state = s.Real.State() + } + + ls := &LocalState{Path: s.Path} + if err := ls.WriteState(state); err != nil { + return err + } + + s.done = true + return nil +} diff --git a/state/backup_test.go b/state/backup_test.go new file mode 100644 index 000000000..f86b6b299 --- /dev/null +++ b/state/backup_test.go @@ -0,0 +1,29 @@ +package state + +import ( + "io/ioutil" + "os" + "testing" +) + +func TestBackupState(t *testing.T) { + f, err := ioutil.TempFile("", "tf") + if err != nil { + t.Fatalf("err: %s", err) + } + f.Close() + defer os.Remove(f.Name()) + + ls := testLocalState(t) + defer os.Remove(ls.Path) + TestState(t, &BackupState{ + Real: ls, + Path: f.Name(), + }) + + if fi, err := os.Stat(f.Name()); err != nil { + t.Fatalf("err: %s", err) + } else if fi.Size() == 0 { + t.Fatalf("bad: %d", fi.Size()) + } +}