github.com/sixgill/terraform@v0.9.0-beta2.0.20170316214032-033f6226ae50/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  }