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