github.com/ggriffiths/terraform@v0.9.0-beta1.0.20170222213024-79c4935604cb/state/backup.go (about) 1 package state 2 3 import "github.com/hashicorp/terraform/terraform" 4 5 // BackupState wraps a State that backs up the state on the first time that 6 // a WriteState or PersistState is called. 7 // 8 // If Path exists, it will be overwritten. 9 type BackupState struct { 10 Real State 11 Path string 12 13 done bool 14 } 15 16 func (s *BackupState) State() *terraform.State { 17 return s.Real.State() 18 } 19 20 func (s *BackupState) RefreshState() error { 21 return s.Real.RefreshState() 22 } 23 24 func (s *BackupState) WriteState(state *terraform.State) error { 25 if !s.done { 26 if err := s.backup(); err != nil { 27 return err 28 } 29 } 30 31 return s.Real.WriteState(state) 32 } 33 34 func (s *BackupState) PersistState() error { 35 if !s.done { 36 if err := s.backup(); err != nil { 37 return err 38 } 39 } 40 41 return s.Real.PersistState() 42 } 43 44 // all states get wrapped by BackupState, so it has to be a Locker 45 func (s *BackupState) Lock(info *LockInfo) (string, error) { 46 if s, ok := s.Real.(Locker); ok { 47 return s.Lock(info) 48 } 49 return "", nil 50 } 51 52 func (s *BackupState) Unlock(id string) error { 53 if s, ok := s.Real.(Locker); ok { 54 return s.Unlock(id) 55 } 56 return nil 57 } 58 59 func (s *BackupState) backup() error { 60 state := s.Real.State() 61 if state == nil { 62 if err := s.Real.RefreshState(); err != nil { 63 return err 64 } 65 66 state = s.Real.State() 67 } 68 69 // LocalState.WriteState ensures that a file always exists for locking 70 // purposes, but we don't need a backup or lock if the state is empty, so 71 // skip this with a nil state. 72 if state != nil { 73 ls := &LocalState{Path: s.Path} 74 if err := ls.WriteState(state); err != nil { 75 return err 76 } 77 } 78 79 s.done = true 80 return nil 81 }